My new computer is coming together nicely, at least in my mind and in some rough plans. Here is a list of what I hope will be the main hardware features:
- 6809 based (naturally)
- 512KB of Static RAM
- 32KB of EEPROM
- MMU (4KB pages)
- DMAC (2 channel)
- IDE host controller
- PCM sound output
- Four UART channels (3 useable)
- C64 keyboard controlled by an MCU (attached to UART channel)
- V9958 video interface (RGB and composite)
- SPI controller (including headers)
- RTC (attached to SPI)
- Centronics Parallel port
- Joystick port
- Internal GPIO headers via 6522
- General purpose expansion headers
This is obviously very ambitious. Especially around the idea that this will be a self-contained computer, not just a PCB that sits on the desk. There are loads of things that can go wrong. But I’m quietly confident I can get most of it done. My biggest concern is with the size of the PCB and achieving a decent layout. And also the cost of the main PCB, which is likely to be anything upto £200. The second concern is with my VHDL skills. I suspect I will be challenged, especially by the IDE controller. But you don’t learn unless it is difficult, so that is alright.
The computer has a name: the MAXI09.
I’ll now discuss each of the two FPGAs. Of course I will be using the EPF10K10 in PLCC84, FLEX10Ks (PDF). Each one has 59 useable IO pins. And I’ll need every single pin on both of them.
MuDdy - MMU and DMAC
MuDdy is a combined MMU and DMAC. It generates chip selects for all memory and peripheral ICs. It also generates the global \READ and \WRITE signals, which are gaited from R\/W and the E clock. Finally, it generates the RESET signal, which is (annoyingly) required by the UART.
- 8 data bus (D7-D0)
- 12 page address (A11-A0)
- 4 virtual address (VA3-VA0)
- 8 physical address (PA7-PA0)
- 2 clocks (E, Q)
- 2 resets (\RESET, RESET)
- 3 readwrite (R/\W, \READ, \WRITE)
- 1 halt (\HALT)
- 2 bus activity (BA, BS)
- 1 interrupt (\INT)
- 14 chip selects (various)
The purpose of a MMU, for my 8 bit computer at least, is twofold. First of all it allows a multitasking environment (I am reluctant to say Operating System) to prevent different tasks from seeing each others memory. This is fundamentally why modern Operating Systems present a reliable experience to the user; crashing tasks cannot generally destroy the system as a whole. Secondly, it will allow my computer to utilise more then 64KB of RAM, in a similar, but more effective, way to the banking used previously.
The system will use 4KB pages, for 12 bits of addressing within a page. Since the MPU has 16 bits of address, this means the top 4 bits will be used to map a virtual (MPU) page to a physical (Memory, IO) page.
The system will have 512KB of RAM and 32KB of EEPROM. This means (at least) 20 bits of physical address will be required. 20 bits is useful, since it means 20 bits less the 12 bits for the within the page address yields 8 bits for the physical page number. ie. there will be 256 4KB pages.
16 registers will hold the physical addresses which the 4 bits of virtual address are mapped to. There is only the active internal mapping held in the MMU. On a context switch, the 16 registers will be updated to hold the new context's mappings. This could be done by DMA (see below).
FUTURE: It might be useful to hold the address of the various tasks' mapping tables in registers. That way the MMU itself could switch mapping with a single register write, which would trigger a DMA action to fetch the tables. The alternative would be to hold all the tasks mappings in registers, and again a task switch could be achieved with a single write. In any case, such optimisations will be done later.
When the CPU address bus is valid (determined from the clocks), the 4 PA bits will be decoded to find out which of the 16 registers should be used to generate the 8 bits of physical address. External address decoding (ie. the generation of peripheral chip selects) will be via a combination of physical address and page address:
- 0x00 to 0x7f - RAM (128 x 4KB = 512KB)
- 0xf8 to 0xff - EEPROM (8 x 4KB = 32KB)
- (others) - IO
Within the IO page, the 12 bits of page address will be split so 4 bits are used for the peripheral IC, leaving 8 bits for register selects. This provides room for 16 peripheral ICs on the board, which should be ample. Note that peripheral 0x0 will be the MuDdy device itself.
FUTURE: Write protecting a page is also trivial to do via this mechanism. An extra byte per page could be used to hold settings, such as write protected. Since the 6809 has a synchronous bus, it is not possible to have a faulting mechanism, though basic things like status bits that indicates a page has been written to, read etc, could have some utility.
The purpose of a DMA Controller is to allow data transfer to happen within the computer without utilising the MPU. This is useful any time block transfers are required, for example:
- Reading and writing disk blocks
- Reading and writing data blocks to the serial port (eg. XMODEM)
- Writing to a sound device
- General memory copying or initialising
FUTURE: It may be more practical to make both channels the same, and achieve bursting transfers by setting the rate to 0, or similar.
For each channel the following registers will be needed:
- Source address (20 bits)
- Destination address (20 bits)
- Flags (8 bits)
- Length (16 bits)
- Increment source
- Increment destination
- Clear destination
- Negate source
- Generate interrupt at transfer end
- Active transfer
FUTURE: Some DMACs can do transfers backwards, ie. decrementing the source and/or destination. This does not seem to be very useful to me, though it would be trivial to implement.
Interrupt generation will allow the next transfer to be initiated inside an interrupt handler, etc. The transfer will initiate when this register is written to, assuming the active transfer bit is set.
The slow channel has an additional register:
- Transfer period (16 bits)
Implementation of the DMA transfer will follow the very rough prototype created with the XC95108. When a transfer is initiated \HALT is asserted. The MPU will then cease operation, but not immediately. A few cycles later BA and BS will be set to high, indicating the busses are tristate. At this point the DMAC can claim the bus and perform the transfer. At the end of the transfer the \HALT line will be returned to the inactive state.
Actually determining if a transfer should take place will involve examining both channels and first determining if the slow channel has a byte to transfer. This will be done by decrementing the rate counter and if it is zero setting up a transfer. Otherwise, if the bursting channel is marked as active, that channel will be made active. I must admit the details around this area a little lacking at the moment.
DISCo - Disk, Interrupt and Sound Controller
DISCo is responsible for 3 things - the IDE interface, interrupt routing and PCM sound output.
- 8 databus (D7-D0)
- 6 register selects (A5-A0)
- 2 readwrite (\READ, \WRITE)
- 1 chip select (\CS)
- 16 ide data (IDED15-IDED0)
- 3 ide address (IDEA2-IDEA0)
- 2 ide readwrite (\IDEREAD, \IDEWRITE)
- 1 ide chip select (\IDECS)
- 1 reset (\RESET)
- 2 cpu interrupt pins (\IRQ, \FIRQ)
- 8 digital sound (SOUND7-SOUND0)
- 1 clock (E)
- 8 interrupt sources (various)
The bulk of DISCo will be concerned with interfacing to the IDE drive in the system. Unlike in the previous IDE interface, the one in this computer will be “intelligent”. The data and address busses on the IDE drive will not be attached to the MPU directly; instead they will be connected to DIsCo. The host MPU will issue commands to DISCo, which will then communicate with the IDE device. Part of the motivation for this functionality is so that the details of the 16 bit data connection can be hidden. As far as the MPU (and more importantly the DMA Controller) is concerned, the IDE will present a 8 bit data path. Thus the DMA Controller will be able to DMA blocks from the disk transparently, without caring about the fact that the IDE presents data 16 bits wide.
Again, this functionality is not yet very well defined. I do not want to duplicate the disk controller logic in the FPGA. But at the same time it would be nice to hide some disk-level details from the MPU code, implementing only the parts of the IDE specification as I need. In summary, if I was only to be concerned with the 16 bit to 8 bit problem (presenting the 16 bit transfers at the same 8 bit IO port) then I could probably simplify this interface quite a bit and pass IDEA2-IDEA0 through from the MPU as I did in my previous CPLD-based computer. But this does not seem like an interesting solution.
This is essentially the same functionality as implanted in the CPLD. The following registers will be required:
- IRQ mask
- FIRQ mask
- Interrupt status
PCM sound output
In its initial implementation, this will simply be an output latch connected to an external 8 bit DAC. This will allow me to experiment with PCM sound output. Since this will be drivable from the DMAC, it will be possible to generate sound output from memory containing PCM sound data without the MPU doing all the work. It might even be possible to DMA disk blocks directly into the sound output.
FUTURE: Digital sound synthesis is something I’m also interested in looking into. It might be possible to generate sound waveforms in the FPGA itself, instead of reading them from memory.
In my next post I will present a proper block diagram, as well as (hopefully) the first draft of the schematic. I'll also touch on some of my plans for the system software…