68008 boardPeople may wonder why a 68000 board is still making sense today, and they would be right. For small projects, it is easier to use a microcontroller (8, 16 or 32 bits), and for larger projects, it is easy to find either pre-built boards or use off-the-shelves components, or “system on a chip”. Microcontrollers don’t require an operating system, and boards with ARM or PPC embedded CPUs come pre-loaded with some sort of linux kernel, and often u-boot as bootloader.
The idea here is different : the goal of this project is to make it a learning experience (in my case, for my son). Starting from a cpu, adding memory, some simple address decoding, some I/O capability, and finally a monitor to ease software development.
There are hundreds of CPU available on the market, from very old ones to the most recent chips. Old 8-bits CPUs (such as the Z80, 6502,etc...) don’t offer a rich assembler. Modern ones are RISC-based, have many registers and not always a easy-to-learn assembler. The 68000 family is located between these 2 extremes : it has a very nice set of instructions, 16 32-bits registers, and enough addressing schemes to learn how assembly code works. Furthermore, I was lucky to find several 68008 chips on ebay. (Later, I found some sources for this chip, so anybody who wants to reproduce the board will be able to find this CPU too, and cheap ($10/piece)). While being a full 68k CPU, the bus is only 8-bits. So yes, it is twice slower than a 68000, but our goal here is not speed, otherwise we would have used a modern cpu running at several hundreds megahertz!
People may now say : “Great, but you can do that with emulators...” (easy68k comes to mind here). The answer is “Yes, of course”, but from the learning perspective, one would miss all the little hardware details that makes a CPU board work ! It is not something that we can consider as a given... the board has required tweaks, many code changes, and provided great fun while debugging !
SpecsWith this in mind, the goal is to provide a decent-enough environment to enjoy writing assembly code. For this, the board has :
- 512kB of RAM (static)
- 256kB of ROM (actually flash)
- LCD display
- RS-232 port
- various options (such as a real-time clock, LEDs, etc...)
Address decoding strategyThe 68008 (48-pins version) offers 20 address bits, so the addressable space is 1MB. The space is divided as follow :
- 0x00000 - 0x7FFFF : 512kB RAM
- 0x80000 - 0xBFFFF : 256kB FLASH
- 0xC0000 - 0xDFFFF : 128kB for peripherals, DTACK autogenerated
- 0xE0000 - 0xEFFFF : 64k for peripherals, DTACK generated by peripheral
- 0xF0000 - 0xFFFFF : 64k for synchronous peripherals (6800 compatible)
The 68008 is running at 8MHz. At that speed, a bus cycle is 125ns. With today’s components, it is easy to find static RAM and FLASH that runs faster than this. In other words, we don’t need a logic to generate DTACK with some delay, to accomodate slower devices (such as old EPROM). This, of course, simplifies our board. We also don’t need to mess with dynamic RAMs, when one can find 512kB static RAM for less than $10. So, when RAM, FLASH or the 128kB space for peripherals is selected, our GAL will simultaneously assert DTACK.
Typical older 68000-based boards use an ACIA chip, or a DUART, and some sort of PIO to provide I/O ports and serial interface(s). These chips are obsoleted today, and much harder to find than the CPU itself. Here, we propose to use a PIC18F (we chose the PIC18F452), which will act as a generic I/O interface. This has several advantages : one chip does the job of several others (UART, SPI, several timers, analog input, I/O,...), it’s easy to find, it’s cheap... and furthermore, it helps to understand how the 68000 bus, because this interface has to be programmed in the PIC.
Finally, the 68000 and 68008 have a synchronous interface, which was designed to allow these “new” CPUs to work with older 6800-compatible interface chips. This capability is interesting for us because it almost provide a free LCD interface to the well known “hitachi-compatible” LCD modules. (Almost free, because the 48-pins version of the 68008 requires an external 74LS73)
It is very easy to extend the board, by using decoders. The GAL provides select signals for each of the main blocks described above. By decoding some lower address lines, one can easily split a block into multiple chunks. In fact, the board uses a 74LS139 decoder to subdivide the 128kB peripheral space into 3x32kB and 4x8kB chunks. One of the 8kB chunk is used by a timekeeper chip (M48T59Y), in order to provide a real-time clock and 8kB of NVRAM.
ResetThe 68008 requires a long reset pulse, which is generated by the PIC (in order to avoid using a 555 or a reset controller). Afterwards, the 68008 fetches 2 words (8 bytes) from addres 0x00000. If we place the ROM at address 0x00, there is no problem to provide the initial stack pointer and reset vector, but then we lose the ability to modify all exception vectors. So, we want the RAM at address 0x0000 at all time, except during the first 8 fetches. The solution is to use an extra input pin in the GAL (named ‘BOOTED’). This signal comes from a flip-flop, which is reset by the same reset signal going to the 68008. This flip-flop has its clock input connected to a DEV0_x signal, so that when this device is accessed for the first time, the BOOTED flip-flop will be set to ‘1’ (its D entry is tied to VCC), and the GAL will no more map ROM at address 0x00000, but RAM.
There was a minor problem left : the flash that we use (an old scavenged chip from a PC motherboard (it was the bios flash!)) has several sectors, the first one being pretty big (128kB). That means that if someone erases this sector, the board is dead, since the first 8 bytes should be protected somehow. This could be solved in software (the sector erase routine could restore the first 8 bytes automatically), but we chose an alternative approach : another signal, controlled by the PIC this time, is also going to the GAL. This signal (named ‘BOOTSEL’) allows to select which device is mapped at address 0x00000 while BOOTED is 0. It’s either the FLASH (default case) or the PIC itself ! This is how it works : when the PIC is reset, the BOOTSEL signal is an input. It has a pullup resistor, and a button to ground. If the user presses the button, the pic firmware will wait until the button is released before making BOOTSEL an output, and set it high. If, at reset, the button is not pressed, BOOTSEL is directly made an output, and set low. If BOOTSEL is high, the PIC jumps into a routine which waits for the 68008 to fetch its 8 bytes. These 8 bytes are stored in the PIC EEPROM, so they can be changed by software running on the 68008 ! With this solution, we have a board that boots automatically from flash, but if the user pressed a button at poweron, it boots from an alternate address (the monitor code, for example).