Rudi's Homepage - Elektronik

EnglishDeutsch

Introduction

Here you find some classic single-board computers, based on legendary CPU's like the Z80 or the 68000. Beside the self-educational purpose (how do I design a memory or I/O control logic, how do I interpret the dynamic bus protocol of the CPU?) I see these projects as personal monuments of milestones in computer history. Not so far in the past the Z80 was a synonym for CP/M and Personal Computers and the 68000 the driving force behind Macintosh computers or the hearths of the legendary Commodore Amiga or the Atari ST.
Last time updated: 18.06.2018 20:40

Z80 Computer

Description:

This is my first self-made computer. Its a minimal Z80 system consisting of a Z80 CPU clocked by 2.4576 Mhz, 8 kByte ROM, 8 kByte SRAM and a 16C550 UART. The UART provides an interface for the communication with the computer via a serial link with 9600 baud. There are 3 LED's, one signalling the HALT-signal of the CPU, the others are connected to free-programmable output pins of the UART.

Component description.
Component description.

Construction

The computer is build on a "Euro-Processor" hole-matrix board. For the chasing I used a fully transparent sweatmeat box which gives a complete insight (the purpose!) and doesn't cost a penny.

View from below.
View from below.
A part of the motivation to build this computer was to build a memorium to an important time of the computer age, the time of 8 bit microcomputers, for whom the Z80 was the "crowning glory", the most perfect example of its kind. Its instruction set was not the product of hardware limitations, the hardware followed a clear spirit. Ahead of its competitors, the Z80 provided 16 Bit Operations, block transfer operations and a sophisticated interrupt system.

Schematic - overview

Schaltplan
Schaltplan
The power supply consists of a full-wave rectifier followed by a 7805 fixed-voltage regulator. The clock signal is provided by an oscillator module (OSC). The input pins WAIT and BUSRQ have been deactivated by connection to to 2k2 pullup resistors. The NMI input pin is also on H level by a pullup resistor but can set to active L by a jumper bridge. The reset circuit (drawed below the CPU) consists of an RC-lowpass an two cascaded 71HCT14 smith-trigger inverters to produce the H- and L-active reset signal. Notice that the RC combination was not sufficient to produce a power-on-reset. Notice too that the schematic doesn't include the 100n buffer condensators connected directly to the power pins of the IC's. In addition, all unused gate inputs of the TTL chips have been connected to L level to inhibit oscillations.

Schematic - memory control

The purpose of the memory control is to generate the chip-select signals for the extern memory chips (8 kByte EEPROM, 8 kByte SRAM) and for the 16C550 UART. A complicated dynamic behavior is not necessary since all memory IC's are fast enough to respond within a bus cycle of the CPU (otherwise the memory control would have to generate WAIT-signals for the CPU). Since the Z80 uses seperate memory spaces for data and I/O I used the following simple address space segmentation: the program/data memory space of 64 kByte is seperated into two halves, the lower half belongs to the 8 kByte EEPROM, the beginning of the upper half to the SRAM. A memory read bus cycle start with an active MEMRQ (L) in combination with a valid address on the bus and the desired direction indicatet by the RD or WR pin. Therefore the chip select signal for the ROM is A15=L AND MEMRQ=L, in short ROMCS = A15 UND MEMRQ, which will be realized by gate U4. For the RAM we have: RAMCS active = L if A15 = H and MEMRQ = L, in short RAMCS = (NOT A15) AND MEMRQ, realized by U3 and U5. For the I/O the main difference is that we use IORQ instead of MEMRQ. Since we have only one I/O chip it would be sufficient to connect IORQ with the chip select of the UART but we have enough gates free. I choosed to set the UART base address to 128, therefore UARTCS = active L if A7=H and IORQ=L, in short UARTCS = (NICHT A7) UND IORQ, realized by U6 und U7.

The monitor

The firmware (or Basic Input Output System, BIOS) has two functions: provide a set of elementary routines (for I/O e.g.) and to provide a monitor tool which allows to see the content of the memory or the registers, switch the LED's, load an execute programs. The assembler source code is available here, the binary here. The following system routines are available: PRINT_CHAR (0xd3) Prints a char. The ASCII code of the char will be expected in the A register. PRINT_STRING (0xb9) Prints a zero-terminated character string which base address is expected in BC. PRINT_HEX (0x144) Prints the content of the HL register as a hexadecimal number. PRINT_BINARY (0x1ba) Prints the content of the A register as a binary number. DUMP_MEM2 (0x1cb) Dumps the content of the memory cell indicated by HL as a hex number. Num2Dec (0xfd) Converts the number in HL to a character string containing the decimal code. The base address of the string is expected in DE. Num2Hex (0x125) Converts the number in HL to a character string containing the hexadecimal code. The base address of the string is expected in DE. input_char (0xe6) Inputs a single character (blocking) and puts it into the A register. input_string (0x193) Inputs a zero-terminated character string to the location indicated by HL. HL points to the end of the string afterwards. input_stringl (0x1a6) Inputs a zero-terminated character string of max BC characters to the location indicated by HL. HL points to the end of the string afterwards. atoi8u (0x172) Converts the zero-terminated string referenced by HL into a 8 Bit unsigned decimal number stored in A. atohex8u (0x21a) Converts the zero-terminated string referenced by HL into a 8 Bit unsigned hexadecimal number stored in C. The B register contains 0 if the conversion was succesfull or the index of the faulty character. toggle_1 (0x3a5) Switches the first LED. toggle_2 (0x3c1) Switches the second LED. mul8u8u (0x5cd) Unsigned 8 bit multiplication HL=H*L. div8u8u (0x5f6) Unsigned integer division D/E, Quotient in D, Remainder in A. After a reset the computer output a greeting and the main menu (serial communication with 9600 baud, 8N1). This menu provides functions to dump the memory or registers, load and execute programs or toggle the LED's.

Main menu.
Main menu.
The following picture shows a register dump:
Register dump.
Register dump.
The next picture shows a memory dump.
Memory dump.
Memory dump.

Programmierung

The following example shows how to load an execute a simple program. This program should calculate the sum of all integer numners from 1 to N for a given N. The number N should be read from a given address in memory and the result should be written back to the same location. First we write the assembler program in our favorite editor:

Writing the assembler program.
Writing the assembler program.
At the beginning we define the address of the memory cell where N is (0x8200) as a symbol or macro N. Then we save all used registers to the stack and load the content of the memory cell N to the A register and from A to the counter register B. Afterwards we clear the accumulator register (very important register for 1-argument maschines like the Z80!) and sum up the values of B in a count-down-loop which runs from N to 0. For this purpose we use the DJNZ instruction which decrements B and jumps if B != 0. Now we only have to write the value in A back to the memory cell N, restore the content of the used register from the stack and return to the calling monitor program. After the assembling of the source with an assembler (z80-asm, local copy)
			  z80-asm Prog1.asm Prog1.z80
		  
We can view the instruction code with a hex editor (which we use to remove the preamble generated by the assembler):
The maschine program.
The maschine program.
Now we can enter the instruction code via the l command of the monitor:
Input of the instruction code.
Input of the instruction code.
Now we can validate the input with the d command:
Verification of the program loading.
Verification of the program loading.
Now we can enter the numerical value of N into the memory cell 0x8200:
Input of the argument.
Input of the argument.
Again we check the input with a memdump:
Verification of the argument input.
Verification of the argument input.
After we executed the program with the g command we can read the result:
Display of the result.
Display of the result.
The result 0xF=15d is the sum of 1+2+3+4+5 = (5+1)*5/2.

An advantaged version.

Now we rewrite the program to provide a better user interface using the provided BIOS subroutines. The source code of the resulting program can be found here. Since a manual input of the instruction code would be too much work I rewrote the monitor to provide the loading of binary files using the b command. In addition I wrote a C++-programm for converting the output format of z80-asm to the format expected by the monitor. The calling syntax is:

			  z80-asm Prog2.asm 0x8400::Prog2.z80
			  convertZ80 Prog2.z80 Prog2.bin
		  
The converted binary Prog2.bin can be send via the "send raw file" command of the terminal program gtkterm.
Eine komfortablere Version.
Eine komfortablere Version.


68000 Computer

Description:

Impressions from the construction

Preview.
Preview.
Workbench.
Workbench.