6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Nov 23, 2024 12:36 am

All times are UTC




Post new topic Reply to topic  [ 16 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Sun Nov 14, 2010 7:01 pm 
Offline

Joined: Wed Oct 27, 2010 1:28 pm
Posts: 25
Location: Valladolid (Spain)
What happens if the /IRQ input is still low when the RTI instruction is executed? It seems that not a single instruction of the interrupted program is executed. Instead the IRQ handler is called again just after the RTI instruction and the PC keeps stuck on the same position. This behavior ruined my plans for a step by step debugger program, so, I need other ideas...

The most obvious is to place a BRK op-code just after the current instruction (assuming the code under debug is placed in RAM). The original op-code will be restored by the BRK routine before continuation. This would implement the "execute until next" function of the debugger, but not the desired "single step" one. In order to do this the original op-code must be decoded, the Bcc, JMP, JSR, RTS and RTI op-codes have to be identified, the next execution address computed and, then, the BRK op-code placed on that address. In short, we need half a 6502 emulator running on a 6502 system. I wonder if there is another simpler way of doing this.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sun Nov 14, 2010 7:50 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
It looks like you're right - I checked on visual6502, and IRQ doesn't run even one opcode. This surprises me, because I'm sure I've heard of situations where code proceeds very slowly and the cause is found to be a stuck interrupt pin. Maybe different 6502 versions act differently?

I think your sketch of placing a BRK, and having to be careful about the instructions which cause a change of PC, is absolutely normal. It's not as bad as half a 6502 emulator, but it is worse than you'd hope. In some systems there might be a 6522-type timer where you can fire an IRQ very soon after the last one.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sun Nov 14, 2010 9:23 pm 
Offline

Joined: Sat Jan 04, 2003 10:03 pm
Posts: 1706
jesari, the 6502 outputs a signal called SYNC, which indicates when the next opcode fetch is in progress. If you assert IRQ right after SYNC is negated, the CPU will finish the execution of the current instruction before branching to the interrupt handler.

Put another way, the CPU samples IRQ only when SYNC is asserted.

(Or, in the case of the 65816, only when VPA/VDA are both asserted.)


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sun Nov 14, 2010 9:25 pm 
Offline
User avatar

Joined: Fri Dec 12, 2003 7:22 am
Posts: 259
Location: Heerlen, NL
BigEd wrote:
In some systems there might be a 6522-type timer where you can fire an IRQ very soon after the last one.
I have worked with a single stepper for the C64 using this method so it should work.

_________________
Code:
    ___
   / __|__
  / /  |_/     Groetjes, Ruud
  \ \__|_\
   \___|       URL: www.baltissen.org



Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sun Nov 14, 2010 10:40 pm 
Offline

Joined: Wed Oct 27, 2010 1:28 pm
Posts: 25
Location: Valladolid (Spain)
The timer solution looks easier to code and, BTW, I got a VIA with unused timers. This approach has the disadvantage of being system-dependent. On the other hand I can remember a nice debugger for the Apple II (but I can't remember its name) and that computer had no interrupts at all. It must have resorted to the BRK approach...

Thanks for the tips.

Just to be accurate... I tested the RTI instruction on an real NMOS 6502 made by Rockwell during 1981.

Ruud wrote:
BigEd wrote:
In some systems there might be a 6522-type timer where you can fire an IRQ very soon after the last one.
I have worked with a single stepper for the C64 using this method so it should work.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sun Nov 14, 2010 11:27 pm 
Offline

Joined: Sat Jan 04, 2003 10:03 pm
Posts: 1706
jesari wrote:
It must have resorted to the BRK approach...


Most debuggers for the 6502 rely on the BRK approach, precisely because it ought to work on most 6502 platforms. An example debugger appears in the book "Programming the 65816, including the 6502, 65C02, and 65802" by David Eyes and Ron Lichty. I'm not sure if this book is online anymore; I think WDC has since replaced this book with another.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Nov 15, 2010 1:48 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8544
Location: Southern California
See my tips #36 and 37 at viewtopic.php?t=342&start=36 .

I also used to use a debugger routine that I would call with a JSR where I wanted to check and see what was in various registers, check I/O status, particular memory locations, etc.. Lacking a logic analyzer, I have also single-cycled the clock so I could probe the buses at each cycle, something that could not be done on the NMOS 6502 since it could not be stopped without losing its registers' data like the 65c02 can. But obviously these approaches are worthless in a real-time situation where the hardware that the computer is supposed to control won't work at all if the computer isn't going at least close to the normal speed. I have had a few projects like that.

I believe the AIM-65 computer used the Sync output to single-step.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Nov 15, 2010 3:56 am 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
kc5tja wrote:
If you assert IRQ right after SYNC is negated, the CPU will finish the execution of the current instruction before branching to the interrupt handler.

Garth Wilson wrote:
I believe the AIM-65 computer used the Sync output to single-step.

Yes, for purposes of single-stepping, the KIM-1 (and, I assume, the AIM-65) basically drive the NMI (not IRQ) input with an inverted copy of the SYNC output. Page 26 of the KIM-1 User Manual shows the pertinent section of schematic, including the "SST" (Single Step) slide switch.

Edit: A key point is that the Debugger and the Code Being Debugged reside in separate memory chips, and the latter's chip-select, combined with SYNC, is what triggers the NMI. Please refer to my subsequent post.

Unlike IRQ, NMI is an edge-sensitive input, triggered by a negative-going (logic high to logic low) transition. Oddly enough that means the KIM-1 arrangement actually triggers NMI at the beginning -- not the end -- of the cycle during which SYNC is asserted. But NMI is not immediately recognized. It needs to remain low for at least 2 clock cycles, so recognition occurs 1 cycle after SYNC is negated. And that's evidently still in time to preempt the following opcode fetch.

Note that gate U26 conveniently ensures that single-stepping will NOT occur in the ROM that fields the NMI interrupt. And, a mechanical switch may perhaps not be your preference, so another gate (driven off a peripheral IO line) may be required. But no timer is needed. With or without a mechanical switch, probably this is what was used in the "nice debugger for the Apple II" that you mentioned.

Note that U26 is an open-collector type gate. You can use a regular NAND gate here, but not if NMI is also driven by another device.

Big Ed wrote:
I'm sure I've heard of situations where code proceeds very slowly and the cause is found to be a stuck interrupt pin. Maybe different 6502 versions act differently?

I suspect there may be a misunderstanding or miscommunication here. To me it seems more plausible that such behavior would be caused by an accidental short between SYNC and NMI -- which are on adjacent pins. Or perhaps some other signal (or noise) somehow appeared on NMI or IRQ -- or on RDY. But it could be a chip version issue as you suggest. Interesting, if so...

cheers,

Jeff


Last edited by Dr Jefyll on Wed Nov 17, 2010 8:05 am, edited 2 times in total.

Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Nov 15, 2010 8:22 pm 
Offline

Joined: Wed Oct 27, 2010 1:28 pm
Posts: 25
Location: Valladolid (Spain)
The timed IRQ seems to work. I tested it with the following code where I reduced the delay until just before the PC went stuck (looks like I'm missing 1 cycle somewhere...).

Code:
   ; new IRQ just after returning and fetching 1 op-code   
   lda   #$A0
   sta   IER      ; enable TIMER2 IRQ
   lda   #20      ; 21.5 cycles until irq
   sta   T2CL      ; write latch
   lda   #0
   sta   T2CH      ; Write counter, clear IRQ
   
   ; 22 cycles until return
   pla         ; restore registers
   tay
   pla
   tax
   pla
defISR:   rti

Here is a log. Forget about ***BRK*** and (-2). I'm using the old BRK handler for IRQ (lot of things need to be changed). The code being traced was:

E0DF CLV
E0E0 LDA #8
E0E2 AND $201
E0E5 BNE $E0ED

Code:
   *** BRK ***
PC=$E0DF(-2)  P=.VrB..ZC  A=$0A  X=$00  Y=$00  S=$FF

qmdg>q

   *** BRK ***
PC=$E0E0(-2)  P=..r...ZC  A=$0A  X=$00  Y=$00  S=$FF

qmdg>q

   *** BRK ***
PC=$E0E2(-2)  P=..r....C  A=$08  X=$00  Y=$00  S=$FF


Thanks to this trick I think I can go ahead with the debugger.
Thanks a lot for all the ideas.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Nov 15, 2010 9:10 pm 
Offline

Joined: Tue Jul 05, 2005 7:08 pm
Posts: 1043
Location: near Heidelberg, Germany
kc5tja wrote:
jesari, the 6502 outputs a signal called SYNC, which indicates when the next opcode fetch is in progress. If you assert IRQ right after SYNC is negated, the CPU will finish the execution of the current instruction before branching to the interrupt handler.

Put another way, the CPU samples IRQ only when SYNC is asserted.


Except when it's not. See the other thread about the interrupt being delayed by one opcode when a branch is taken.

André


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Nov 15, 2010 9:11 pm 
Offline
User avatar

Joined: Fri Dec 12, 2003 7:22 am
Posts: 259
Location: Heerlen, NL
kc5tja wrote:
Most debuggers for the 6502 rely on the BRK approach, precisely because it ought to work on most 6502 platforms.
The BRK approach has one disadvantage: it cannot be used in ROM area. That's why I first went for the timer method and later for my hardware debugger.

_________________
Code:
    ___
   / __|__
  / /  |_/     Groetjes, Ruud
  \ \__|_\
   \___|       URL: www.baltissen.org



Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Nov 15, 2010 9:12 pm 
Offline

Joined: Tue Jul 05, 2005 7:08 pm
Posts: 1043
Location: near Heidelberg, Germany
Ruud wrote:
BigEd wrote:
In some systems there might be a 6522-type timer where you can fire an IRQ very soon after the last one.
I have worked with a single stepper for the C64 using this method so it should work.


IIRC those single-steppers in the C64 used the NMI - at least the one I did in my monitor (although admittedly I did not take into account the bad rasterlines so it sometimes ended up in the return-from-interrupt code, but you could trace through that)

André


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Nov 15, 2010 9:14 pm 
Offline

Joined: Tue Jul 05, 2005 7:08 pm
Posts: 1043
Location: near Heidelberg, Germany
kc5tja wrote:
jesari wrote:
It must have resorted to the BRK approach...


Most debuggers for the 6502 rely on the BRK approach, precisely because it ought to work on most 6502 platforms.


But the BRK method does not work on ROM code.

André


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Nov 15, 2010 9:19 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
jesari wrote:
The timed IRQ seems to work....
Thanks to this trick I think I can go ahead with the debugger.
Quick work!

Not wishing to redirect your efforts or change the approach, but for interest's sake I had a look at the appleII monitor ROM, around address FA43.

The approach taken there in single-stepping is to copy the opcode and operands into RAM and execute there. Again, special handling for instructions which change flow (branches are adjusted to branch to a branch-taken handler). The instructions are operating on register contents which are restored before and saved after execution. To do all the above the code makes use of the nearby disassembler to compute instruction length. It's worth a read (although I'm not suggesting it's any better than what you have)(*)

Cheers
Ed

(*) Just realised: the test for 'is this a branch' does some masking and then compares with #04. If equal, it's a branch. So the branch offset is adjusted to #04. Which is already in the accumulator! See FA74.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Nov 15, 2010 9:57 pm 
Offline

Joined: Sat Jan 04, 2003 10:03 pm
Posts: 1706
fachat wrote:
But the BRK method does not work on ROM code.


I would have thought this was obvious. Also, no mention of ROM was made until Dr. Jefyl's post.


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

All times are UTC


Who is online

Users browsing this forum: No registered users and 20 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: