Booting computers is an age old problem. It seems like an easy task to you, just press the button, but the software and hardware involved is often a bit of a hack. When you start a Z80 processor (ignoring reset hold times and clock stability for the moment) it will try to load an instruction from memory address 0, execute it then move on. So the traditional way Z80 micro computers (like the Sinclair ZX Spectrum and the Amstrad NC100, to name a couple I own) are built is with a ROM chip at the bottom of the address space with some kind of operating system on it, e.g. a BASIC interpreter. This is cheap and simple, but has some big problems for the hobbyist or developer.
Problem 1: Reprogramming the system If you have a nice command interpreter/OS tested and ready to load programs from some mass storage and run them then you've got no problems, program once and forget about it. If you've just invented an exciting (to you at least) new hardware platform and have no code to run on it yet, you're going to need to program it a few times until it works. The old fashioned way of dealing with this was to use a UV erasable EPROM, this meant when you wanted to reprogram it you had to put it in an eraser box with a UV light for half an hour and then program it again. Now, you have the option of an EEPROM of some sort that skips this lengthy step, but it's still a physical wear on the parts to remove the chip and re-program it. If you're really rich you could get a zero-insertion-force (ZIF) socket.
Problem 2: Limited memory space The Z80 has a 16bit address bus so only 64KB physical address space. Take out of this the amount of space for your ROM and you've got even less room to work with! Why would you want a load of graphics routines in memory if you're only using text, or a bitmap font if you're only drawing images? You could, of course, have your ROM movable by writing to a register to have it moved out of the address space, but this is complicated, and the smaller the ROM the more address decode logic you need to select it properly. These days RAM is cheap, 64KB of SRAM is only a few pounds, so you don't even need to worry about the refresh signal and keeping the RAM up to date. So using RAM for the whole address space is appealing but how do you get code into it to boot the system?
The Solution: A PIC and an SD card
I've been looking at this problem since I stopped working on the first version of my Z80 homebrew system. A few months ago I came to the realisation that the PIC I was planning on using to interface an SD card to the system was under-utilised. SD cards are huge in storage and very cheap, plus you can interface to them via SPI which is easy to do. I'd built a file browser that ran on a PIC before that could cope with multiple partitions and FAT types, so knew that was well within the capabilities of a PIC to do. So the plan was to just use the PIC as an easy way to interface the storage to the Z80. The space requirement and cost of a PIC microcontroller is much lower than what would be needed for a 74xx logic solution, even if a parallel standard like IDE was used instead of SPI.
I had also experimented with connecting PICs to Z80 busses before for debugging and programming the "ROM" chip in-system. I realised though, that a bootloader for the Z80 designed to get it to load a program from the SD card, would be quite small and simple (a few KB at most). I also noted that the PIC I was using had some spare pins and a 32KB flash memory. So I came up with the following plan:
- PIC holds Z80 in reset
- PIC loads the boot image into RAM from it's internal FLASH memory
- PIC releases the bus and then lets the Z80 start
- Z80 starts requesting bytes from the SD card, possibly invoking a DMA transfer, as the PIC can control the system bus.
- The Z80 then runs whatever program it is that was stored on the card.
This means that all you have to do to try a new operating system is update the appropriate file on the SD card and plug it in. It also has the potential to perform task switching and state-saving to disk with DMA transfers by the PIC speeding up disk access. More than this it saves on a whole heap of logic for address decoding and a memory chip.
In my latest version I've also used the PIC to provide the clock for the Z80 using one of its internal counters, saving on more chips.
Of course, you could have done all this and more with a suitable CPLD or FPGA, but I've avoided that for two reasons; PICs are easier to use in stripboard built systems and it's easier to integrate a PIC into a 5V system as most of the FPGA chips around are 3.3V or lower. I also find programming PICs a lot easier than FPGAs. Of course an Atmel chip or another competitor microcontroller would probably do the job fine. I just tend to use PICs because that's what I'm familiar with.