65c02 - Program Counter/stack issue
65c02 - Program Counter/stack issue
Hi, I've been designing and building a 1MHz WDC65c02 based system for the last month and I'm running into a seemingly irresolvable issue. If anyone has any idea, guess or insight about what might be causing this, it would be greatly appreciated.
I'm using a spare CIA (MOS 6526) to generate interrupts on some timers, but whenever there is 2 interrupt sources triggering in a short time frame (most likely the 2nd triggering while it is still in the first ISR), it returns to some garbage location when it is done with the ISRs.
From what I understand from the 65c02, it does set the interrupt flag automatically while in the ISR. So it would end the first one, pop back PC, pop back processor status, clear int flag, then service the other interrupt right away, push status, push PC, load $FFFE/$FFFF... And my guess is the problem would come from this sequence, although I cannot see why this would go bad if the sequence for a single interrupt go fine. Anyway, odds are, my Program Counter gets corrupted there somehow.
On a related topic, I had problem earlier with the stack, let say I was doing:
phx (65c02...)
jsr whereever
plx
I got a similar problem, most likely stack corruption there, until I inserted some NOPs:
phx
nop
jsr whereever
nop
plx
Of course I cannot use that hack with the ISR, but it seems to hint to a stack pointer problem happening when it get changed "too fast". I still don't understand why one interrupt sequence would ever work if that was the case.
So, if my understanding seems wrong, or you have any suggestion on what to investigate... I'm armed with a logic analyzer, strong will and way too much free time.
Thanks!
I'm using a spare CIA (MOS 6526) to generate interrupts on some timers, but whenever there is 2 interrupt sources triggering in a short time frame (most likely the 2nd triggering while it is still in the first ISR), it returns to some garbage location when it is done with the ISRs.
From what I understand from the 65c02, it does set the interrupt flag automatically while in the ISR. So it would end the first one, pop back PC, pop back processor status, clear int flag, then service the other interrupt right away, push status, push PC, load $FFFE/$FFFF... And my guess is the problem would come from this sequence, although I cannot see why this would go bad if the sequence for a single interrupt go fine. Anyway, odds are, my Program Counter gets corrupted there somehow.
On a related topic, I had problem earlier with the stack, let say I was doing:
phx (65c02...)
jsr whereever
plx
I got a similar problem, most likely stack corruption there, until I inserted some NOPs:
phx
nop
jsr whereever
nop
plx
Of course I cannot use that hack with the ISR, but it seems to hint to a stack pointer problem happening when it get changed "too fast". I still don't understand why one interrupt sequence would ever work if that was the case.
So, if my understanding seems wrong, or you have any suggestion on what to investigate... I'm armed with a logic analyzer, strong will and way too much free time.
Thanks!
Re: 65c02 - Program Counter/stack issue
welcome xbg! You should surely check out hoglet's protocol analyser
viewtopic.php?f=4&t=4963
Does your system behave any more helpfully if you clock it a bit slower?
Is your power supply clean and well decoupled at each board and near each chip?
Does the phx/jsr/plx code work if the subroutine is trivial - just an RTS? If interrupts are disabled?
I wonder if your ISR is mishandling the stack.
viewtopic.php?f=4&t=4963
Does your system behave any more helpfully if you clock it a bit slower?
Is your power supply clean and well decoupled at each board and near each chip?
Does the phx/jsr/plx code work if the subroutine is trivial - just an RTS? If interrupts are disabled?
I wonder if your ISR is mishandling the stack.
- GARTHWILSON
- Forum Moderator
- Posts: 8773
- Joined: 30 Aug 2002
- Location: Southern California
- Contact:
Re: 65c02 - Program Counter/stack issue
Welcome. You don't show any code above, so I have to ask if you're doing a CLI before the RTI. That will get you into trouble under the conditions you describe. In most cases, you don't want any CLI instruction in the ISR at all. The RTI will normally take care of that. There's more about it in the 6502 interrupts primer.
Note that the 6502 does not have an interrupt flag in the status register. It is an interrupt-disable flag.
Note that the 6502 does not have an interrupt flag in the status register. It is an interrupt-disable flag.
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?
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
- BigDumbDinosaur
- Posts: 9425
- Joined: 28 May 2009
- Location: Midwestern USA (JB Pritzker’s dystopia)
- Contact:
Re: 65c02 - Program Counter/stack issue
You may be seeing some timing issues that are corrupting the section of RAM that is the stack. Posting a schematic would be helpful, as well as code examples. Also, look into Ed's suggestion about the protocol analyzer if you get stuck.
x86? We ain't got no x86. We don't NEED no stinking x86!
Re: 65c02 - Program Counter/stack issue
So thats my whole ISR
Otherwise, in my main loop im just polling these flags for now and do the appropriate function. (music routine on timer A, test UART transmit on timer B, and get the byte in UART RX bufffer when the uart flag is set.
All of which works perfectly fine if I just remove both timer B and poll uart instead of using int.
Thanks for the replies. I'll check sigrok and try to slow down my clock.
Right now my prototype is just a pile of garbage on a breadboard.
Code: Select all
*=$E000
!to "isrE000.bin", plain
!cpu 65c02
cia_icr = $DC0D
uart_isr = $D302
temp = $1F
tb_flag = $20
uart_flag = $21
sid_flag = $22
int_routine
pha
phx
phy
check_timer_a
lda cia_icr ; ack int/get int data
tax
and #$01
beq check_timer_b
inc sid_flag
check_timer_b
txa
and #$02
beq check_uart
inc tb_flag
check_uart
lda uart_isr ; get int status register & ack
cmp #$06 ; Line status register int (RX byte ready)
bne end_int
inc uart_flag
end_int
ply
plx
pla
rti
All of which works perfectly fine if I just remove both timer B and poll uart instead of using int.
Thanks for the replies. I'll check sigrok and try to slow down my clock.
Right now my prototype is just a pile of garbage on a breadboard.
Last edited by xbg on Sun Dec 03, 2017 12:40 pm, edited 2 times in total.
Re: 65c02 - Program Counter/stack issue
There's a missing space here - I don't suppose your assembler would do something weird with that?
xbg wrote:
Code: Select all
check_uartlda uart_isr ; get int status register & ack
Re: 65c02 - Program Counter/stack issue
BigEd wrote:
There's a missing space here - I don't suppose your assembler would do something weird with that?
xbg wrote:
Code: Select all
check_uartlda uart_isr ; get int status register & ack
Re: 65c02 - Program Counter/stack issue
Looks good to me. Are you seeing at least one increment, so you know you've installed the ISR OK?
Re: 65c02 - Program Counter/stack issue
Yep, the music play right, at 50hz (timer A value).
Characters received from UART are displayed on the LCD just fine... for like 10-20 seconds.
Then as soon as 2 interrupts are triggering closeby (100 microsecs or so), it all crashes. And from sniffing the chip enable signals, it seems to just return to some random location (unitialized) in the ram.
I guess if it is a problem you guys have never seen before it might just be some ground bounce/noise issue, due to it being on a huuge piece of breadboard. I do have decoupling on all chips VCC, but its not magical... I don't think gate delay can be an issue at 1MHz, and my address decoder isnt that bad, except for the UART chip which was meant for an Intel bus.
I really need to put this on a real pcb asap.
Characters received from UART are displayed on the LCD just fine... for like 10-20 seconds.
Then as soon as 2 interrupts are triggering closeby (100 microsecs or so), it all crashes. And from sniffing the chip enable signals, it seems to just return to some random location (unitialized) in the ram.
I guess if it is a problem you guys have never seen before it might just be some ground bounce/noise issue, due to it being on a huuge piece of breadboard. I do have decoupling on all chips VCC, but its not magical... I don't think gate delay can be an issue at 1MHz, and my address decoder isnt that bad, except for the UART chip which was meant for an Intel bus.
I really need to put this on a real pcb asap.
Re: 65c02 - Program Counter/stack issue
An instruction trace would be very interesting to see. Dave's (hoglet's) protocol decoder, in the latest incarnation, only needs to see the databus, RnW, and clock, IIRC. And it can then tell you the exact instruction sequence and machine state.
Re: 65c02 - Program Counter/stack issue
xbg wrote:
On a related topic, I had problem earlier with the stack, let say I was doing:
phx (65c02...)
jsr whereever
plx
I got a similar problem, most likely stack corruption there, until I inserted some NOPs:
phx
nop
jsr whereever
nop
plx
phx (65c02...)
jsr whereever
plx
I got a similar problem, most likely stack corruption there, until I inserted some NOPs:
phx
nop
jsr whereever
nop
plx
Dunno if this issue (above) is part of the same problem you're chasing. But it's worth observing (if you haven't already) that inserting a NOP means the data pushed to the stack is different. At a minimum the LS bit of the return address will flip to the opposite value (if it's just a single NOP that's added).
So, if adding the NOP eliminates a symptom then it's plausible one of the data lines to the RAM is somehow not right -- stuck high, stuck low, floating or else shorted or misconnected with respect to some other signal. (It's also possible an address line could be faulty.)
Anyway, to me the NOP business seems important. IMO it's a clue worth paying attention to. What happens if you add 4 or 8 NOP's? Or 16? Experiments like that could alert you to what's really going on.
cheers
Jeff
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html
https://laughtonelectronics.com/Arcana/ ... mmary.html
- BigDumbDinosaur
- Posts: 9425
- Joined: 28 May 2009
- Location: Midwestern USA (JB Pritzker’s dystopia)
- Contact:
Re: 65c02 - Program Counter/stack issue
xbg wrote:
So thats my whole ISR...
Also, you can make your code a bit more succinct:
Code: Select all
int_routine pha
...you may need code here to differentiate
between an IRQ & a BRK instruction...
lda cia_icr ;read 6526's interrupt status...
;
; ——————————————————————————————————————————————————————————————
; If the above read operation occurs one or two Ø2 cycles before
; timer B is scheduled to interrupt, that interrupt may not occur
; & subsequent code may fail.
; ——————————————————————————————————————————————————————————————
;
lsr A ;timer A interrupt?
bcc check_timer_b ;no
;
inc sid_flag ;yes
;
check_timer_b lsr A ;timer B interrupt?
bcc check_uart ;no
;
; ———————————————————
; The above may fail!
; ———————————————————
;
inc tb_flag ;yes
;
check_uart lda uart_isr ;get int status register & ack
cmp #$06 ;line status register int (RX byte ready)
bne end_int
;
inc uart_flag
;
end_int pla
rtiLastly, the standard 6526 is rated for 1 MHz operation. The rarely seen 6526B was rated for 2 MHz operation. Set your clock accordingly! You'd be better off with the WDC 65C22, which can be clocked to 14 MHz and whose timer interrupts work as they should.
x86? We ain't got no x86. We don't NEED no stinking x86!
Re: 65c02 - Program Counter/stack issue
Thanks to all of you for the inputs. Ill try to see if I can dig an ez-usb device somewhere, otherwise it will have to wait until the christmas vacation as my logic analyzer is 8 channels. I don't think I'd be able to get a high enough throughput on usb on any of my embedded devices in a timely manner.
Data line is the first thing I'll investigate today...
And yep, I still have a lot of tricks to learn with ASM. The useless pushes and pulls are artifacts left from when I ran the music routine from inside the isr to make it longer and make that problem manifest faster, but I would have never thought about the shifting by myself. Thanks!
Data line is the first thing I'll investigate today...
And yep, I still have a lot of tricks to learn with ASM. The useless pushes and pulls are artifacts left from when I ran the music routine from inside the isr to make it longer and make that problem manifest faster, but I would have never thought about the shifting by myself. Thanks!
Re: 65c02 - Program Counter/stack issue
I fixed the problem!
It was an issue with my RAM OE#/WE#/CE# logic. I completely rewired it to switch from CE# to WE# controlled write cycle logic (if this even make sense, basically switched the phi2 nand-strobe from one line to the other) and everything started working fine. I think there was some unwanted delay on the OE# creating this problem (or something else, anyway...). I still can't believe it didn't manifest earlier/worked at all.
Right now my address decoding / logic chips block look like a tangled mess but I'll stick around and post the result once it's all cleared up.
Thanks guys.
It was an issue with my RAM OE#/WE#/CE# logic. I completely rewired it to switch from CE# to WE# controlled write cycle logic (if this even make sense, basically switched the phi2 nand-strobe from one line to the other) and everything started working fine. I think there was some unwanted delay on the OE# creating this problem (or something else, anyway...). I still can't believe it didn't manifest earlier/worked at all.
Right now my address decoding / logic chips block look like a tangled mess but I'll stick around and post the result once it's all cleared up.
Thanks guys.
Last edited by xbg on Tue Dec 12, 2017 4:49 am, edited 1 time in total.
Re: 65c02 - Program Counter/stack issue
Good to hear it!