6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Wed Sep 25, 2024 4:29 am

All times are UTC




Post new topic Reply to topic  [ 30 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Interrupt Handling
PostPosted: Sat Dec 15, 2012 6:32 pm 
Offline

Joined: Sat Dec 13, 2003 3:37 pm
Posts: 1004
I just want to clarify a point, make sure I understand this.

The bit in the status register controlling IRQ is a DISABLE bit, so SEI "disables", CLI "enables" (that's not intuitive from a mnemonic perspective).

Assuming CLI has been executed, and the bit is cleared, and IRQ fires.

The CPU then:

o Pushes the PC
o Pushes the status register
o then disables the bit in the status register

So, initially while the interrupt routine is running, interrupts are disabled. (This makes intuitive sense.)

After the routine is done, it calls RTI.

RTI restores the status register, and then jumps back to the PC it stored.

So, I assume that since the interrupt bit was cleared when the interrupt fired (being an IRQ), that the restoration of the status register is what implicitly re-enables the interrupts for future interrupts.

Just wanted to clarify that point on how this all works, as that last parts seems a bit glossed over.


Top
 Profile  
Reply with quote  
 Post subject: Re: Interrupt Handling
PostPosted: Sat Dec 15, 2012 7:25 pm 
Offline

Joined: Fri Aug 30, 2002 2:05 pm
Posts: 347
Location: UK
Quote:
So, I assume that since the interrupt bit was cleared when the interrupt fired (being an IRQ), that the restoration of the status register is what implicitly re-enables the interrupts for future interrupts.
Yes, that's exactly it.

Lee.


Top
 Profile  
Reply with quote  
 Post subject: Re: Interrupt Handling
PostPosted: Sat Dec 15, 2012 7:34 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8517
Location: Southern California
Right. You can also re-enable interrupts in the ISR (interrupt-service routine) after you've cleared the original cause of the interrupt. This is not common, but you could do it if for example you wanted a higher-priority interrupt that can be serviced quickly to be able to interrupt the servicing of a lower-priority one. In my system to service interrupts in high-level Forth with no overhead, I actually do a PLA, ORA#4, PHA in order to exit the machine-language ISR without re-enabling interrupts.

Note that the processor comes out of RST with the IRQ-disable bit I set.

See my article on interrupts at if you haven't already.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
 Post subject: Re: Interrupt Handling
PostPosted: Sat Dec 15, 2012 8:11 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8395
Location: Midwestern USA
whartung wrote:
The bit in the status register controlling IRQ is a DISABLE bit, so SEI "disables", CLI "enables" (that's not intuitive from a mnemonic perspective).

It is intuitive if you think in terms of what the instruction is doing: CLI = CLear the I bit, SEI = SEt the I bit.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
 Post subject: Re: Interrupt Handling
PostPosted: Sat Dec 15, 2012 9:10 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8517
Location: Southern California
Yes, it is important to think of it as SEt the Interrupt-disable bit and CLear the Interrupt-disable bit. Someone else recently seemed to be making the mistake of thinking of it as "clear interrupts" which is a separate thing, something you have to do by accessing the I/O ICs that produced them, not something you can do in the processor itself.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
 Post subject: Re: Interrupt Handling
PostPosted: Sat Dec 15, 2012 11:49 pm 
Offline

Joined: Sat Dec 13, 2003 3:37 pm
Posts: 1004
Ok, thanks. That's what I thought.

Now, the IRQ pin is set low (?) and that triggers the interrupt. The Interrupt Service Routine (ISR) is supposed to tell the device to reset the interrupt pin before it leaves the routine. If there is more than one device requesting an interrupt, then the pin remains set (low?), and the CPU, once it see CLI fire off, calls the ISR again.

So, what happens after RTI?

RTI pops the Status Register, and this (normally) re-enables interrupts. But the processor has not yet popped off the PC.

Does the processor, effectively, pop the status register, reset the interrupt bit, load the PC from the stack, and THEN notice that IRQ is still set and start the whole thing again? I assume that it's noticing the interrupt as its getting ready to fetch the instruction at the restored PC, so in effect the ISR is called twice with the same values on the stack, the processor never gets a chance to advance.


Top
 Profile  
Reply with quote  
 Post subject: Re: Interrupt Handling
PostPosted: Sun Dec 16, 2012 12:12 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8395
Location: Midwestern USA
whartung wrote:
Ok, thanks. That's what I thought.

Now, the IRQ pin is set low (?) and that triggers the interrupt. The Interrupt Service Routine (ISR) is supposed to tell the device to reset the interrupt pin before it leaves the routine. If there is more than one device requesting an interrupt, then the pin remains set (low?), and the CPU, once it see CLI fire off, calls the ISR again.

So, what happens after RTI?

RTI pops the Status Register, and this (normally) re-enables interrupts. But the processor has not yet popped off the PC.

Does the processor, effectively, pop the status register, reset the interrupt bit, load the PC from the stack, and THEN notice that IRQ is still set and start the whole thing again? I assume that it's noticing the interrupt as its getting ready to fetch the instruction at the restored PC, so in effect the ISR is called twice with the same values on the stack, the processor never gets a chance to advance.

The MPU always finishes the current instruction before responding to IRQ or NMI. As RTI is an instruction, it must finish before the MPU will notice that IRQ is low. So, yes, it is possible that the MPU may effectively repeat what it just did as soon as RTI has pulled PC, although presumably a different source would be interrupting.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
 Post subject: Re: Interrupt Handling
PostPosted: Sun Dec 16, 2012 10:17 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10938
Location: England
You can see the effect in this simulation:
http://www.visual6502.org/JSSim/expert. ... ogmore=irq
The program is
CLI
INX
INY
and the interrupt handler is just
RTI
You notice that the INX completes, the INY is fetched but subsumed by the interrupt response sequence, and on RTI the INY is again fetched but again subsumed. The Y reg is never incremented.

Cheers
Ed


Top
 Profile  
Reply with quote  
 Post subject: Re: Interrupt Handling
PostPosted: Sun Dec 16, 2012 3:26 pm 
Offline
User avatar

Joined: Mon Apr 23, 2012 12:28 am
Posts: 760
Location: Huntsville, AL
The described behavior of that simple code sequence when interrupted just doesn't seem right.

It seems to me that something is not right with the behavior described as it corresponds to the INY instruction. First, I am assuming that the IRQ is asserted before CLI. Second, at the completion of CLI, the interrupt is not immediately taken and the INX instruction is fetched and executed: X += 1. Third, at the completion of the INX, the I mask is not set, IRQ is asserted, so the processor takes the interrupt. (I expect that the I bit is cleared in P by CLI not on the falling edge of Phi2 or rising edge of Phi1, but on the rising edge of Phi2. This puts a half cycle delay in the clearing of the I bit, which allows INX to execute.)

The interrupt service routine (ISR) is simply an RTI instruction. To enter the ISR after the INX, the processor does not increment the PC, so it first pushes {PCH, PCL}, which point to INX, and then it pushes P. The processor then updates (sets) the I bit in P and performs a jmp ($FFFE) to get to the RTI instruction of the ISR. The RTI immediately reverses the process, by pulling P from the stack, pulling PCL for the INX instruction and incrementing it, pulling PCH for the INX instruction and incrementing it if a carry occurred (PCL += 1), and then performing a fetch of the INY instruction. INY should execute, and at its completion, before the PC is incremented for the next instruction fetch, the IRQ will be taken because I is not set.

I suppose it's possible that the processor's sequencer evaluates IRQ/NMI before the increment of (pulled) PC is performed. However, given the small number of temporary registers in the 6502, I would expect the increment of PCL to occur while the pull of PCH from the stack is being performed by the RTI/RTS instruction sequence. Then when PCH is ready, it can be incremented if there was a carry during the previous cycle. It also means that the RTI and RTS instructions can share the same return address adjustment sequence.

If the operation of the IRQ is as described, then it means that the processor has just been stopped unless the external logic deasserts IRQ at some point. Is this really the case with the 6502/65C02?

_________________
Michael A.


Top
 Profile  
Reply with quote  
 Post subject: Re: Interrupt Handling
PostPosted: Sun Dec 16, 2012 3:44 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10938
Location: England
First, I should say that I was slightly surprised because I'd had the idea that a single instruction would be executed after the RTI(*). But, second, I should say that I have a very high degree of confidence in the simulation. If it doesn't match our expectations, we need to think harder!

MichaelM wrote:
The described behavior of that simple code sequence when interrupted just doesn't seem right.

It seems to me that something is not right with the behavior described as it corresponds to the INY instruction. First, I am assuming that the IRQ is asserted before CLI.
I added a couple of NOPs to check that nothing changes - indeed, nothing changes. You can see I've tabulated 'irq'.
Quote:
Second, at the completion of CLI, the interrupt is not immediately taken and the INX instruction is fetched and executed: X += 1. Third, at the completion of the INX, the I mask is not set, IRQ is asserted, so the processor takes the interrupt.
In a sense, I think this is not quite right. I think the processor was already committed to take the interrupt.
Quote:
(I expect that the I bit is cleared in P by CLI not on the falling edge of Phi2 or rising edge of Phi1, but on the rising edge of Phi2. This puts a half cycle delay in the clearing of the I bit, which allows INX to execute.)
Most things change at the fall of phi2/rise of phi1. Indeed, you can see the I bit changes at the beginning of cycle2.
Quote:
The interrupt service routine (ISR) is simply an RTI instruction. To enter the ISR after the INX, the processor does not increment the PC, so it first pushes {PCH, PCL}, which point to INX
In fact, no - this is probably the crux - PC has already been incremented to 3
Quote:
..., and then it pushes P. The processor then updates (sets) the I bit in P and performs a jmp ($FFFE) to get to the RTI instruction of the ISR.
Conceptually it executes a jmp indirect, but (as discussed elsewhere) it's actually executing something rather like a BRK
Quote:
The RTI immediately reverses the process, by pulling P from the stack, pulling PCL for the INX instruction and incrementing it,
Actually no - PC was already pre-incremented
Quote:
... pulling PCH for the INX instruction and incrementing it if a carry occurred (PCL += 1), and then performing a fetch of the INY instruction.
Indeed, we see INY is (re)fetched
Quote:
INY should execute,
But no, it is subsumed by the IR being forced to zero, which causes the BRK-like subsequent behaviour
Quote:
... and at its completion...


Hope this helps somewhat!

Cheers
Ed

(*)In fact, I think what I was misremembering might be the way that the instruction after a CLI will always be executed - precisely because of the pipelining, which means the next instruction is underway as the I bit is cleared.


Last edited by BigEd on Sun Dec 16, 2012 4:43 pm, edited 2 times in total.

Top
 Profile  
Reply with quote  
 Post subject: Re: Interrupt Handling
PostPosted: Sun Dec 16, 2012 3:59 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10938
Location: England
In case anyone is unable to run that simulation, and for ease of reference, here's the tabulation it produces:
Code:
cycle
      ab    db  rw Fetch  pc     a   x   y   s         p irq
0   0001    58  1   CLI 0001    aa  00  00  fd  nv‑BdIZc  1
0   0001    58  1   CLI 0001    aa  00  00  fd  nv‑BdIZc  1
1   0002    e8  1       0002    aa  00  00  fd  nv‑BdIZc  1
1   0002    e8  1       0002    aa  00  00  fd  nv‑BdIZc  0
2   0002    e8  1   INX 0002    aa  00  00  fd  nv‑BdiZc  0
2   0002    e8  1   INX 0002    aa  00  00  fd  nv‑BdiZc  0
3   0003    c8  1       0003    aa  00  00  fd  nv‑BdiZc  0
3   0003    c8  1       0003    aa  00  00  fd  nv‑bdiZc  0
4   0003    c8  1   INY 0003    aa  00  00  fd  nv‑bdiZc  0
4   0003    c8  1   INY 0003    aa  00  00  fd  nv‑bdiZc  0
5   0003    c8  1       0003    aa  01  00  fd  nv‑bdizc  0
5   0003    c8  1       0003    aa  01  00  fd  nv‑bdizc  0
6   01fd    c8  0       0003    aa  01  00  fd  nv‑bdizc  0
6   01fd    00  0       0003    aa  01  00  fd  nv‑bdizc  0
7   01fc    c8  0       0003    aa  01  00  fd  nv‑bdizc  0
7   01fc    03  0       0003    aa  01  00  fd  nv‑bdizc  0
8   01fb    c8  0       0003    aa  01  00  fd  nv‑bdizc  0
8   01fb    20  0       0003    aa  01  00  fd  nv‑bdizc  0
9   fffe    00  1       0003    aa  01  00  fa  nv‑bdizc  0
9   fffe    00  1       0003    aa  01  00  fa  nv‑Bdizc  0
10  ffff    00  1       0003    aa  01  00  fa  nv‑BdIzc  0
10  ffff    00  1       0003    aa  01  00  fa  nv‑BdIzc  0
11  0000    40  1   RTI 0000    aa  01  00  fa  nv‑BdIzc  0
11  0000    40  1   RTI 0000    aa  01  00  fa  nv‑BdIzc  0
12  0001    58  1       0001    aa  01  00  fa  nv‑BdIzc  0
12  0001    58  1       0001    aa  01  00  fa  nv‑BdIzc  0
13  01fa    00  1       0002    aa  01  00  fa  nv‑BdIzc  0
13  01fa    00  1       0002    aa  01  00  fa  nv‑BdIzc  0
14  01fb    20  1       0002    aa  01  00  fa  nv‑BdIzc  0
14  01fb    20  1       0002    aa  01  00  fa  nv‑BdIzc  0
15  01fc    03  1       0002    aa  01  00  fa  nv‑Bdizc  0
15  01fc    03  1       0002    aa  01  00  fa  nv‑Bdizc  0
16  01fd    00  1       0002    aa  01  00  fd  nv‑Bdizc  0
16  01fd    00  1       0002    aa  01  00  fd  nv‑bdizc  0
17  0003    c8  1   INY 0003    aa  01  00  fd  nv‑bdizc  0
17  0003    c8  1   INY 0003    aa  01  00  fd  nv‑bdizc  0
18  0003    c8  1       0003    aa  01  00  fd  nv‑bdizc  0
18  0003    c8  1       0003    aa  01  00  fd  nv‑bdizc  0
19  01fd    c8  0       0003    aa  01  00  fd  nv‑bdizc  0
19  01fd    00  0       0003    aa  01  00  fd  nv‑bdizc  0
20  01fc    c8  0       0003    aa  01  00  fd  nv‑bdizc  0
20  01fc    03  0       0003    aa  01  00  fd  nv‑bdizc  0
21  01fb    c8  0       0003    aa  01  00  fd  nv‑bdizc  0
21  01fb    20  0       0003    aa  01  00  fd  nv‑bdizc  0
22  fffe    00  1       0003    aa  01  00  fa  nv‑bdizc  0
22  fffe    00  1       0003    aa  01  00  fa  nv‑Bdizc  0
23  ffff    00  1       0003    aa  01  00  fa  nv‑BdIzc  0
23  ffff    00  1       0003    aa  01  00  fa  nv‑BdIzc  0
24  0000    40  1   RTI 0000    aa  01  00  fa  nv‑BdIzc  0
24  0000    40  1   RTI 0000    aa  01  00  fa  nv‑BdIzc  0


Top
 Profile  
Reply with quote  
 Post subject: Re: Interrupt Handling
PostPosted: Sun Dec 16, 2012 4:36 pm 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Since I had never looked at this scenario, I was curious how my core would do. It looks very similar. The RTI takes 6 cycles. In the 3rd cycle, the flags are read from the stack, and in the 4th cycle, the I bit is cleared. As soon as that happens, the IR bits are zeroed, simulating a BRK instruction. It still tries to read the next instruction from memory, and the following byte, but then it hits the DECODE state, and the BRK takes preference.
Quote:
If the operation of the IRQ is as described, then it means that the processor has just been stopped unless the external logic deasserts IRQ at some point. Is this really the case with the 6502/65C02?

Normally, the IRQ handler takes care of removing the source of the interrupt, so this is not a problem.


Top
 Profile  
Reply with quote  
 Post subject: Re: Interrupt Handling
PostPosted: Sun Dec 16, 2012 6:04 pm 
Offline
User avatar

Joined: Mon Apr 23, 2012 12:28 am
Posts: 760
Location: Huntsville, AL
I can see from your state vector listing the points you are making. It's still less than satisfying to know that if IRQ is continuously asserted, then the second instruction past the CLI does not appear to execute unless the source of the IRQ is forced to deassert for at least one instruction cycle time in the ISR.

I have generally been unsatisfied with this type of behavior for level activated interrupts, so in the M65C02 core, I have forced all program flow control instructions (plus the SEI/CLI instructions) to be non-interruptable. That is, the target instruction of any branch, jump, or return is always executed. A self-referencing loop, i.e. jmp $, will not be interruptable, but the WAI instruction is a suitable replacement for such a construct.

With that simple change, the issue WRT INY becomes moot.

_________________
Michael A.


Top
 Profile  
Reply with quote  
 Post subject: Re: Interrupt Handling
PostPosted: Sun Dec 16, 2012 6:07 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10938
Location: England
Interesting design choice!


Top
 Profile  
Reply with quote  
 Post subject: Re: Interrupt Handling
PostPosted: Sun Dec 16, 2012 6:08 pm 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
I think that the 6502's behavior is the preferred one. From a systems standpoint, you want the interrupt handling to be as quick as possible.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 30 posts ]  Go to page 1, 2  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 19 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron