RST 0 --> 0x0000
RST 1 --> 0x0008
...
RST 7 --> 0x0038
dkguyen said:Interrupts, as far as I have seen and know all work in the same basic way:
When a particular interrupt occurs the processor jumps to a reserved area in memory (which contains a table of addresses). The specific "entry (location in memory) that the processor jumps to depends on the interrupt that was triggered. The address contained at this location in memory points to the subroutine that is to be run for the interrupt, and the processor jumps to that address and runs the subroutine. THe interrupt subroutine should store the system's previous state when it starts running and restore the state after it finishes.
So it's basically writing your interrupt subroutine, and writing the address that this subroutine is stored at into the specific location in the "interrupt vector table" (that reserved location of memory which is basically a table of stored addresses) that is associated with your interrupt.
An interrupt controller is just the circuitry inside the uC that handles all the interrupt stuff, isn't it?
Papabravo said:To get a handle on address decoding you should look at an actual decoder chip like a 74LS138 or 74LS139 or their CMOS equivalents. On the 74LS138 you will notice that there are three inputs labeled A, B, and C. These inputs would be connected to address lines A13, A14, and A15 respectively. You will also notice three enable inputs. One is active High and two are active low these might be tied to Vcc anf GND respectively.
What will the outputs do? Well Y0 = 0 whenever A15 = A14 = A13 = 0 and so on. this circuit will break up the 64K memory space into eight 8 K blocks. There is no right answer to how people divy up the 64K space it depends on lots of things.
Interrupts are accomplished by forcing a special instruction onto the data bus during the M1 cycle (instruction fetch) These instructions are call RESTART instructions and there are eight of them. they are like one byte subroutine calls to fixed locations
Code:
RST 0 --> 0x0000 RST 1 --> 0x0008 ... RST 7 --> 0x0038
RST 0 is also equivalent to a power up reset.
One of the Z80 predecessors (8085) had three additional RST instructions called RST 5.5, RST6.5, and RST 7.5 associated with dedicated lines on the processor. I dont remeber where they vectored to. The Z80 may also have had additional interrupt mechanisms which I've forgotten.
Check out pages 24-25 of the following
https://www.electro-tech-online.com/custompdfs/2008/01/z80cpu_um-1.pdf
Pommie said:I found a good page on Z80 here.
The Z80 has 3 interrupts modes. The simplest is mode 1 where all interrupts go to rst38 (jump to location 0x38). The other modes require hardware to place values on the bus during an acknowledge cycle and so get complex. There is also a Non Maskable Interrupt (NMI) which cannot be turned off and jumps to location 0x0008.
As for address decoding, the Z80 handles I/O seperate to memory and so you have the full address space to play with. In your example, the PIO will be mapped at 0,4,8 .. ,7c but it doesn't matter, the space may as well be used.
Mike.
A short explanation of the z80 stack:Marks256 said:That brings me to another question. What is a "Stack". I do know that it is like a "stack" of memory, but a better explanation would be nice...
EX AF,AF' ; Exchange A and PSW with primed set
EXX ; Exchange BC, DE, HL with primed set
kchriste said:A short explanation of the z80 stack:
https://www.smspower.org/dev/docs/wiki/Z80/Stack
Also Wiki has a simple explanation on this page entitled "Basic architecture of a stack":
**broken link removed** _stack
Papabravo said:If you want to decode a single address then you need a circuit with 16 inputs
Papabravo said:and they must save and restore anything that they will alter.
Yes, that is the jist of it. You would use the interrupt routine to empty the keyboard buffer and place the "key presses" in global memory so that the buffer is empty to receive the next key press. Then your main routine can take its own sweet time to deal with the key presses in global memory when it is ready to do so.Would i load it into memory at a specific address, and have the program poll that address for changes?
void kb_EnQueue(unsigned char c)
{
if(kb_n > 255) return ; /* Queue is full */
kb_Queue[kb_put++] = c ;
++kb_n ;
}
unsigned char kb_DeQueue(void)
{
--kb_n ;
return kb_Queue[kb_get++] ;
}
...
if(kb_n > 0) /* If there is data in the Queue */
{
key = 0 ;
disable_interrupts() ;
key = kb_DeQueue() ;
enable_interrupts() ;
}
...
Papabravo said:Well interrupts by definition cannot return values. The more interesting thing to do is to place the "keys" in a FIFO queue. That is a fancy name for a data structure where the first key put into the queue (by the interrupt service routine) is the first key taken out of the queue (by the background program). This way the interrupt is serviced in a timely fashion, and the background program can take it's sweet time before it gets around to processing the data.
So what you need for this queue is
The initial condition is all variables initialized to zero.
- A chunk of memory called kb_queue[256]
- A put index called kb_put
- A get index kb_get
- A count of the number of keys in the queue called kb_n
Now you need two functions called kb_EnQueue that will put 1 byte of data into the queue, and a function kb_DeQueue that will take one byte of data out of the queue.
In C-like pseudo code here goes
Function kb_EnQueue is called inside the interrupt service routine. Note that it modifies variables kb_put and kb_n. Notice also that when either of these variables is equal to 255 and they are incremented then they roll over to 0.Code:void kb_EnQueue(unsigned char c) { if(kb_n > 255) return ; /* Queue is full */ kb_Queue[kb_put++] = c ; ++kb_n ; } unsigned char kb_DeQueue(void) { --kb_n ; return kb_Queue[kb_get++] ; }
In the background program there would be a sequence like the following
Interrupts must be disabled for a short time during which you will modify the common variable kb_n.Code:... if(kb_n > 0) /* If there is data in the Queue */ { key = 0 ; disable_interrupts() ; key = kb_DeQueue() ; enable_interrupts() ; } ...
The interrupt routine service routine never touches kb_get, and the background program never touches kb_put. They both touch kb_n and that is why we need to protect that critical section.
I should point out that there are ways to use smaller queues and there are ways to avoid using kb_n. At least this way you can focus on what is happening instead of tying yourself in knots tying to super code the last scraps of time and space out of the routine.
One last thing to note is that these routines work for all sorts of character oriented peripherals like serial ports, SPI ports, parallel ports, CAN peripherals and so forth. They are a handy thing to keep in your toolbox.
Haven't you started using a PIC?Marks256 said:Aaaah. I see! So if i had a device that wanted to request an interrupt, i would wait for the CPU to attempt to fetch the next instruction, but inject the interrupt command instead? Then the CPU will do that subroutine, and then continue back where it was?
tkbits said:Haven't you started using a PIC?
You can study interrupts with it.
The device can "request" an interrupt at any time. It might wait for an "acknowledge"; at which time it can finish up, and prepare for the next request. Some devices will automatically "release" the interrupt on an acknowledge; others will need to be told you are "finished", before they release the interrupt.
I would suggest a clock or timer as a first interrupt project. Not a keyboard buffer.
I would suggest a clock or timer as a first interrupt project. Not a keyboard buffer.
Marks256 said:Let's not start the "PICs are better" thing. Ok? I will start with PICs when i feel that i am good and ready.
lets start at the very beginning
a very good place to start
when you read yo begin with A-B-C
when you sing you begin with DO-RE-MI
child: do re mi
DO RE MI...
the first three notes just happen to be : DO-RE-MI
CHild: do re mi...
DO-RE-MI-FA-SOL-LA-TI...
oh let me see if i can make it easier
DOE-- A DEER A FEMALE DEER
RAY-- A DROP OF GOLDEN SUN
ME-- A NAME I CALL MYSELF
FAR-- A LONG LONG WAY TO RUN
SEW-- A NEEDLE PULLING THREAD
LA-- A NOTE TO FOLLOW SEW
TEA-- A DRINK WITH JAM AND BREAD
THAT WILL BRING US BACK TO DO... oh oh oh
DOE-- A DEER A FEMALE DEER
RAY-- A DROP OF GOLDEN SUN
ME-- A NAME I CALL MYSELF
FAR-- A LONG LONG WAY TO RUN
SEW-- A NEEDLE PULLING THREAD
LA-- A NOTE TO FOLLOW SEW
TEA-- A DRINK WITH JAM AND BREAD
THAT WILL BRING US BACK TO...
(CHILD)
DOE-- A DEER A FEMALE DEER
RAY-- A DROP OF GOLDEN SUN
ME-- A NAME I CALL MYSELF
FAR-- A LONG LONG WAY TO RUN
(EVERYONE)
SEW-- A NEEDLE PULLING THREAD
LA-- A NOTE TO FOLLOW SEW
TEA-- A DRINK WITH JAM AND BREAD
THAT WILL BRING US BACK TO DO
DO-RE-MI-FA-SOL-LA-TI-DO....SO DO!
now children, do re mi fa sol and so on..
are only the tools to build a song...
once you have these notes in your head you can
sing a millions different tunes my mixing them up!!!
like this:
SOL-DO-LA-FA-MI-DO-RE
(CHILD)SOL-DO-LA-FA-MI-DO-RE
SOL-DO-LA-TI-DO-RE-DO
(CHILD)SOL-DO-LA-TI-DO-RE-DO
(julie)NOW put them all together!!
(all)
SOL-DO-LA-FA-MI-DO-RE
SOL-DO-LA-TI-DO-RE-DO
chemelec said:However, I am just leaving to go on a Holiday to Chile, so DON'T email me till after March 3, 2008.
Chile is mainstream. Now Tristan da Cunha, Peter I, or Pitcairn Island those would be outliers.Nigel Goodwin said:Chile?, that sounds a bit random?
Nigel Goodwin said:Chile?, that sounds a bit random?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?