To build a simple computer.
We could design one completely from scratch but that would be a considerable effort. We would also need to write a lot of software - and we do not have the time to write a BASIC interpreter, games, and documentation.
Instead, one could produce a clone of an 'antique' micro from the early eighties: the ZX81. This was used an Uncommited Logic Array (ULA) to replace the many discrete TTL chips of its predecessor (the ZX80) and add some extra features. The ULA was a silicon chip containing many unconnected logic gates, and the chip was customised by a single final layer of metal connections. This was cheaper than full custom chips.
The ZX80 and ZX81 were designed to be as cheap as possible to reach a mass market. Conventional computers used seperate video display controller chips such as the 6845 and 6847. The 6845 required an external font ROM and pixel shift registers. However, the main task of these controllers was to generate a regular sequential accesses to video data. A CPU running NOP codes also makes regular sequential accesses to memory. It is possible to trick the CPU into running the display data, by presenting it with NOP codes when it does so. This is what the ZX80 and ZX81 did, cutting the cost of conventional video circuitry.
Another trick was to use the system ROM as the font ROM. This is okay because the CPU does not need the ROM when it is 'executing' the display data.
The down side of all this is that the CPU cannot produce a display and run useful code at the same time. The ZX80 simply didn't bother to produce the display when it had something else to do such as interpret a keypress. This was tolerable for programs that simply had to go and compute something then display it.
The ZX81 added the refinement of a continuous display by having a non-maskable-interrupt generator to periodially force the CPU to generate a frame of video data. This took about 75% of the CPU time, so programs ran four times slower. The user could select either mode using the FAST and SLOW commands.
Since the ZX81 ULA is no longer made, nostalgic engineers have made 'reproduction antique' copies using TTL chips, several simple PLDs, or one FPGA. Of course, we have no desire to repeat work if someone else has already done it, and this project is based on a design by Bodo Wenzel and modified by Kai Fischer, both of the German ZX81 team.
Bodo's original design used a CPLD in a 44-pin PLCC as an almost drop-in replacement for the original ULA. This is a clever design in itself. However, the limited number of I/O pins on the original ULA meant the ZX81 placed series resistors in many signal paths so either end could be driven instead of using proper multiplexers. Using a chip with more I/O pins would be a better design, and the resistors would not be needed.
Bodo's second design uses an XC3042 in an 84-pin PLCC. This is also crammed full of logic, and demonstrates the engineering skill of getting the most performance value from the minimum component cost. Components evolve towards bigger better chips and Xilinx are no exception. The XC3000 and XC4000 series chips are fairly old technology (as of 2001) and have been superceded by the Spartan and Virtex families. The XC2S200 on the B5 board has far more logic and I/O than necessary, but the B5 is designed to be a very capable development board. Cost-engineering designs to fit in the smallest cheapest parts is a seperate exercise altogether.
The first design task is to consider the connections for the new target hardware.
Many of the connections are the address and data busses: one for the CPU and one for the memory. The Burched SRAM board carries 256K bytes of RAM, which is far more than the 1K of the standard ZX81. By assigning address and data bus signals in a compatible manner, these boards can be used in this project if desired.
The XC2S200 has 56Kbits of on-chip Block RAM which could provide 7 Kbytes of RAM. This would be enough for a useful ZX81. If hi-res graphics are implemented, the 256x192 pixels of screen data consume 6K bytes. Programs using such a screen are unlikely to fit in the remaining 1K, but since the Block RAM is there it seems a pity to waste it. The G007 graphics board mapped the ZX81's 1K to appear elsewhere, where it could be used seperately from the RAM pack.
Dynamic RAM is a higher density alternative to SRAM. It won't save any pins because the ROM still has a non-multiplexed address bus, but you can build the row/col multiplexer into the FPGA and also create the RAS/CAS signals.
The original ZX81 ran at 3.25 MHz and produced a display of 256 x 192 pixels. With some enginuity and faster chips this design might be run at higher speed to produce higher resolution displays.
The oscillator should be set for a clock frequency of 6.5 MHz. The original design configured the XC3042 to include an inverter to provide a simple crystal oscillator. Since the B5 already has a good one, the original inverter is no longer needed.
It has been reported (after synthesis experimentation) that it might be possible to cram an entire ZX81 into an XC2S200. By using all the block RAM, and distributed RAM, and dropping the LCD circuit, one might be able to get a VHDL Z80, 8K of system ROM and 2K of system RAM in there. This uses 99% of the logic and most of the I/O pins.
Personally I think it would be a great feat but 2K of RAM is not very useful. With a full display file you will have just over 1K to store programs in. It certainly rules out a graphics display (6K).
Memory and Z80 CPUs are far cheaper than FPGA chips, so it makes sense to reserve the latter for stuff that you can't do with the former. Once a basic ZX81 design is established, it would be nice to have room for adding peripherals like an AY38910 sound chip or a 16C552 LPT/COM device.
For the meantime, I think it will be enough to port the ZX81 glue logic to the B5 board. The Z80 core and PS2 keyboard can be added later as an optional extra.
You'll need some RAM, a Z80 CPU, keyboard keys, and a few discrete components as listed later. The Z80 clock signal should be driven to a slightly higher voltage than the usual TTL levels, so a transistor buffer does this task.
The circuit diagrams for the ZX80 and ZX81 are readily available on the net, and it is educational to examine them. The ZX80 more so, because the circuitry is not hidden in the ULA of the ZX81.
The circuit diagram for the B5-based ZX81 will be made available. (when I've done it)
You'll need the ROM contents of the ZX81 ROM. This is readily available at various nostalgic websites.
See the original source files for now. I sketched a block diagram to get a picture of how the VHDL components connect.
The res_clk block drives the clock oscillator and sends a pulse to the modes97 block at reset.
The modes97 reads the default start-up modes from diodes in
the keyboard matrix when this pulse arrives.
Alternatively it latches a new mode if the CPU writes to I/O
location 0x0007.
The mode latch controls the RAM/ROM modes, inverted video mode
and pixel/character graphics mode.
The I/O block buffers the inputs from the keyboard, tape input, and USA/UK selection.
| 0 | 1 | 2 | 3 | <- page | ||
| 0000 1FFF |
0000 1FFF |
2000 3FFF |
4000 5FFF |
6000 7FFF |
ROM page | |
| 2000 3FFF |
None | 2000 3FFF |
A000 BFFF |
C000 DFFF |
RAM page | |
| 4000 5FFF |
Usual 16K RAM pack area | |||||
| 6000 7FFF |
||||||
| 8000 9FFF |
||||||
| A000 BFFF |
||||||
| C000 DFFF |
Alias of
16K RAM pack, used for 'running' display. |
|||||
| E000 FFFF |
||||||
This is the map matching Bodo's description. The green areas are entirely ZX81 compatible. The original ZX81 had the 8K ROM appearing twice in the first 16K, but only the first 8K image was used. Bodo seems to have used the second 8K space for paged RAM, and made the first 8K paged ROM. The latter is useful because the ROM pages can contain different code (e.g for modified versions of ZX81 BASIC, or perhaps FORTH) or boot code that does something special before changing to another page. The pages are selected by writing to the mode-control latch at address 7.
I'm torn between stripping out this paging for simplicity's sake, and for the option of adding a different memory mapping scheme later on.
Kai has written a lot of code for his own mega-enhancement of the ZX81 - the ZX96 - and this includes IDE hard disks, floppy disks, and more. It seems less effort to make the I/O expansion compatible with this large body of code, than to re-invent the code for a new I/O scheme.
Kai's ZX96 uses standard parts, and basically transplants the ZX81 ULA into an entirely new rack-based computer. It does not use any FPGA chips. The ZX96 memory map does use a more complex memory paging system.
Kai's ZX96 hard disk interface is the IDE interface. Far simpler than an FDC interface, it is essentially just a few latches and buffers. BurchED have recently brought out an adapter board for connecting IDE drives to the B5 board. This will dictate the connections.
Kai's ZX96 FDC is a SAB 1793 which is slowly but surely passing the way of all non-PC compatible FDC chips. I'm not too sure how useful it will be for transferring data from PC to ZX81. May be better to fill an IDE drive at the PC then move it to the ZX81.
I recall seeing some VHDL code for PC-compatible COM and LPT ports. Kai's design did provide some non-PC compatible serial ports but there are high-integration chips like the 16C552 that dispense with the need for building baud-rate generators etc.
Kai's has also designed a board which provides 4Mbytes in 256 pages of 16K in the last 16K of the memory map. I expect this requires some enginuity to ensure the RAM containing the display file is always there when required. The XC2S200 has plenty of logic and pins available for implementing such an interface.
None yet!
See the user configuration file for this project. (when it arrives!)
Group A: CPU Address bus
Group B: CPU Data bus
Group C: CPU Control bus
Group D: TBD
Group E: Memory Address bus
Group F: Memory Data bus
Group G: TBD
Group H: TBD
To connect the FPGA to an SRAM board on the headers for I/O groups E and F, fill in the Location fields with the following:
SRAM Data
Bus (group F)
|
CPU Data
Bus (group B)
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
SRAM Address bus (group
E)
|
CPU Address bus (group
A)
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
CPU Control bus (group
C)
|
Z80 control signals (yet to be assigned to group C pins) phi |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||