Firmware & software

Ok, the hardware was no biggie, but the software was a bit more of a problem. I needed a Z80 or 8080 emulator which could fit into the ATMega88. The AVR series does support C using GCC, so my first try was to get an open-source z80 emulation core and feed it into avr-gcc. The resulting binary ended up occupying 48K, and that was only the emulator core. That was never going to fit, so I had to move to assembly.

Ofcourse, I wasn't the only one with the idea to write a Z80 emulator in assembly. The project to put a Z80 in a Propeller was the most interesting: while the propeller is much more powerful than an AVR, the amount of program memory a cog can directly address is less than the AVR can. While the code of that project wasn't of any use to me, the way they structured their emulator was of use: divide each instruction into a load, process and store action and put references to these functions into a huge lookup-table. if you download the sources, you can see that my emulator is structured exactly like that, and it ends up using a bit more than 2K of program memory. That's 12 times less than the C solution!

The Z80 emulator (well, actually, 8080 emulator because none of the Z80-specific instructions are implemented yet...) is the largest piece of the puzzle, but not the only one. The machine also needs I/O, memory and disk interfaces.

The I/O-interface was the easiest: just initialize the UART at 38400/n81 and create a pair of Z80 ports that read or write from that. Memory was not too difficult too: while I took the DRAM chip from the garbage box, it had a nice datasheet available on the Internet and I just took over the examples from there. The RAM needs to be refreshed too, or else it goes blank after a while: I used an AVR timer for that.

The MMC/SD-card was another story. First of all, talking to an SD-card isn't that hard, but you need to know what you're doing. Luckily, I still had some assembly code to read sectors lying around; I could just copy/paste that. Then there was problem 2: the sectors on a SD-card are 512 bytes, but CP/M expects a storage media which has 128 byte sectors... I decided on implementing this in the most ugly way possible: for example writing a sector means reading the 512 bytes from SD-card, changing the 128 bytes requested (which are obtained via emulated DMA from the DRAM chip) and writing the 512 bytes back. This means that the SD-card will erase and re-write its flash 4 times as much as normally... hope the wear-leveling it does is good. Still, it's longevity is probably longer than the floppies CP/M used to work from.

CP/M needs a few things to work with the hardware it's running on. First of all, it needs to be loaded. For that purpose, the emulator will load the first sector of the SD-card to the DRAM before starting the emulation. This is the same as what the original hardware CP/M ran on used to do. The first sector contains an Initial Program Loader, aka IPL, which then loads the rest of the OS. Secondly, CP/M requires a BIOS, which is a small bit of code that the CP/M core can call on to do hardware-specific stuff, like reading or writing a sector and inputting and outputting characters. Both things weren't too hard to write: my Z80 assembly still is relatively fluent and being able to control the 'hardware' too is a big help. One of the more interesting things I encountered on the way is that to implement the BIOS, you need to follow a book called the 'CP/M System Alteration Manual'. The copy I used was written in 1979, which means I was implementing specifications thought up 2 years before I was even born!

« Prev 3 Next »

© 2006-2022 Sprite_tm - Contact