This blog post is concerned with planning and, unlike pretty much all my posts to date, is not concerned with things I’ve actually done.
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
All of this will be laid out on a 4 layer PCB, with the entire computer put in a case (some day) with the keyboard. The expansion headers will be organised so I can either use them to attach to breadboards, or attach daughterboards.
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.
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
Because ROM needs to always be mapped to virtual address 0xfff0-0xffff, for the interrupt and reset vectors, virtual page 0xf will be special-cased in the mapping to map to physical page 0xff, the top 4KB of EEPROM. Critical OS routines to perform remappings will also be held in this page.
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
The DMA Controller will allow for the transfer of chunks up to 64KB in length. The source and destination addresses will be arbitrary, allowing memory to memory, IO to memory and memory to IO transfers. The DMA Controller will operate by mastering the CPU busses by asserting HALT. There will be two channels: a bursting channel in which the CPU is halted for the duration of the transfer and a “slow” channel where the transfer happens at a particular rate set by a period counter. The purpose of the rate limited transfer is principally to support driving the audio output in DISCo. Because audio transfers should not be paused while transferring data with the bursting channel, the slow channel will take priority over the bursting channel.
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)
Both addresses are physical addresses. The flags byte will be used to hold transfer properties:
- Increment source
- Increment destination
- Clear destination
- Negate source
- Generate interrupt at transfer end
- Active transfer
Optional incrementing makes the DMAC useful for IO port transfers. As well as source to destination transfers, it will also be possible to zero the destination. This will make it possible to zero memory extremely rapidly, since no read will be involved. It doesn’t have much utility, but it will also be possible to negate the source before it is written to the destination.
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)
A 16 bit counter, with a 2Mhz clock, will allow transfers rated down to about 30 bytes a second. A 8KHz audio transfer will yield a byte transfer every 250 clock ticks, which should allow a useful amount of MPU work to be done whilst playing audio data.
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
To save a couple of pins, NMI at the MPU will simply be connected to a button, making it not possible to mask this out at the interrupt controller. Two pins is a large price to pay for the fairly useless ability to mask this interrupt.
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…