6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Nov 10, 2024 8:46 am

All times are UTC




Post new topic Reply to topic  [ 15 posts ] 
Author Message
PostPosted: Mon Jul 03, 2017 2:01 am 
Offline

Joined: Mon Jul 03, 2017 1:15 am
Posts: 6
Greetings fellow 6502 enthusiasts! Following in what seems like every other 8-bit curmudgeon's footsteps, I've spent the last few months working on a compact, affordable 6502 SBC for my own enjoyment and (hopefully, one day) to serve as the core around which I'll build a wholesome afterschool computing program for local kids. I read and reread Garth Wilson's primer (hereafter The Good Site) and breadboarded out something very close to the basic layout found in his 'potpourri' section. I wrote a few simple routines including a RAM tester and 4-bit KS0066 character LCD driver and drank deeply of the satisfaction of having built a working 8-bit computer. When I discovered that PCB production had become dirt cheap, I designed a densely-packed board and sent the gerbers off to EasyEDA for production. The result was surprisingly professional and, again indulging in the pride that precedes a fall, I open-sourced my layout on GitHub, going with the name 'PINKY-8' so as to permit the tagline, "When ARM's too much, try PINKY." See https://github.com/contrarian-computing/pinky-8

As my goal is to implement support for dual Micro SD 'floppies' and HDMI Video / USB Input via PiGFX (https://github.com/fbergama/pigfx) I opened up CA65 and set to work implementing SPI and a MAX3100 UART driver atop that. When I tested my new ROM, I was surprised by what seemed to be a ton of spurious interrupts from the VIA. I double-checked my VIA initialization code and later pulled IRQ# high on the '02 but my IRQ handler was called again and again. I looked more closely and discovered that I was entering the IRQ handler after certain (generally later-occurring) RTS calls, indicating that the return address on the stack was incorrect, leading the CPU into unaligned/unused memory full of $00, aka BRK. I figured I had unbalanced push/pulls somewhere, audited the code thoroughly and found nothing. I reduced my code to test cases for stack manipulation and the problem disappeared. I added some code back and the behavior returned, ultimately leading to a disturbing revelation: I can make the problem disappear or go away by removing or inserting NOPs between my RESET routine and the rest of the code. Specifically, the problem seems to occur when there is execution of code in the later bytes of page $81 (the second page of ROM). This strongly suggests an address decoding issue of some sort, because if SRAM were somehow enabled (and WE# low) during $81xx reads, it would corrupt the stack in $0100-$01FF. I replaced the SRAM, verified continuity on everything, verified connections from datasheet pinouts, checked for shorts, etc. and failed to uncover any issues with the board. The behavior is consistent for any given ROM, changing only when ROM offsets change.

After 12 hours testing various hypotheses I broke down and ordered a 32 channel logic analyzer. While I'm waiting for it to arrive, would anyone like to spitball as to what shameful mistake I've made? As I said, it's pretty much just The Good Site's basic schematic on a PCB - 16K RAM (from a 32K chip), 32K ROM (128K chip with 4 jumpered banks), decoded with a single 74AC00N. Minty fresh W65C02S and W65C22S from Mouser, running at 2Mhz from an oscillator can. (Full specs on GitHub)


Last edited by contrariancomp on Mon Jul 03, 2017 3:24 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 03, 2017 2:07 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8479
Location: Midwestern USA
contrariancomp wrote:
While I'm waiting for it to arrive, would anyone like to spitball as to what shameful mistake I've made? As I said, it's pretty much just The Good Site's basic schematic on a PCB - 16K RAM (from a 32K chip), 32K ROM (128K chip with 4 jumpered banks), decoded with a single 74AC00N. Minty fresh W65C02S and W65C22S from Mouser, running at 2Mhz from an oscillator can. (Full specs on GitHub)

It would be convenient if you could post the schematic here instead of making us deal with Github. I'd like to help but have never had much success getting anything from that site.

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


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 03, 2017 3:05 am 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
contrariancomp wrote:
"When ARM's too much, try PINKY."
Oh, great -- another comedian! :roll: :wink: :P

contrariancomp wrote:
I looked more closely and discovered that I was entering the IRQ handler after certain (generally later-occurring) RTS calls, indicating that the return address on the stack was incorrect, leading the CPU into unaligned/unused memory full of $00, aka BRK.
Can you elaborate on what "looked more closely" means? Sounds like you're examining the stack upon entry to the ISR. The last items pushed to stack will be the address of a BRK opcode plus two, and the P register. So, you're examining the previous item pushed to stack?

Welcome!

-- 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: Mon Jul 03, 2017 3:16 am 
Offline

Joined: Mon Jul 03, 2017 1:15 am
Posts: 6
Gladly! Nice to make your acquaintance, BDD. There's now a JPEG of the schematic in the repo here: https://github.com/contrarian-computing/pinky-8/blob/master/pinky-8.sch.jpg


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 03, 2017 3:31 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8538
Location: Southern California
Welcome, and congratulations on the success so far. It sounds like you have a good understanding of how to troubleshoot. I'm glad my 6502 primer was a help.

As you can see, there's no way the SRAM's chip select can go true while the ROM is selected. I was going to say make sure you pay attention to how A14 is used in the memory, since it's a subtle part of the address decoding, but then you posted the link to the schematic while I was writing, and it looks like you took care of it. Make sure you don't leave A15 and 16 on the ROM floating as currently shown. (A small note—monochrome, black lines on white background, seems best for diagrams. BDD is one of our colorblind members. He can correct me if I'm wrong, but I think the light green disappears into the white background for him.) Something I've used to troubleshoot these things is the single-cycler in section 6, the "clock generation" section, the 3rd-to-last diagram on the page.

_________________
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: Mon Jul 03, 2017 3:39 am 
Offline

Joined: Mon Jul 03, 2017 1:15 am
Posts: 6
Thanks, Doc, I'll try to tone down the dad humor :oops:
Dr Jefyll wrote:
Can you elaborate on what "looked more closely" means? Sounds like you're examining the stack upon entry to the ISR. The last items pushed to stack will be the address of a BRK opcode plus two, and the P register. So, you're examining the previous item pushed to stack?

In my desperation I fell back on old debugging-with-no-debugger techniques and peppered the code with print statements (for the character LCD). I noticed the pattern after testing a few revisions. I have yet to directly observe bad addresses on the stack so it's all still supposition. Tonight I'll put together a routine to print addresses off the stack and invoke it just before problematic RTS calls. As I'll have to JSR to that routine I'll print out what was put on the stack for it as well.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 03, 2017 4:17 am 
Offline

Joined: Mon Jul 03, 2017 1:15 am
Posts: 6
GARTHWILSON wrote:
Welcome, and congratulations on the success so far. It sounds like you have a good understanding of how to troubleshoot. I'm glad my 6502 primer was a help.

Thanks! It's nice to be finally be conversing here after years of lurking.
GARTHWILSON wrote:
As you can see, there's no way the SRAM's chip select can go true while the ROM is selected.

That's what I thought, leading me to suspect a bridged, shorted or floating line somewhere but I haven't found one yet. :?
GARTHWILSON wrote:
Make sure you don't leave A15 and 16 on the ROM floating as currently shown.

They're both pulled down to ground by jumpers on the board. That much is working.
GARTHWILSON wrote:
(A small note—monochrome, black lines on white background, seems best for diagrams. BDD is one of our colorblind members. He can correct me if I'm wrong, but I think the light green disappears into the white background for him.)

Good call, I've updated the JPG in the repo: https://github.com/contrarian-computing/pinky-8/blob/master/pinky-8.sch.jpg
GARTHWILSON wrote:
Something I've used to troubleshoot these things is the single-cycler in section 6, the "clock generation" section, the 3rd-to-last diagram on the page.

Thanks, I'll get that ready while I'm waiting for the logic analyzer to arrive.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 03, 2017 4:29 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8479
Location: Midwestern USA
contrariancomp wrote:
Gladly! Nice to make your acquaintance, BDD. There's now a JPEG of the schematic in the repo here: https://github.com/contrarian-computing/pinky-8/blob/master/pinky-8.sch.jpg

Thanks!

Some things I noted:

  • You have BE, NMI(B), RDY and SO(B) all tied to the same pullup resistor. RDY is a bi-directional pin and should be on its own pullup. If the 65C02 executes a WAI instruction it will drive RDY low, which in turn will drive the others low, causing the MPU to high-Z the buses, think it should service a non-maskable interrupt and set the overflow bit in SR (status register), all at the same time. Just think about how confusing that would be to the MPU, not to mention the poor bloke who's trying to get the contraption working. :D

    Now, you may not have used WAI in your code, but a program error could cause the MPU to encounter $CB and think that it is a WAI instruction opcode.

  • You have pins 12 and 13 of U2 unconnected, leaving those inputs floating. That is a no-no with CMOS hardware. You should either ground them or pull them up to Vcc.

  • Are you sure that USB power source you are using to run your machine has enough nuts for the job?

  • A design hint for the future: the first gate in U2 is being used as an inverter. You can delete R1 and instead tie pins 1 and 2 together, thus saving on a part and a little bit of PCB real estate.

  • A second design hint for the future: do not use the clock outputs of the MPU. WDC doesn't test the performance of those outputs and in fact, doesn't even state how much they lag the clock input, how hard they drive, or the rise and fall time. All clocking should be derived from your Ø2 oscillator (X1).

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


Last edited by BigDumbDinosaur on Mon Jul 03, 2017 4:44 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 03, 2017 6:20 am 
Offline

Joined: Wed Feb 12, 2014 1:39 am
Posts: 173
Location: Sweden
Echoing BDD's last point I was having a whole stack of stability problems with my own 1st design that I couldn't figure out for the life of me. Cutting the trace from the MPU's Clock output and driving everything directly from the oscillator can fixed that.

Re: Pull-ups, any WAI instructions will also generate an NMI immediately as it shares the same pull-up
If I'm interpreting this correctly, your address decoding is going to select the RAM whenever the VIA is selected too, any time you write to the VIA you're going to write to the ram too?

Your ROM CE and OE are tied together, you can instead tie CE to ground to save a bunch of time for ROM accesses, looking at the datasheet the CE access time is 70-90ns while OE is 30-40ns though doing so will increase power consumption as the rom will never go into standby mode.


Attachments:
Screen Shot 2017-07-03 at 4.24.38 PM.png
Screen Shot 2017-07-03 at 4.24.38 PM.png [ 39.28 KiB | Viewed 4679 times ]
Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 03, 2017 6:55 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10975
Location: England
Welcome contrariancomp!

In your IRQ handling routine, you can inspect the saved processor status as found on the stack and distinguish whether you hit a BRK. You could also perhaps save the top three bytes of the stack somewhere and arrange to display them or inspect them later.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 03, 2017 8:16 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8538
Location: Southern California
LIV2 wrote:
If I'm interpreting this correctly, your address decoding is going to select the RAM whenever the VIA is selected too, any time you write to the VIA you're going to write to the ram too?

Yes. That's a subtle part of doing the entire address-decoding scheme with only three sections of a 74xx00. There's 16KB of addressable RAM; but there are no 16KB SRAMs, so you use a 32KB. When you write to I/O, you're also writing to the upper half of the RAM; but it doesn't matter, because it will never be read out and cause bus contention, because anytime A14 is high, the RAM's output will be disabled. I've been using that scheme on my workbench computer for 24 years.

_________________
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: Fri Jul 07, 2017 2:33 am 
Offline

Joined: Mon Jul 03, 2017 1:15 am
Posts: 6
Thanks for the tremendous support, guys. I'll go into the gory details below but tl;dr is that your suggestions addressed the issue.

BigDumbDinosaur wrote:
You have BE, NMI(B), RDY and SO(B) all tied to the same pullup resistor. RDY is a bi-directional pin and should be on its own pullup. If the 65C02 executes a WAI instruction it will drive RDY low, which in turn will drive the others low, causing the MPU to high-Z the buses, think it should service a non-maskable interrupt and set the overflow bit in SR (status register), all at the same time. Just think about how confusing that would be to the MPU, not to mention the poor bloke who's trying to get the contraption working. :D

This was an oversight on my part that I'll address in the next revision. Thanks for pointing that out.
BigDumbDinosaur wrote:
You have pins 12 and 13 of U2 unconnected, leaving those inputs floating. That is a no-no with CMOS hardware. You should either ground them or pull them up to Vcc.

I made poor assumptions about the independence of gates on the 74xx00. Remedied it with bodge wires but it wasn't sufficient to fix the stack corruption. Again, thanks for the correction - it'll be in the next PCB revision.
BigDumbDinosaur wrote:
Are you sure that USB power source you are using to run your machine has enough nuts for the job?

I'm using 10W and 12W Apple iPad chargers as they have high output, low noise, very good regulation and safe construction. Though, for whatever reason, Apple decided that voltage sag is a good thing and made these supplies nominally 5.1V and 5.2V, respectively, dropping to ~5V under load. Conveniently, the sag is linear with respect to current right up to the limit so you can compute load from observed voltages. With the 12W charger, VCC is 4.98V with the logic board, CLCD, MAX 3100 and Raspberry Pi Zero going. I based my selection on this comprehensive lab test of common USB chargers.
BigDumbDinosaur wrote:
A design hint for the future: the first gate in U2 is being used as an inverter. You can delete R1 and instead tie pins 1 and 2 together, thus saving on a part and a little bit of PCB real estate.

Makes sense! I don't know why I didn't do that...perhaps I was worried about additional load on A15?
BigDumbDinosaur wrote:
A second design hint for the future: do not use the clock outputs of the MPU. WDC doesn't test the performance of those outputs and in fact, doesn't even state how much they lag the clock input, how hard they drive, or the rise and fall time. All clocking should be derived from your Ø2 oscillator (X1).

So this, it turns out, was root of the problem. The best places to cut the traces from the '02's PHI2O to the 74AC00 and 65C22 were under the sockets so I started over on a second board, transferring components from the first. With bodge wires in place to transmit the clock directly from X1, I'm no longer seeing stack corruption and spurious BRKs. PHI2O must be sufficiently out of phase to cause RAMSEL to be low at an inopportune moment. Without an oscilloscope it's hard to dig deeper.

I'm very excited to complete my UART and get some text and graphics going on the Pi! Thanks again everyone who pitched in!


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 07, 2017 4:39 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8479
Location: Midwestern USA
contrariancomp wrote:
BigDumbDinosaur wrote:
A design hint for the future: the first gate in U2 is being used as an inverter. You can delete R1 and instead tie pins 1 and 2 together, thus saving on a part and a little bit of PCB real estate.

Makes sense! I don't know why I didn't do that...perhaps I was worried about additional load on A15?

CMOS inputs look like capacitors during the time the voltage is changing. They are not like TTL devices, which continually load whatever is driving them. Hence doubling up the inputs as I suggested will produce very little additional loading on A15.

Quote:
BigDumbDinosaur wrote:
A second design hint for the future: do not use the clock outputs of the MPU. WDC doesn't test the performance of those outputs and in fact, doesn't even state how much they lag the clock input, how hard they drive, or the rise and fall time. All clocking should be derived from your Ø2 oscillator (X1).

So this, it turns out, was root of the problem...PHI2O must be sufficiently out of phase to cause RAMSEL to be low at an inopportune moment. Without an oscilloscope it's hard to dig deeper.

Not belabor the obvious, but this is why it is so important to read the data sheet cover-to-cover, even if it's not well-written. On page 26 of the 65C02 data sheet is the following:

    Timing Notes:

  1. Timing measurement points are 50% VDD.
  2. PHI1O and PHI2O clock delay from PHI2 is no longer specified or tested and WDC recommends using an oscillator for system time base and PHI2 processor input clock.

The PHI1 and PHI2 outputs exist in the 65C02 for historical reasons, as does the SOB input. Back in the early days, the Ø2 clock was generated with a crystal circuit, which didn't have enough oomph to supply a clock signal to everything else on the board. So what MOS Technology did was use the 6502 as a sort of driver to provide a strong clock to other parts of the circuit. Since there were design cases where a two phase clock was needed, the 6502 had the required outputs.

When Bill Mensch designed the 65C02 he wanted to make sure it could be plugged into a system with an NMOS 6502 and everything would work as expected. Hence the PHI1 and PHI2 outputs were retained from the original 6502 design. SOB, which was something that Chuck Peddle apparently thought might be useful, was also carried over, even though it was almost never used (the Commodore 1541 floppy disk drive made use of SOB, the only example I know about). The result was that up until the 65C02 was converted to a static core it was 100 percent hardware compatible with the 6502 and as long as a program didn't use any undefined opcodes, 100 percent software compatible as well.

When the static core conversion of the 65C02 was made, pin 1 was reassigned from being ground to being the VPB output, which slightly broke hardware compatibility. MLB was assigned to the previously no-connect pin 5 and BE was assigned to the previously no-connect pin 36. I was aware of a few systems in which pins 5 and 36 were used as tie points, since they weren't connected to anything in the NMOS part. Plugging a static core 65C02 into such a system would at best result in no operation. At worst it could damage the 'C02.

Quote:
I'm very excited to complete my UART and get some text and graphics going on the Pi! Thanks again everyone who pitched in!

Which UART are you using?

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


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 07, 2017 7:19 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8538
Location: Southern California
contrariancomp wrote:
BigDumbDinosaur wrote:
You have pins 12 and 13 of U2 unconnected, leaving those inputs floating. That is a no-no with CMOS hardware. You should either ground them or pull them up to Vcc.

I made poor assumptions about the independence of gates on the 74xx00. Remedied it with bodge wires but it wasn't sufficient to fix the stack corruption. Again, thanks for the correction - it'll be in the next PCB revision.

It's not about the independence of gates, but about what happens with the internal transistors when CMOS inputs are allowed to loiter between valid logic states. We covered this recently at viewtopic.php?f=4&t=4561&p=54303#p54303 .

_________________
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: Tue Jul 11, 2017 11:08 pm 
Offline

Joined: Mon Jul 03, 2017 1:15 am
Posts: 6
BigDumbDinosaur wrote:
Which UART are you using?

As I was working from Garth's primer I used the MAX3100 SPI UART he recommends. It's flexible, has a simple interface and comes in a breadboard-friendly package for prototyping. I had a lot of fun writing the routines to big-bang a duplex'ed SPI interface using the 65C22.

It took me a while to get everything working with the PiGFX UART, mostly because I didn't trust my own ability to properly interface with the MAX3100. Characters weren't showing up on the Pi and I couldn't figure out what the problem was by inspecting my code. I decided I needed to get serious and invest in proper hardware development tools, so I bought a 32-channel logic analyzer and proceeded to port the entire Sigrok open-source analysis suite to my Linux distribution of choice, which is Solus. After doing this I got some very nice traces out of the 65C22 and MAX3100 which showed that my SPI routines and the MAX's UART were spot on. Only after spending a week on this did I Google issues with PiGFX and discover, from an archived mailing list discussion, that I was simply using an incompatible version of the the Raspberry Pi's bootloader. Swapped one file on the SD card et voila, everything worked as it should.


Attachments:
File comment: 65C22 bit-banging SPI to MAX3100 sending the first two characters of 'PINKY-8'
pinky-8-spi_uart.png
pinky-8-spi_uart.png [ 25.42 KiB | Viewed 4494 times ]
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: Google [Bot] and 1 guest


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: