Here is a project I've been working on over the past few weeks - a 6502 compatible single board computer with 128K of RAM, 128K of ROM and an IO expansion port. The reason I call it 'compatible' is because the role of the 6502 processor is being played by an emulator running on a 8 pin LPC810 ARM Cortex-M0+ processor. The emulated processor supports all the official 6502 instructions (the undocumented instructions are treated as NOPs) and it is not a cycle accurate emulation. The entire emulator fits in the 4K flash on the LPC810.
The project is not yet complete, at this stage it is capable of running EhBASIC from the on-board EEPROM chip but the code to provide access to the front panel IO and the expansion slots is not yet implemented. I am also in the process of redesigning the main PCB to simplify it - this redesign will remove one of the IO slots and replace the 16 bit IO expander with it's 8 bit little brother.
You can find the full source code and hardware design in this GitHub repository if you would like to play around with it for yourself. I would appreciate any feedback on the design and firmware as well. I used DesignSpark PCB for the schematic design and PCB layout, to make it easier I've also made the design available in PDF and gerber format in the hardware/RevA/mfr directory of the repository. The firmware is available as an LPCXpresso project. Both of these are free tools so it should be relatively easy to hack away at the project.
I've always wanted to build my own single board 8 bit computer, I have a bunch of older 8 bit CPUs such as the 6809 and Z80 in my parts collection that I acquired just for that purpose. Unfortunately it seems to be a project that I never get time for. I have toyed with the idea of building an emulated system on a more modern microcontroller as well but it was this post on the MOS6502 Google+ community that finally triggered me into action.
That post linked to this entry on StackExchange that had the C source for a compact 6502 emulator core. At the time I was considering the LPC810 for another project and I started wondering if I could fit the emulator into the 4K flash on the chip. A few experiments and a simple breadboard prototype soon followed and the project was born.
All the heavy lifting is done by the LPC810 of course but, with only 1K of RAM available on the chip, I needed the ability to access external memory chips to have a system that was at least marginally useful. I also wanted the ability to expand the system at a later date with relative ease so that meant some sort of IO expansion that could be exposed to the emulated processor.
The LPC810 only has 6 IO pins, two of those are needed for the serial interface which leave just 4 to implement all of the above. The best solution turned out to be using external components on a SPI bus to get the additional functionality. The final system has an SPI IO expander, a 1Mbit (128K x 8) SRAM and a 1Mbit (128K x 8) EEPROM. There is a quad 2 input NAND gate in the circuit as well to help with the SPI slave selection logic. You can see how it all fits together on the schematic in the GitHub repository, I will put up a more detailed post about the hardware in the next day or so.
The board design that is currently in the repository is my RevA board - it uses a 16 bit IO expander (a Microchip MCP23S17) and has two SPI based expansion slots. This is one of the first boards I've made using CNC milling and the quality isn't as good as I had hoped. The board layout was also less than optimal, very long traces for the SPI bus which introduced errors at higher speeds and far too many jumper wires for my liking. As I have to remake the board anyway with better settings for the CNC machine I am taking the opportunity to simplify the design a bit and cut back on some of the more optimistic goals. The RevB board (which will be pushed to the repository in the next few days) drops one of the expansion slots and replaces the 16 bit IO expander with an 8 bit version (a Microchip MCP23S08). This should help make the board a bit more compact and help reduce the size of the firmware a little bit as well.
The emulated environment is a straight forward emulator based on the C code from this StackExchange post which I have heavily modified to minimise the final code size. I managed to shrink it from 6198 bytes to 2468 bytes by removing some features (undocumented instruction support and cycle counting) and making structural changes to the code such as manually in-lining functions and removing some large look-up tables. The result still correctly emulates a 6502 (enough to run EhBASIC at least) but makes no attempt at cycle accurate emulation.
System memory is made available to the emulator as 8 pages of 8Kb each selected through a memory mapped page table. Each memory access uses this table to convert the processors 16 bit address into a 21 bit 'physical' address before performing the memory access. This gives a physical memory range of 2Mb - I have arranged it so that the RAM chip is found at the bottom of memory and ROM starts at the 1Mb boundary so I can use the most significant bit of the address to determine which chip I should be talking to.
Access to the 'real' hardware is provided to the emulator through a memory mapped IO block just below the interrupt vector address at $FF00, this block is always available at that processor address regardless of the active page mapping. As I mentioned the memory page map is accessible there as well as a few extra bits:
- Interrupt source selection for the NMI and IRQ lines. These can be triggered by an internal timer (every 1/4 second), input on the serial port or a pin on the IO expansion slot.
- Control of the front panel hardware (2 LEDs and a push button).
- A very simple interface to the SPI bus so you can control an SPI device in the expansion slot. This allows transfer of up to 128 bytes at a time over SPI (not enough for an SD card but plenty for a LCD display).
- A 'seconds since boot' value that is automatically incremented every second.
A 'KIPS' (Kilo-instructions per second) value that gives you an idea how fast the system is running. This is updated every quarter second.
I really wanted to make the system as useful as possible, not just a proof of concept. With the amount of memory available and some access to external hardware I think I have achieved that goal. I am writing a more detailed post on the emulation environment with examples on how to use the hardware interfaces.
A retro computer emulator deserves a suitably retro case as well, I had the front panel design in mind from the moment I started implementing the project - I think it conveys the late 70's perfectly. The panel is milled out of a piece of laminated flooring with all engraved text using the Motter Tektura font (as used by Apple, Reebok and others in the 80's) - the combination of the font and the fake plastic wood is exactly what I was aiming for.
I was originally going to build a fully enclosed case but my 3D printer is out of action at the moment so I had to mill MDF to build it. I haven't done much work with MDF on a CNC machine before and wasn't sure how well it would work so I kept the design simple to start with - just a base plate and two side panels. It turned out better than I expected, the case looked like something that would be shown at the Homebrew Computer Club and the open design made it a lot easier to debug the hardware while it was assembled so I stuck with it rather than building a fully enclosed version. When my printer is up and running again I will just make a PCB mounting frame to attach to the base plate so it doesn't slide around.
The casing isn't mandatory of course - all of the external connections (power switch and LED, front panel button and LEDs, etc) are exposed through pin headers on the main PCB so you can use whatever components you like.
This has been a fun project to do and the result so far is quite usable (even if it is a little slow). The two large changes I would like to make would be to increase the speed a bit and to have some form of persistent storage available. Increasing the speed mainly revolves around the SPI interface to the memory chips which is the real bottleneck for performance, support for persistent storage could be provided with an IO expansion board (something I already have some ideas on how to implement).
The design is not limited to emulating a 6502 either, I have tried to keep the emulator core and the hardware emulation functionality as separate as possible with a well defined interface between the two. You could replace the 6502 core with something different and build a single board computer for your favourite microprocessor. The only limitation is that it has to fit in the 4K of flash available - a 6809 might be possible but the Z80 might be a bit too complex (which is unfortunate, I would love to run Fuzix on the hardware). As I mentioned earlier - the full code is up on GitHub and I would welcome any alternative processor cores if someone has a mind to write one.
This post is the first in a series of three that will appear over the next week or so - future posts will cover details of the hardware design and provide more information about the emulated environment. I will be posting updates on Google+ as well.