• Another fascinating glitch!

    Dawid Buchwalda day ago 0 comments

    Why this keeps happening to me?

    So, last time I wrote about things that scare me the most: some seemingly random glitches that obscure larger design problems. This is why whenever I see something off I get really anxious - I'm afraid this time it will be too hard to fix, and I got pretty terrified recently!

    As usual, I want to share the story, partially because it makes for a nice cautionary tale, and partially because it was pretty interesting investigation that followed, with some magical twist to it.

    Status update

    First things first, to set the stage. Recently I made an amazing discovery, but I will cover this in a separate entry. Suffice to say I managed to solve one of the major pains with my first version of the board without any significant modifications to version 2.

    As a result I could finally move forward with clock switching design I wrote about previously. After having included all the comments from Reddit, I moved on to hardware implementation: one 74AC74, one 74HC157 and a full-can crystal oscillator.

    I was surprised to see how easy that was. With all the schematics prepared in advance and prototype build for my test fixture it took less than 15 minutes.

    Booted up OS/1 and all seems fine, the whole machine started at 8MHz, ran just fine until I decided to enter debug mode where it seamlessly switched to 300KHz mode with bus logging and when needed I could single step down to half-clock-cycle precision. Lovely.

    Another feature I included was real-time CPU clock frequency measurement, so the below output was captured in a single session, without restarting or powering down the computer:

    +---------------------------+
    |                           |
    |   ####   ####     #   #   |
    |  ##  ## ##       #   ##   |
    |  #    #  ###    #   # #   |
    |  ##  ##    ##  #      #   |
    |   ####  ####  #      ###  |
    |                           |
    +---------------------------+
    
    OS/1 version 0.3.5C (Alpha+C)
    Welcome to OS/1 shell for DB6502 computer
    Enter HELP to get list of possible commands
    OS/1>info
    OS/1 System Information
    System clock running at 0MHz
    
    ROM at address: 0x8000, used: 13420 out of 32768 bytes.
    System RAM at address: 0x0300, used: 1517 out of 3328 bytes.
    User RAM at address: 0x1000, used: 0 out of 28672 bytes.
    
    ROM code uses 9056 bytes.
    ROM data uses 4194 bytes.
    SYSCALLS table uses 164 bytes.
    
    VIA1 address: 0x0220
    VIA2 address: 0x0240
    Serial address: 0x0260
    
    Serial driver: SC26C92
    OS/1>info
    OS/1 System Information
    System clock running at 8MHz
    
    ROM at address: 0x8000, used: 13420 out of 32768 bytes.
    System RAM at address: 0x0300, used: 1517 out of 3328 bytes.
    User RAM at address: 0x1000, used: 0 out of 28672 bytes.
    
    ROM code uses 9056 bytes.
    ROM data uses 4194 bytes.
    SYSCALLS table uses 164 bytes.
    
    VIA1 address: 0x0220
    VIA2 address: 0x0240
    Serial address: 0x0260
    
    Serial driver: SC26C92
    OS/1>

    First time the INFO command was invoked, the computer was running at 300KHz, hence the 0MHz reading. Before second invocation I switched clock in the supervisor session to 8MHz and it was detected properly as you can see above.

    Lovely, isn't it?

    It seems like more and more features from my dream DB6502 build are getting implemented nicely, I'm proud to report :)

    And then it happened...

    So, obviously, I needed to test some more complex programs to see if the system is stable. I mean it's all very nice, but bare operating system doesn't make for a good testing software.

    I loaded some simple programs, and they all worked just fine. Tried MicroChess, which is using CPU and memory extensively and this one also worked correctly, no glitches there.

    Time for the most difficult one: Microsoft BASIC interpreter. It loaded just fine (well, almost, but that is different story I will cover another time), and I ran it in anticipation. It starts by asking user if this is Cold or Warm boot, and depending on the answer it starts memory size detection routine.

    The "memory detection" is really simple mechanism: it starts from defined address and moves on, byte by byte, writing and reading 0x55/0xAA to each address....

    Read more »

  • Test Driven Development meets hardware

    Dawid Buchwald10/20/2020 at 20:01 0 comments

    The scary stuff...

    So, I don't know about you guys, but for me the most scary part about designing any circuit whatsoever is that it might not work, but not all the time, just every now and then. Failure rare enough to be near impossible to capture, yet severe enough to make the device unusable.

    Sure, you can test your design all you want, but honestly, how many reliable tests can you execute? What if the problem is related to one of the most heavily used parts of your circuit? That will be near impossible to troubleshoot.

    So, I came with an idea for DB6502 v2 that would enable two modes of use: full-speed mode, without AVR supervisor attached (say 8MHz, will go faster next time), and slow-speed mode, with AVR analysing system busses. Obviously, AVR would be controlling the selector, and user can choose the mode on the fly, via the supervisor shell.

    Implementation of such contraption is actually pretty simple - all you need is single 2:1 multiplexer:

    So, depending on the signal fed to S pin on the mux, 6502 would be fed with 8MHz clock or the slow AVR variant. There is, however, a serious problem with this approach:

    There are certain requirements in the 6502 CPU as to the length of the clock cycle. Both high and low phases of the clock need to be of certain duration. If the toggle happens in the middle of low or high phase (called PHI1 and PHI2 respectively), CPU state might get corrupted. Nothing tragic, but whatever software ran on the computer would no longer work as expected.

    Probably most of the times you wouldn't even notice, because CPU would somehow recover or the data that was corrupted (like accumulator state) was not important (as it was going to be overwritten anyway in next cycle).

    However, every now and then, the results would be catastrophic - execution would fail due to hard to pinpoint glitch.

    The problem is that you need to find a way to ensure these things don't happen. Even if you know what to do (and probably some of you already know the solution to the issue at hand), the important questions is: how do you know the solution will work?

    TDD to the rescue!

    Well, I'm new to electronic engineering, but I'm no stranger to software development. What developers do to ensure their mission critical code runs correctly? They apply one of many proven techniques to ensure code correctness, and one of them is Test Driven Development where you start with writing tests that your software absolutely must pass. Your tests are not based on observations of the encountered or expected failures, your tests document the critical requirements. If your software must ensure safe plane landing you don't test altimeter reading, you test for collision, and first flight ends in flames :)

    Basically, to consider TDD execution to be proper, you have to ensure to see the test fail the first time. If you wrote your code first and the test later - you are doing it wrong. If you wrote your test first, and then your code that works - you are doing it wrong. You have to see your test fail to know that the test itself works correctly. Only then, when the test finally passes you can consider the code correct.

    So, how do we go about this approach with the problem at hand?

    There is just one requirement here: clock cycle can't be shorter that half the maximum CPU frequency. So, if the maximum for modern 6502 is 14MHz, then neither of the clock phases can be shorter than 35ns (half of 71ns which is 1sec/14.000.000).

    So, we need to generate special test fixture that will toggle clock selector in a way that ensures shorter than 35ns cycle. Then, we need to come up with a test that will catch these occurrences. And only then, when we prove we can see the test fail, we can go about finding a fix for the problem.

    Initial setup of the test fixture

    Let's start with the basics: we will need a clock, say 8MHz, that will generate the basic signal:

    Build it on breadboard:

    Measure to be sure:

    Sorry,...

    Read more »

  • The curious case of reset button

    Dawid Buchwald10/16/2020 at 10:43 2 comments

    Update on the DB6502 Proto Board

    So, I've been playing with my DB6502 Proto Board for some time now, polishing the supervisor software recently, and it's pretty neat as it is now. You can flash ROM, you can obviously read its contents as well. You can run the 6502 using onboard AVR as clock source with speed ranging between 300KHz (system bus captured, no breakpoints yet) and 800KHz (system bus capture disabled). You can single step over single cycle or single instruction, so basic disassembler is already in place. Some screenshots:

    The one above shows how onboard AVR is used to flash OS/1 system image to EEPROM.

    This one - dump EEPROM operation and entering monitor shell.

    You can single-step the cycles...

    And whole instructions.

    Finally, you can run fast to get enough performance to run OS/1 on the board:

    I have also implemented major redesign to OS/1 serial interface architecture, it's using replaceable (at compile time) serial driver modules, and I created one for my next-gen DUART controller, so it works with three different chips now.

    So yeah, I've been busy recently, and it all worked pretty fine, with one simple exception.

    Reset circuit explained

    So, there are two reset circuits on the board, and the same design will be used in the final version. There is primary master reset circuit connected to DS1813 chip that resets everything on the board (with the exception of the UART->USB interfaces, see below). However, I wanted to have another, secondary circuit, used to reset only 6502 and its peripherals. The reason to do so is that you might want to use your AVR supervisor session over several 6502 resets. You want to keep your breakpoints for instance.

    The solution is pretty simple: both reset signals are active-low, so the master reset is connected directly to DS1813 chip (that generates the signal on power-up and when reset button is pressed) and AVR and its peripherals. 6502, however, is connected to secondary circuit that is generated as an output of AND gate. The inputs are: master reset and signal originating from AVR.

    This way we have two ways of resetting the 6502: by the master switch/power-on, or by command from AVR shell.

    Now, this is pretty simple, right. Could anything possibly go wrong?

    Well, I wouldn't be writing about it, if there wasn't.

    The strange case of reset button

    So, most of the time it worked, I could reset the 6502 from AVR shell and it would just work. Sometimes, without any apparent reason I had to invoke the reset operation more than once for it to kick in. That was weird, especially that my code for sending the reset signal was following WDC datasheet that requires at least two full clock cycles. I had three.

    Still, sometimes what happened was this:

    As you can see, reset sequence was performed, but the CPU continued as if nothing happened. In those cases I just had to repeat it couple of times to kick in:

    I was ignoring the issue for a while, because it was just a small annoyance, but at certain point I decided to look closer at it. And what I found was eye-opening.

    First investigation attempt

    What do you do in cases like this? Get your logic analyser and see what it records. Here is what was captured using my cheap Saleae Logic 8 clone:

    A-ha! Three cycles, bus taken over (it's not really necessary though for reset operation), but RES line was not pulled low. I checked the terminal, and the puzzle got all the weirder:

    RES line was not pulled low, but the reset operation worked? WHAT THE HELL?

    Probably the cheap clone is crap. Weird, but whatever. Let's get the serious stuff: 16 channels, 200MHz. Proper gear.

    Second investigation attempt

    What ensued was so strange I actually forgot to take screenshot of it, so what you will see below is my own recreation of the observed result. This is what I saw at much higher frequency logic analyser:

    What got my attention here (but I wasn't able to replicate this afterwards),...

    Read more »

  • Yet another story about "insignificant" details

    Dawid Buchwald10/08/2020 at 18:51 5 comments

    Learning product development the hard way

    One of the least expected consequences of sharing is that people actually take what you shared and start using it. To make things worse, these people are different than you, have diverse backgrounds, experiences and competences; they also use your design in a ways you have not imagined.

    This, at least in my rather short experience, is the best part of the whole project. Every now and then I get messages from people all over the world who built DB6502 and ran into smaller or bigger issues while doing that. These issues let me see things from different perspective and are the best course in product design I could ever dream of.

    At the same time this is the hard way, as you have to think of all the possible issues as much in advance as you can; negligence or ignorance can get you in trouble and while everyone seems to agree that authors of open sourced projects should not be held responsible for any consequences of their usage, you still will feel that you should address most of the comments you get in one way or another. So, prepare for bumpy ride and enjoy every single moment of the experience!

    Think about target audience

    This is something we all should know - consider the background of the people who will follow your project, and make sure you don't assume certain level of expertise. And yes, while you can expect at least some of them to be similar to you (after all, all great minds work alike), you have to ask yourself if you provide enough details for users outside of your demographics, whatever they might be.

    One instance of such omission from my side was the unwritten assumption that most users of my project will have background in software development. After all, if you host your sources on GitHub and write documentation about compilation flags, you should expect anybody interested to be familiar with these things, right?

    Well, wrong actually. Your project might be also followed by people who have never used git, so it's common courtesy to describe how to use it for the purpose of your project. You never know who's on the other side!

    Key takeaway here: be careful with your assumptions, especially regarding your core competences. Remember how you got into electronics first and was upset about certain things never being explained clearly? This is exactly what happens to non-developers if you tell them to fetch the latest version of repo and switch to specific branch :)

    The curious case of blink LED

    One of the features I put on my DB6502 board was simple LED driven by remaining line on port B (other 7 lines are used to drive LCD screen). The schematic is as simple as it can possibly get:

    Few weeks ago I was contacted by one user, let's call him Adam, who started building DB6502 and while very competent in electrical engineering, he was struggling with the software development toolkit that I used for my software. He managed to use VASM to create simple ROMs to run on the board, but was unable to follow the instructions for building my code.

    I have to admit I put quite an effort to ensure that my software builds "out of the box" on each of the major operating systems (Windows/MacOS/Linux), but the documentation of the environment setup was lacking in that regard.

    So, I started exchanging e-mails with Adam, guiding him step by step of the process.

    To be fair - I have already done similar things in the past, improving my documentation with comments coming from other people, but it was first time that non-developer started working with my project. I expected this one to be pretty quick - five to ten e-mails maybe, simple suggestions and done. It turned out to be more complicated and it taught me a lot!

    After we got to the point where ROM images would compile nicely, it seemed as if it would take just a few more steps to get to working OS/1 image. Unfortunately, this was not that easy. When we got to setting up the serial connection,...

    Read more »

  • The Gods of Electrickery have not been kind recently...

    Dawid Buchwald10/02/2020 at 14:11 1 comment

    Current status

    Recently I promised to share the details of my rapid PCB prototyping exercise, and I wish I could do it being 100% certain about the results. Unfortunately, The Gods of Electrickery have not been kind to me recently, and I came across an issue that stopped me dead in my tracks.

    As I wrote recently, the worst part of any project is when there seemingly insignificant things happen. Something works when it shouldn't, or doesn't where it should. Normal reaction would have been to shrug, rewire, reset and move on. Unfortunately, as I have learned the hard way, this is not a proper reaction. You should really get to the bottom of the issue for two reasons mostly:

    1. Chances are that it will occur again in less favourable environment (like, you know, production, or on PCB),
    2. Even if it doesn't, the Grand Issue is that you are supposed to understand your circuit. All the magicky stuff happening now and then is just your incompetence at play, and it will haunt you one day.

    So, regardless of having at least three different solutions to the observed issue, I still don't know what happens and why these solutions work. To put it in proper context:

    This is how I feel right now :)

    Call for help

    So far my blog here was all about triumph of a mind over matter; spectacular success after another. That makes writing this post all that harder - I'm stumped and I really don't know how to proceed.

    Again, more than one reason to share. First and foremost, I really hope that some of you might have seen something similar and can suggest other ways to investigate (or to solve) the issue further. Help me understand what I'm missing here and how to approach cases like that. Teach me where I'm failing.

    But the other reason to share is that I would like to send a message to all the beginners like myself who come across similar roadblocks. This is normal, you can't let it discourage you. You can choose how to approach the situation (apply the first possible solution, keep digging, or just move on regardless), but don't let that situation let you down.

    And, even if you don't understand what's happening, there is plenty of investigation you can do on your own just using the opportunity to learn more about analysis and troubleshooting.

    So, please, if you have any idea what might be causing issue that I've been struggling with or what else could I check, please let me know in the comments below.

    The weird case of line wrapping

    So, soon after receiving my DB6502 prototyping PCB (described here and here) and sorting out initial open questions (like feeding bus control signals from AVR to 6502) I started testing how the integration with external I/O components works. Plugged in my 20x4 LCD screen and ran some basic program to test it. The expected outcome was to display text "Hello 4-bit LCD! Chars!". I use 6522 VIA chip to interface to LCD. This is the basic setup:

    Now, to shortly describe what is here: in the middle there is a PCB with the core components: ATmega644PA used as a supervisor - it feeds clock input to 6502, can take control of system bus and flash the ROM chip. You can use it to step through 6502 execution (cycle by cycle) while observing system bus activity; 6502 CPU (the CMOS variant from WDC), two 32KB RAM chips (one not being used), 32KB ROM, ATF22V10 PLD for address decoding and 74AC138 for I/O channel selection.

    Mandatory to run there are also several chips on the left side: 74HC595 shift register that AVR uses to control signals like RDY or BE for 6502, 74HC00 inverter for them and 74HC08 AND gate for RES signal routing (you can reset 6502 from AVR without resetting the latter). Pretty basic stuff.

    On the right side there is a single chip - 6522 VIA (also CMOS variant from WDC) used to drive the LCD in 4-bit mode. As you can see, each of the breadboard sections is fed power and GND connections from three breakout ports on each side of the PCB.

    Sorry, if all the above was a bit confusing,...

    Read more »

  • Tech quickie - USBAsp and fresh AVR chips

    Dawid Buchwald09/28/2020 at 16:12 0 comments

    Just a quickie

    There are some steps in my project that take a lot of time and effort to document, and I love writing about them. There are, however, small issues, problems, obstacles that don't require full-blown post to describe, and yet I want to share them because they weren't that easy to research online. I will call these tech quickies and document them in much shorter posts.

    Using ICSP for AVR chips

    Since my first version of 6502 computer, I loved the idea of being able to program AVR controllers directly on the board without the necessity to remove them. I was really proud of myself when, almost at the last minute, I added the port for it on my board, and it worked perfectly.

    For me, that is, because some people complained about it, and they were right. Depending on the programmer you use and the origin of the chip it might be trivial or not so much, so lesson learned here. Consider how it works with fresh chip, be mindful of default fuse settings and quirks of different programmers.

    Some time ago I built simple POV toy for my son (I mentioned it recently) and it is basically ATmega168P + some LEDs that blink very fast to make nice images when waving the thing in dark room. 

    Now, when I built it on protoboard, I plugged in one of fresh ATmega168 chips (purchased just for this project specifically), plugged in my USBAsp programmer and tried programming it:

    ➜  ~ avrdude -p m328p -c usbasp -P usb  -t
    
    avrdude: error: program enable: target doesn't answer. 1
    avrdude: initialization failed, rc=-1
             Double check connections and try again, or use -F to override
             this check.
    
    
    avrdude done.  Thank you.

    Please note: this is not the exact command I used (this comes from further investigation), the original session output got lost in the fight.

    I have seen this one before

    This reminded me that I have seen these errors before, and the way I solved them, after some head scratching, was basically to use Arduino Nano as ISP programmer. I remember doing some research online and just came to conclusion that I still don't know what it is, but using Arduino ISP and external crystal solved the problem.

    Since I wanted to complete the toy project this was exactly what I did again: fished out the chip, put it into the breadboard, programmed there with Arduino ISP that didn't seem to have any problems with the chip.

    It kept bothering me though. I hate to not be able to understand why something works or why it doesn't. I hate workarounds that don't address the underlying issue, they just obscure it so much that you forget what the actual problem was. And if you have ever ran into these issues with USBAsp, I bet you found these approaches:

    1. Replace your AVR, because it's bricked,
    2. Connect external crystal + 22pF caps,
    3. Add capacitor to reset pin,
    4. Remove capacitor from reset pin,
    5. Throw a handful of caps at various pins in different locations,
    6. Get yourself another programmer,
    7. Update USBAsp firmware and/or Windows driver (if using),
    8. Connect external power to your board, as USBAsp is not providing enough voltage/current.

    Now, these are nice advices, but none of them has anything to do with the problem. And, more often than not, these will not help at all.

    How to troubleshoot it then?

    Well, what I noticed is that once I got the first programming out of the way with Arduino ISP, the problem never occurred again, making it more difficult to investigate. As if there was some kind of magical formatting needed that the USBAsp wasn't capable of. I didn't like the explanation, especially because I wanted to start using SMD version of ATmega chips, and these you can't "fish out" of your board for breadboard programming. Somehow it never occurred to me that maybe I could use Arduino ISP with the onboard ICSP port. Well, brain is a funny thing :)

    When purchasing some other chips for my project recently, I decided to put an end to the whole debate in my head. Get handful of fresh AVR chips, replicate the problem and instead...

    Read more »

  • Rapid PCB prototyping - update (part 1)

    Dawid Buchwald09/24/2020 at 18:37 6 comments

    What is your excuse?

    This header title of this section was supposed to be separate post on its own. One of the first things that surprised me when I started working on DB6502 version 1 design was the general hesitation for SMT soldering among beginner EE community. I did feel a bit intimidated by it as well, but I couldn't find UART->USB converter chip in DIP package, so I settled for not-so-beginner-friendly FT230XS in TSSOP-16 package. Got myself couple of chips, several adapters and while waiting for the delivery started watching YouTube videos about the process.

    OK, it didn't seem trivial, but didn't seem that hard either. Then I came across this excellent post (which I, obviously, lost) where somebody proposed slightly different procedure. Since it seemed the most reasonable to me, I decided to give it a try.

    Then the chips arrived. Much smaller than I expected :) Not to worry, I got to work. My first attempt at TSSOP-16 was horrible, I almost burned the chip, adapter and my apartment.

    That being said, it actually turned out OK. After about an hour of experimenting with flux, wick, solder and different soldering tips it looked fine and worked as expected.

    That's not hard, I thought to myself, and started with a second chip. Took me only five minutes. Later got myself SMT practice board (they are cheap and contain various footprints) and spent some time with it as well.

    Recently, when playing around with the idea for DB6502 I wanted to try out some specific chips that, sadly, are not available in DIP package. I figured it would make nice post for my blog, where I would show the process. To get better light I moved to terrace on a sunny, exceptionally warm day. Long story short - I was sweating like a pig, cursing like a seaman, but hell-bent on making it happen. Took plenty of photos, soldered several chips. Moved inside to check out the pictures just to find out that most of them were utter shit. It was so bright I didn't notice they were out of focus... Here are some before and after:

    Oh, and out of the above, only one pin was not connected correctly. There were no bridges. All in under an hour.

    What's with the excuses then?

    Well, actually two things: for one, my crappy pictures aside, there is no excuse really to give up on SMT soldering. You should try it, and I will demonstrate the process I use below. Now, I understand that some people can't do it due to physical conditions, sometimes caused by age or other diseases, so if you suffer from them, don't take it personally. I'm addressing here the healthy majority, especially younger engineers - guys, man up, try this. It might turn out easier than you think.

    But I do have second takeaway from the story: as usual, I want to emphasise the importance of sharing with others. Working on a project? Share your stories. People will notice and they will give back. Recently I was contacted by another Hackaday user and he informed me that there are actually UART->USB adapter chips in DIP package. It's MCP2221A, and I will write more about it soon. Bottom line: what's your excuse to not share your work?

    Back to business, what about these PCB prototypes?

    Again, this post is not sponsored by PCBWay, but I just have to recommend their service. The whole process (order validation, manufacturing, shipping and delivery) took under a week. This is really fast, and it ties perfectly in the "rapid prototyping" flow.

    What about quality? Glad you asked:

    Lovely :)

    First things first: FT230XS soldering

    So, what's the secret procedure I use?

    First, soldering station: doesn't have to be something fancy. I use Zaoxhin 936DH with 1C Black tip. 340 degrees Celsius. Flux pen. Thinnest solder you can find - I use 0,56mm. That's it, really.

    Now about the process up close:

    This is clean PCB, nothing happened yet. Sorry for pictures quality, but these are really small, and pictures have been taken with my...

    Read more »

  • Rapid PCB prototyping and what can possibly go wrong?

    Dawid Buchwald09/18/2020 at 18:32 0 comments

    Breadboards - the worst of best inventions ever...

    When I first started contemplating getting into field of hobbyist electronics, it was the discovery of breadboards that sparked my interest. I understood that they are the magical devices that are perfect for all hackers and tinkerers alike. Devices from alien galaxy that allow you to build complex circuits that are pretty robust and yet completely modifiable over time. I loved the idea, but then I came across some book about beginner Arduino projects and couldn't understand pull-up resistor concept. It just didn't make a lot of sense, so I got into ceramics instead and spent couple of years on it.

    Then one day I stumbled across first Ben's video about 6502 and I decided to give electronics another try. Maybe it was because he made me understand what the bloody pull-up is, or maybe it was simple childhood nostalgia about my Atari 800XE with tape drive.

    One way or another, I started playing with breadboards. I really considered them the best invention ever! And they probably are, until, that is, you purchase Ben Eater's 6502 kit and try to wire CPU, ROM and RAM and Arduino Mega debugger on a single breadboard with AWG22 wire. And then fish out the ROM chip to program it and put back in while keeping all the connections intact.

    This was my trauma with breadboards, and I believe we all have our own horror stories. All these loose wires, ZIF sockets slipping out of place, shorts and forgotten connections between power rails.

    The thing is that there is no realistic alternative to breadboard, right? I knew I want to go full-on PCB one day and I spent literally months to design my very first board. It turned out nice, and it worked just fine to my honest surprise. OK, I might have made it faster, some of the time I spent perfecting it was because of COVID lockdown of my Chinese PCB manufacturer - lead times were like three or four weeks, so I figured I would rather spend this time checking my design over and over, improving it to perfection. Found couple of mistakes (mostly cosmetic, though), fixed all of them and one day the factory reopened.

    Still, it was very long process. The main take-away from the situation was that you never ever put on PCB something that hasn't been tested on the breadboard. And PCBs take forever to make.

    With that universal wisdom in mind, after couple of months I started toying with the idea of DB6502 v2.

    Enter nightmares...

    OK, so I had some basic stuff figured out. I knew I want AVR (specifically ATmega644PA) to act as 6502 debugger and ROM programmer. I knew I want to use ATF22V10 PLD for address decoding, two RAM chips and one ROM. I knew I wanted to use SC26C92 for dual channel UART interface. I wanted selectable clock frequency (great idea if you want to start with slow clock, copy slow ROM contents into fast RAM, disable ROM and increase clock frequency to much higher), and many, many other features. Problem is that my "universal wisdom" was to test it all on breadboard.

    I knew that was the right way to go, but man... Doing all that again?

    I did build the SC26C92 DUART interface on breadboard and connected it to version one of my 6502 PC. It worked, kind of, and I know what that means - there is some very nasty bug in my design, and I still need to find it.

    I did build the EEPROM programmer based on ATmega on breadboard, and it worked just fine. It was actually faster than the minipro software with TL866 II+.

    But still, to add CPU and RAM and all these other components? No, seriously, I just couldn't force myself to wire the 6502 address/data busses to additional AVR and extra RAM chip. I was looking at the picture, and I was like "nope". I just can't go down that rabbit hole once again...

    Alternate idea

    I recently played a bit with protoboards, or perfboards or whatever they are called. I made a simple POV toy for my kid, based on the awesome AVR programming book:

    This was fun to make! I was thinking...

    Read more »

  • Field testing PLD and how to test your test

    Dawid Buchwald09/18/2020 at 17:21 0 comments

    Putting it all together

    After having completed implementation of my PLD-based address decoder, I finally decided to try and program it. Obviously I expected issues, because these were supposed to be programmed by dedicated hardware. I read about many, many issues with chips available on the market, so I came prepared. Got myself decent cup of coffee, locked myself and told my family to not disturb me for another three to four hours.

    Grabbed my JED file, inserted ATF22V10 chip into my TL866 II+ and tried to guess proper minipro syntax:

    dawid.buchwald@PL-2LGX4M2 ~/Documents/Personal/Development/6502/WinCUPL
    $ ls -l
    total 48
    -rwx------+ 1 dawid.buchwald Domain Users 2777 Sep 10 15:40 DB6502.abs
    -rwx------+ 1 dawid.buchwald Domain Users 4196 Sep 10 15:40 DB6502.doc
    -rwx------+ 1 dawid.buchwald Domain Users 4261 Sep 10 15:40 DB6502.jed
    -rwx------+ 1 dawid.buchwald Domain Users 3605 Sep 10 15:40 DB6502.pdf
    -rwx------+ 1 dawid.buchwald Domain Users 2903 Sep 10 15:40 DB6502.PLD
    -rwx------+ 1 dawid.buchwald Domain Users 1732 Sep 10 15:40 DB6502.si
    -rwx------+ 1 dawid.buchwald Domain Users 1011 Sep 10 15:40 DB6502.sim
    -rwx------+ 1 dawid.buchwald Domain Users 5287 Sep 10 15:40 DB6502.so
    -rwx------+ 1 dawid.buchwald Domain Users 2343 Sep 10 15:40 DB6502.wo
    
    dawid.buchwald@PL-2LGX4M2 ~/Documents/Personal/Development/6502/WinCUPL
    $ minipro -p 'ATF22V10C' -w DB6502.jed
    Found TL866II+ 04.2.112 (0x270)
    Warning: Firmware is out of date.
      Expected  04.2.118 (0x276)
      Found     04.2.112 (0x270)
    
    VPP=12V
    Declared fuse checksum: 0x67A5 Calculated: 0x67A5 ... OK
    Declared file checksum: 0x910D Calculated: 0x910D ... OK
    JED file parsed OK
    
    Use -P to skip write protect
    
    Erasing... 0.33Sec OK
    Writing jedec file...  5.01Sec  OK
    Reading device...  0.41Sec  OK
    Writing lock bit... 0.35Sec OK
    Verification OK
    
    dawid.buchwald@PL-2LGX4M2 ~/Documents/Personal/Development/6502/WinCUPL
    $
    

    Aaaaand that was it. Can't say I was disappointed to see it work the first time, but maybe I was? You know, just a little. I guess no troubleshooting for me now. Or so I thought.

    Next step, obviously, was field testing the thing. The way I wanted to do this was to write simple Arduino program that would check all the possible combinations (64KB addresses accessed in 8 modes - CLK high/low, RW high/low, EXRAM high/low) and compare them against expected output.

    I already implemented something similar in the past, but this time it was a bit more complicated. More vectors to test and a bit more outputs to verify.

    The code I came up was along these lines:

    #define IN_CLK         0
    #define IN_RWB         1
    #define IN_EXRAM       2
    
    #define OUT_WEB        0
    #define OUT_OEB        1
    #define OUT_RAM1_CSB   2
    #define OUT_RAM2_CSB   3
    #define OUT_ROM_CSB    4
    #define OUT_IO_CS      5
    
    #define MODES_COUNT    3
    #define ADDR_COUNT     16
    #define OUTPUT_COUNT   6
    #define MAX_FAIL       1000
    
    const char MODES[]   = {53, 51, 49};
    const char ADDR[]    = {52, 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, 30, 28, 26, 24, 22};
    const char OUTPUTS[] = {47, 45, 43, 41, 39, 37};
    
    uint16_t BIT_MASK[ADDR_COUNT];
    
    bool ADDR_VAL[ADDR_COUNT];
    
    uint16_t currentAddress;
    uint8_t  currentMode;
    uint8_t  currentOutput;
    
    uint32_t passCount;
    uint32_t failCount;
    
    void setup() {
      setupPinModes();
      Serial.begin(57600);
      runTest();
      displayTestResult();
    }
    
    void setupPinModes() {
      uint8_t i;
      
      for (i=0; i<ADDR_COUNT; i++) {
        pinMode(ADDR[i], OUTPUT);
        digitalWrite(ADDR[i], LOW);
        ADDR_VAL[i]=false;
        BIT_MASK[i]=1 << i;
      }
    
      for (i=0; i<MODES_COUNT; i++) {
        pinMode(MODES[i], OUTPUT);
        digitalWrite(MODES[i], LOW);
      }
    
      for (i=0; i<OUTPUT_COUNT; i++) {
        pinMode(OUTPUTS[i], INPUT);
      }
    }
    
    void loop() {
    }
    

    This is basic init - setting Arduino pins to input/output, populating basic values (like bitmask)  and so on. Nothing fancy here.

    This is also pretty basic:

    void displayTestResult() {
      char output[128];
      Serial.println("Test results:");
      sprintf(output, " Scenarios passed: %lu", passCount);
      Serial.println(output);
      sprintf(output, " Scenarios failed: %lu", failCount);
      Serial.println(output);
     Serial.println(...
    Read more »

  • Address decoding... and how to get it right

    Dawid Buchwald09/10/2020 at 18:13 0 comments

    But it just works...

    What I find really amazing is how small, seemingly insignificant experiences can have enormous impact on us, how they can shape our path. For me one of those things was rather not-that-important article written by one of my professors, when I was still at the university. It was great piece called "The essay about Fibonacci Sequence", and the idea was pretty simple: to start with the simplest working algorithm to calculate n-th Fibonacci number, and improve the performance step by step.

    Some of the tricks were trivial, others less so, and in general, there was nothing groundbreaking about the method. As far as I recall, the optimal solution was to calculate n-th power of some matrix, but that doesn't matter really. What does, however, was that the person who wrote the article didn't focus simply on the result, but deliberately made all the silly mistakes along the way to illustrate how they compound to impressive performance drop.

    Following that path taught me one of the first important lessons in IT: it doesn't matter if it works. Everybody (or almost everybody) can make it work; the thing is to make it right, or at least try your best to do so.

    Address decoding for 6502

    One of the things I absolutely love about 6502 is how simple this CPU is: just a handful of registers, basic system bus and memory-mapped I/O. Everything is just an address, be that RAM, ROM or serial interface. This makes programming model very simple and easy to read. I would even argue that this architecture is best suited to teaching basics of programming. And yes, I do know how it sounds - using assembler to learn programming - but try to think about it for a moment. There are just several variables, no data types, no abstractions, memory management and such. Simple instructions, data fetched from uniform cells and saved the same way.

    Unfortunately, there is a downside to this simplicity. Most basic 6502 builds (like Ben Eater's BE6502 or my own DB6502 v1) use simple logic gates to map memory addresses to specific hardware devices (reads/writes at address 0x0100 go to RAM, while 0xFFFC usually to ROM). This model is usually sufficient for most of the applications, but there is some inefficiency there. Vanilla BE6502 wastes 16KB (25%) of available memory just to access single VIA chip. My own build wastes 8KB (12.5%) to provide access to several I/O devices (up to 10), so it's a bit better, but honestly - all you need is 16 bytes per device, so you should not waste more than 256 bytes (one page) for the whole I/O region.

    By the way, if the above is not perfectly clear, please let me know in the comments, I can explain it more, but truth be told - Ben's explanation in his video should be sufficient.

    Can it be done better?

    Sure thing. Anyone looking for better solution will sooner or later stumble across the invaluable 6502 primer. There is whole section about address decoding there. I strongly suggest you take a look, there are some nice ideas and important details to keep in mind (mostly - importance of propagation delay).

    You usually end up with two possible options: use 74xx logic gates (and quite a lot of them) to narrow down I/O memory range, or use PLD. The former is perfectly sufficient for plenty of applications (remember - many of the original computers from the 80s didn't even use the full 64KB range and they were powerful enough to run plenty of software), while the latter, while providing the best results (high performance and low memory range waste), might be intimidating for beginner user. There are some strange tools to be used with weird syntax and ancient interface. There must be a way to navigate those, right?

    How not to share knowledge

    I really admire all the people who spent countless hours trying to figure out all the weird stuff about 8-bit computers. They did amazing job, and the fact that they found the time to document all this is awesome. That being said, there are some things I...

    Read more »