6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Thu Nov 21, 2024 5:34 pm

All times are UTC




Post new topic Reply to topic  [ 9 posts ] 
Author Message
 Post subject: Stack problems
PostPosted: Mon Sep 29, 2003 6:56 am 
Offline

Joined: Mon Sep 29, 2003 6:45 am
Posts: 7
Hi All,

Thought I'd ask this question before I give up for the evening and go to bed. I'm currently bringing up a very simple 6502 system; 2kx8 sram, 8kx8 eprom, '138 decode and a latch as an output device for debugging.

I wrote a couple test programs that completed without errors, but as soon as I started writing anything more complex (read: with JSRs)- I was out of luck.

I can read and write to my sram (that starts at $0000 obviously) all day long, without error- and I am doing LDX #$FF, TXS to init the SP.

Single PHAs and PLAs work fine as well... but as soon as I have something that touches the stack more than once in close proximity- no joy. Three Pushes of different numbers don't bring the same back on Pulls. And I'm assuming the RTS has the same problem.


I've tried three different SRAMs, I don't see much noise, I'm heavily decoupled and have tried another 6502.

Any thoughts?

TIA!


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Sep 29, 2003 7:34 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8543
Location: Southern California
Hmmm...   Do you have any interrupts?  Are you bringing phase 2 into the RAM CS logic?  Is there any possibility a variable is getting stored in page 1 where it could interfere with the stack (like because of erroneous indirects or indexing?  Should we assume it crashes easily?  What's the memory map?  (I doubt you have any bus contention at the problematic addresses, but it might be worth double-checking.)  If you start the stack at 1FF, can you see that the problem starts when the stack gets down to a particular address in page 1?  It could even be that just one address pin is touching something it shouldn't, and depending on which one it is, it's still possible your short ROM code could still work to some extent, but you could start overwriting some stack bytes.  I could be way off, but maybe these things will trigger another idea that will get things going.

_________________
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:
PostPosted: Mon Sep 29, 2003 3:11 pm 
Offline

Joined: Wed Sep 04, 2002 4:08 pm
Posts: 57
Location: Iowa
You have a problem with either your address bus or your data bus.

Does your memory test write a few different values to RAM and then read them back? (Remember to write a few values first and then read them all back; don't write one, read one, then move on to the next.). Did you try your memory test IN the stack? (Not using JSR or PHP, but something like STA $100, STA $101, etc.?) Are you using unique values in your memory test? Are you writing consecutive addresses and non-consecutive addresses? Here's a great article discussing these techniques:

http://www.embedded.com/2000/0007/0007feat1.htm


Some problems you might be having are shorted address and/or data lines, poorly connected address/data lines (in this case, stray capacitance may make it look like a value is written to a address and read back correctly when really it's just the capacitance on the data bus that is holding the data, not the SRAM chip--speaking of which, how does your test behave without any SRAM chip in the socket at all? Try it), or bad control logic. Garth's question about phase 2 into the RAM CS logic is appropriate; some 6502 designs forget this, though most can get away without it, but all should include it. If you have a question about what this means, it can be explained.

One more question, if you have access to an oscilloscope, it can be very revealing on the address/data/control bus, especially if you can watch two signals at the same time.

Good luck!

Scott


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Sep 29, 2003 5:02 pm 
Offline

Joined: Mon Sep 29, 2003 6:45 am
Posts: 7
Wow. Thanks for the responses.

On the SRAM test: yes, I am doing some writes to the sram, then some reads from eprom, a write to a different location in sram and then back to read the original values that I wrote. I learned some time ago that one write/read cycle even w/o a ram in the socket can pass that test.

Thanks for the link- once I get this working, I'll want to do a better memory test so that'll be helpful.

And no, it fails my tests w/o the SRAM in the socket, immediately. I pulse a failure code out my latch that I can read on the 'scope.

---

On the shorting on the bus: I've run some pretty complex programs (but w/ no subroutines) and I think the buses are okay.

---

On the "where does the stack fail question":

Three pushes in a row (of bytes, from PHA) work fine. But a single JSR/RTS fails to bring back the right address. In both cases these would the first stack op, $1FF.

---

I think I'm going to take the bus problem idea and tackle that first. I haven't scoped out what all the lines look like. Perhaps I've got some weird problem that's just affecting one of the lines.

---


Thanks again for these valuable tips!


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Sep 29, 2003 5:15 pm 
Offline

Joined: Mon Sep 29, 2003 6:45 am
Posts: 7
Here's a possible problem and question:

Do I need to qualify my r/w* with P2, or just my CS* to my SRAM?

Thanks again.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Sep 29, 2003 9:14 pm 
Offline

Joined: Wed Sep 04, 2002 4:08 pm
Posts: 57
Location: Iowa
A good way to do it for 62xx style SRAMs or anything with /WE and /OE inputs is to generate /WE and /OE by using R/W into a NAND gate with PH2 for /OE and R/W inverted into another NAND gate with PH2 for /WE. The inverted R/W can be generated by a third NAND gate with one input tied high.

Scott


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Oct 01, 2003 4:16 pm 
Offline

Joined: Sat Jan 04, 2003 10:03 pm
Posts: 1706
s800 wrote:
On the "where does the stack fail question":

Three pushes in a row (of bytes, from PHA) work fine. But a single JSR/RTS fails to bring back the right address. In both cases these would the first stack op, $1FF.


When JSR or RTS put/pull stuff off the stack, it does so one cycle after the next. When you execute three PHA or PLA instructions, there are intervening cycles. This might have an effect. At what clock speed are you running this thing at? Can you try slowing your clock down to, say, 250kHz (or for that matter, even slower), to see if that has any effect?

Also, can you verify whether it is JSR or RTS that is corrupting the data? This can be checked using code such as the following:

Code:
jsr_test:
  jsr jsr_test_1
jsr_test_1:
  pla
  sta $01
  pla
  sta $00
  ...


In the above example, $00-$01 would contain the return address pushed onto the stack by JSR (NOTE: 6502's JSR instruction pushes the return address minus 1). After executing the above code, the address stored in $00/$01 ought to be the address of (jsr_test_1 - 1).

By the same token,

Code:
rts_test_1m1 = rts_test_1 - 1

rts_test:
  lda #<rts_test_1m1
  pha
  lda #>rts_test_1m1
  pha
  rts
rts_test_1:
  ...


I don't know of a good way to adequately test the contents of the PC except to halt the microprocessor (bring RDY line low) immediately on the next _SYNC pulse after seeing the RTS instruction read. The status of A0-A15 would then contain the value that was read from the stack.

It's a pity you're not using the 65816 -- I would ask you to place the chip into native mode with 16-bit index registers, and execute a few PHX and PLX instruction, to see if access timing is causing the problem. Speaking of access timing, is your SRAM chip fast enough to keep up with the 6502? Is your address decoding logic fast enough?

Quote:
I think I'm going to take the bus problem idea and tackle that first. I haven't scoped out what all the lines look like. Perhaps I've got some weird problem that's just affecting one of the lines.


With the system off, obviously, use a continuity checker to verify each and every address and data bus line against every other chip in the system. You should get continuity only on like pins (e.g., D0 on one chip and D0 on another chip), assuming they're on the same bus (e.g., buffered buses aren't guaranteed to respond this way).

--
Samuel A. Falvo II


Top
 Profile  
Reply with quote  
 Post subject: Re: Stack problems
PostPosted: Mon Sep 09, 2024 2:50 pm 
Offline

Joined: Tue Sep 26, 2023 11:09 am
Posts: 109
Having similar problems many years in the future. Wonder if this ever got resolved. But some great ideas to try!

Here's an updated link for the 'software based memory testing' article by M Barr which was linked earlier in the thread and is now defunct.

https://www.esacademy.com/en/library/te ... sting.html


Top
 Profile  
Reply with quote  
 Post subject: Re: Stack problems
PostPosted: Thu Sep 12, 2024 1:14 am 
Offline

Joined: Tue Sep 26, 2023 11:09 am
Posts: 109
I implemented a version of these tests to see if that would shed any light on my mystery. Unfortunately(?) they all run correctly on my hardware, showing expected results for my setup.

Figured I'd share in case it was useful for anyone else. Quick and easy to run while watching output in a monitor tool like https://github.com/Nectivio/65C02-Tool At the end of the test it cycles reading the test result bytes to make it easy to observe.


Code:
mem_test:

.comment

Perform several memory integrity tests based on Michael Barr's
"Software-based memory testing" article.
See https://www.esacademy.com/en/library/technical-articles-and-documents/miscellaneous/software-based-memory-testing.html

These help detect wiring issues in the data bus and address
bus, as well as address decoding problems or missing / damaged ICs.
If you suspect a problem it can be helpful to burn this code
and observe it with an external monitor like https://github.com/Nectivio/65C02-Tool

By default test results are written to $d0-$ff, and the stack ($100-1ff)
is filled with all possible byte values: 0, $80, 1, $81, 2, $82, ..., $7f, $ff.

With RAM at $0000-bfff, IO at $c000-c0ff and ROM at $c100-ffff
we'd expect results like this:

00d0  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
00e0  ff ff ff ff ff ff ff ff  0? 00 00 00 00 00 00 00
00f0  01 02 04 08 10 20 40 80  c0 ff ff ff ff ff ff ff
0100  00 80 01 81 02 82 03 83  04 84 05 85 06 86 07 87
...

The range $d0-$ef is a memory map showing one bit per page (256/8 = 32 bytes)
indicating if a byte within page is writable (RAM) or not (ROM).
The ? is 0 or 1 depending on whether the tested I/O byte acts like RAM or not.
(Nb. a simulator without ROM write protection will likely show all $ff values.)

The test results $fb-ff should be $ff, with $fa counting the number of pages
which supported read/write.

.endcomment

rw_map = $d0        ; 32 byte memory bitmap
dbus_tgt = $f0      ; 8 byte output range

test_out = $f8      ; we loop reading these 8 bytes at end of test

rw_cnt = $f8        ; count of r/w RAM pages (usually, e.g $c0, or $0 for all RAM)
rw_out = $f9        ; tested pages-1 (should be $ff)
dbus_out = $fa      ; single byte test result (should be $ff)
abus_out = $fb      ; single byte test result (should be $ff)
stk_out = $fc       ; two byte stack test result (should be $ffff)
test_ptr = $fe      ; temporary two byte pointer
jsr_out = $fe       ; overwrites test_ptr in last test (should be $ffff)

; If your highest RAM address is smaller than $8000, choose the highest
; max_ram_bit where 1 << max_ram_bit is still RAM.  For example if your
; address decoding has RAM from $0..3fff then choose max_ram_bit=13 since
; $2000 (binary %0010_0000_0000_0000) is in RAM but $4000 is not.

max_ram_bit = 15     ; In my system, $8000 is in RAM

dbus_test:
    ; Test that the databus lines are wired correctly by checking that
    ; they can each be set independently.  We write a "walking one"
    ; to a fixed address and test that we can read back. It's OK
    ; to read immediately after write since we'll check persistence later.
    ; If the test fails dbus_val will contain the failing pattern,
    ; otherwise it will contain $0.
        lda #$80
        ldx #7
-
        sta dbus_tgt,x
        cmp dbus_tgt,x
        bne _fail
        lsr
        dex
        bpl -
_fail:
        stx dbus_out

abus_test:
    ; Now test that the address bus lines can be set independently
    ; to both one and zero.  We'll write the values 1,2,3, ... to
    ; RAM addresses %0, %1, %10, %100, %1000 and so forth.
    ; If any bit is stuck high or low, or two bits are coupled, then
    ; writing to one of these addresses will change one or more of the others.
    ; We do a slightly less strict test than described in the article
    ; by simply reading back and summing the values after we've written
    ; them all.  A successful test sums 1+2+3+..+(max_bit+2)
    ; which equals (max_bit+2)*(max_bit+3)/2.

        ; Set up first test address
        stz test_ptr
        stz test_ptr+1

        lda #max_ram_bit+2
        sec
-
        sta (test_ptr)          ; Store test value
        rol test_ptr
        rol test_ptr+1          ; Walk the address bit upward
        dea                     ; Decrement test value
        bne -

        ; Repeat the process to validate the sum, starting
        ; from an offset that should make us finish at $ff

        stz test_ptr
        stz test_ptr+1

        lda #255 - (max_ram_bit+2) * (max_ram_bit+3) / 2
        clc
        adc (test_ptr)          ; initial value

        ldx #max_ram_bit+1
        sec
-
        rol test_ptr
        rol test_ptr+1
        adc (test_ptr)          ; C=0 before and after
        dex
        bne -
        sta abus_out

rw_test:
    ; form a bitmap indicating whether we can write to a byte in each page
    ; we use addresses like $0080, $0181, $0282, $0383, ..., $1090, ...
    ; We test reading and writing complementary bit patterns $aa and $55
    ; but restore the original value to avoid stomping simulator "ROM".
        lda #$80
        sta test_ptr
        stz test_ptr+1
        stz rw_cnt
        stz rw_out

        ldx #0
_loop:
        lda #$80                ; sentinel bit sets C=1 after 8 shifts
        sta rw_map,x
-
        clc                     ; assume we can't r/w (c=0)
        lda (test_ptr)
        tay                     ; save original value
        lda #$55
        sta (test_ptr)
        cmp (test_ptr)
        bne +
        lda #$aa
        sta (test_ptr)
        eor (test_ptr)
        bne +
        tya
        sec                     ; r/w succeeded, c=1
        inc rw_cnt              ; count r/w pages
+
        inc rw_out              ; count pages
        sta (test_ptr)          ; restore original value

        ror rw_map,x            ; roll in the result for this page
        inc test_ptr            ; move to next target address
        inc test_ptr+1
        beq _done               ; wrapped?
        bcc -                   ; finished 8 pages?

        inx
        bra _loop
_done:
        dec rw_out              ; # pages - 1 should be $ff

stk_test:
    ; Test the stack by writing the values $ff, 0, ... $fe
    ; to memory locations $100..1ff and then popping them all
    ; in turn to sum them.  We expect 255*256/2 = $7f80
    ; and add the constant $807f to get a result of $ffff.

        ldx #0
-
        txa                     ; fill stack with ff, 0, ..., fe
        inx
        sta $100,x
        bne -

        lda #$7f                ; initial value $807f
        sta stk_out
        ina
        sta stk_out+1

        dex                     ; X is 0 => $ff
        txs                     ; SP = $ff
        inx                     ; back to X=0
-
        pla                     ; pop 256 items off the stack and sum
        clc
        adc stk_out
        sta stk_out
        lda #0
        adc stk_out+1
        sta stk_out+1
        inx
        bne -

jsr_test:
    ; test filling the stack with 128 recursive calls and unwinding
    ; we'll sum up the stack pointer values we see within each call,
    ; which look like $fd, then $fb, $f9, ... $1 and finally $ff on
    ; the final iteration.   The sum of odd values 1+3+...+255
    ; ending in 2*128-1 is 128^2 = $4000.
    ; We'll leave the stack itself filled with all unique bytes like
    ; $0

    ; SP starts as $ff (empty stack),

        lda #$ff                ; Start sum from $bfff so we end at $ffff
        sta jsr_out
        lda #$bf
        sta jsr_out+1

        ldy #$80

recurse_test:
        dey                     ; count down recursion depth
        bmi +

        tsx
        txa                     ; grab stack pointer
        clc
        adc jsr_out             ; add to running sum
        sta jsr_out
        lda #0
        adc jsr_out+1           ; handle carry
        sta jsr_out+1
        jsr recurse_test
        tya                     ; leave breadcrumbs as we empty stack
        ora #$80                ; -Y-1
        pha
        phy                     ; original
        pla
        pla
+
        iny
        bmi _done
        rts
_done:

; --- tests end ---

forever:
    ; after the tests we'll just loop reading the output so that
    ; we can easily observe the values in a monitor tool
        ldx #test_out
-
        lda 0,x
        inx
        bne -                   ; cycle thru values until we wrap past $ff

        bra forever             ; or jump to your kernel etc



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

All times are UTC


Who is online

Users browsing this forum: Google [Bot] and 30 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: