6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Nov 10, 2024 11:27 pm

All times are UTC




Post new topic Reply to topic  [ 15 posts ] 
Author Message
PostPosted: Sun Dec 03, 2017 12:25 am 
Offline

Joined: Sat Dec 02, 2017 11:31 pm
Posts: 6
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!


Top
 Profile  
Reply with quote  
PostPosted: Sun Dec 03, 2017 5:04 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10977
Location: England
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.


Top
 Profile  
Reply with quote  
PostPosted: Sun Dec 03, 2017 5:35 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8539
Location: Southern California
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.

_________________
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  
PostPosted: Sun Dec 03, 2017 6:26 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8481
Location: Midwestern USA
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!


Top
 Profile  
Reply with quote  
PostPosted: Sun Dec 03, 2017 12:26 pm 
Offline

Joined: Sat Dec 02, 2017 11:31 pm
Posts: 6
So thats my whole ISR
Code:
*=$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



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.


Last edited by xbg on Sun Dec 03, 2017 12:40 pm, edited 2 times in total.

Top
 Profile  
Reply with quote  
PostPosted: Sun Dec 03, 2017 12:30 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10977
Location: England
There's a missing space here - I don't suppose your assembler would do something weird with that?

xbg wrote:
Code:
check_uartlda uart_isr ; get int status register & ack


Top
 Profile  
Reply with quote  
PostPosted: Sun Dec 03, 2017 12:38 pm 
Offline

Joined: Sat Dec 02, 2017 11:31 pm
Posts: 6
BigEd wrote:
There's a missing space here - I don't suppose your assembler would do something weird with that?

xbg wrote:
Code:
check_uartlda uart_isr ; get int status register & ack


Na its my copy/pasting from vim which had bad indentation, and I accidently posted while editing.


Top
 Profile  
Reply with quote  
PostPosted: Sun Dec 03, 2017 12:40 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10977
Location: England
Looks good to me. Are you seeing at least one increment, so you know you've installed the ISR OK?


Top
 Profile  
Reply with quote  
PostPosted: Sun Dec 03, 2017 12:54 pm 
Offline

Joined: Sat Dec 02, 2017 11:31 pm
Posts: 6
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.


Top
 Profile  
Reply with quote  
PostPosted: Sun Dec 03, 2017 2:55 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10977
Location: England
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.


Top
 Profile  
Reply with quote  
PostPosted: Sun Dec 03, 2017 4:54 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
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
Welcome, xbg :)
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


Top
 Profile  
Reply with quote  
PostPosted: Sun Dec 03, 2017 11:14 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8481
Location: Midwestern USA
xbg wrote:
So thats my whole ISR...

I see you are using the 6526's timer B to generate IRQs. You should know that many 6526s have a defect that will cause the timer B interrupt to not work. Specifically, reading the interrupt status register one or two clock cycles before timer B is scheduled to underflow and interrupt may result in no interrupt occurring. Other than performing a "before and after" comparison on the timer contents, there is no workaround. As I recall, there was a 60 to 80 percent defect rate with these devices.

Also, you can make your code a bit more succinct:

Code:
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
              rti

Instead of doing specific comparisons on the 6526's status, you can just right-shift the accumulator and let carry tell you if the timer IRQ flag bits were or were not set. Also, note that there is no point in pushing registers that will not be used in the ISR, unless you like wasting clock cycles. Furthermore, your ISR makes no differentiation between an IRQ and BRK. If your foreground code has $00 in it and the 'C02 reads it as an opcode, that's a BRK and when it executes RTI it will land on the wrong address.

Lastly, 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!


Top
 Profile  
Reply with quote  
PostPosted: Mon Dec 04, 2017 4:11 am 
Offline

Joined: Sat Dec 02, 2017 11:31 pm
Posts: 6
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!


Top
 Profile  
Reply with quote  
PostPosted: Mon Dec 04, 2017 8:00 am 
Offline

Joined: Sat Dec 02, 2017 11:31 pm
Posts: 6
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.


Last edited by xbg on Tue Dec 12, 2017 4:49 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Mon Dec 04, 2017 8:27 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10977
Location: England
Good to hear it!


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 15 posts ] 

All times are UTC


Who is online

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