The computer has a simple architecture. It has only one programmer-accessible register, the accumulator. Originally 12 bits wide, I added another 4 bits later to allow memory transfers. All load and store operations move data between memory and the accumulator, and the arithmetic-logical instructions use the accumulator as one operand, and data fetched from memory as the other. (The NOT operation, of course, only operates on the accumulator, and the operand in the instruction is ignored.) The results of arithmetic-logical operations are stored in the accumulator. Only the original 12 lower bits of the accumulator can be used for arithmetic-logical operations.
The computer has an instruction word size of 16 bits. The four leftmost bits of an instruction word are the operation code, and the 12 rightmost bits are the operand, like this:
In almost all cases, the operand is a memory address. In the case of the arithmetic-logical instructions the memory address holds the data that is to be operated on together with the data in the accumulator. For the load and store operations, the address is the source or target of the data to be moved. The one exception is the immediate load, LDI. In this case, the 12-bit operand value itself is placed in the accumulator. The various jump instructions use the operand as the target address, except the indirect jump JPI, in which the target address is held in the memory location pointed to by the operand. Here is the instruction set:
| Hex Opcode | Instruction Mnemonic | Operation Performed |
|---|---|---|
| 0 | ADD | Adds contents of memory to accumulator |
| 1 | ADC | Adds contents of memory and carry to accumulator |
| 2 | SUB | Subtracts contents of memory from accumulator |
| 3 | SBC | Subtracts contents of memory and complemented carry from accumulator |
| 4 | AND | Binary AND of memory with accumulator |
| 5 | OR | Binary OR of memory with accumulator |
| 6 | XOR | Binary XOR of memory with accumulator |
| 7 | NOT | Complements accumulator (operand ignored) |
| 8 | LDI | Loads 12-bit value of operand into accumulator (immediate load) |
| 9 | LDM | Loads contents of memory into accumulator |
| A | STM | Stores contents of accumulator to memory |
| B | JMP | Jumps to memory location |
| C | JPI | Jumps to contents of memory location (indirect jump) |
| D | JPZ | If accumulator = zero, jumps to memory location |
| E | JPM | If accumulator is negative (minus), jumps to memory location |
| F | JPC | If carry flag is set, jumps to memory location |
The address space of the computer matches the size of the instruction word operand, 12 bits or 4 kilowords. The memory and input/output ports are addressed in the same way--there are no special input or output instructions. The address space in the computer is laid out this way:
There are 5 input and 5 output ports in the computer, on the memory input/output board. The switch inputs, LED outputs and byte switcher ports are 16 bits wide. The UART ports are eight bits wide. Only the low-order eight bits of the 16 bit accumulator are transferred in UART writes. In UART reads, the upper eight bits of the accumulator are padded with zeros. Here are the computer input and output ports:
| Address | Input | Output |
|---|---|---|
| C00h | DIP switch bank 1 | LED bank 1 |
| C01h | DIP switch bank 2 | LED bank 2 |
| C02h | Byte switcher | Byte switcher |
| C03h | UART data | UART data |
| C04h | UART status | UART control |
The very first program I ran was a simple port reflector:
| Code in ROM | |||||
|---|---|---|---|---|---|
| Label | Location (hex) | Machine Code (hex) | Mnemonic | Operand | Comment |
| Start | 0 00 | 9 C 00 | LDM | Port_0 | Get number from switches |
| 0 01 | A C 00 | STM | Port_0 | Display number on LED's | |
| 0 02 | B 0 00 | JMP | Start | Do it again |
When this program was running, I knew the basic structure of the computer was sound. To further test the machine I wrote the following program. This finds the largest factor of an integer, input from DIP switch bank 1. It is the same program as that first run by the first true computer, the Manchester Mark I "Baby" in 1948. Of course, my instruction set is different than the "Baby's" which had only 7 instructions!
| Code in ROM | |||||
|---|---|---|---|---|---|
| Label | Location (hex) | Machine Code (hex) | Mnemonic | Operand | Comment |
| Start | 0 00 | 9 C 00 | LDM | Port_0 | Get number to factor from input port |
| 0 01 | A 8 00 | STM | Original_number | Store number to factor in memory | |
| 0 02 | A 8 01 | STM | Factor | Starting factor = original number | |
| Loop_1 | 0 03 | 9 8 01 | LDM | Factor | Factor loop |
| 0 04 | 2 0 0F | SUB | One | New factor = old factor - 1 | |
| 0 05 | D 0 0C | JPZ | Quit | If factor = 0, better quit (mistake) | |
| 0 06 | A 8 01 | STM | Factor | Store new factor | |
| 0 07 | 9 8 00 | LDM | Original_number | Test factor by | |
| Loop_2 | 0 08 | 2 8 01 | SUB | Factor | subtracting repeatedly from original number |
| 0 09 | D 0 0C | JPZ | Quit | Factor found-quit | |
| 0 0A | E 0 03 | JPM | Loop_1 | Went past zero, not a factor | |
| 0 0B | B 0 08 | JMP | Loop_2 | Still testing | |
| Quit | 0 0C | 9 8 01 | LDM | Factor | Get the proven factor and |
| 0 0D | A C 00 | STM | Port_0 | Display on the output | |
| 0 0E | B 0 00 | JMP | Start | Start over | |
| One | 0 0F | 0 0 01 | (constant) | ||
| Variables in RAM | |||||
| Label | Location (hex) | ||||
| Original_number | 8 00 | ||||
| Factor | 8 01 | ||||
This program tests an essential subset of the instructions, including the arithmetic instructions and two of the conditional jumps. It also tests the RAM. After this, I decided to write a program loader. This program takes hexidecimal character input from a terminal, creates 16-bit instruction words, and loads these into RAM. When the Ctrl-C key is pressed, the RAM program is executed. I have used both a dumb terminal and a 486 running a terminal emulation to enter programs. The 486 allows me to save the programs as text files, and download them as a text transfer. The program loader is here if you want to see it.
The final configuration of the finished computer allows the computer to receive a program by way of the serial port. The clock speed switch on the logic board is set to 1.8 MHz (position number 7 on). This results in a serial port baud rate of 9600. The input port 1 switches (lower bank) are set to B08Eh, as seen in the picture of the Memory-I/O board. When the computer is started (taken out of reset), it begins execution in ROM at location 000h. There is an instruction there that jumps to the I/O port location and executes whatever instruction it finds there. This feature was put in during the troubleshooting phase of development to allow testing of the computer using a variety of routines stored in ROM. To run a particular test, a jump to that test is put on the port 1 switches. B08Eh is JMP 08Eh. Location 08Eh is the entry point for the program loader.
The computer's serial port is connected to a dumb terminal (or PC running a terminal program) set for 9600 baud, one stop bit, no parity. Power is applied to the computer with the Reset/Run switch in the Reset position. A garbage character may appear on the terminal screen. The programmer may clear the terminal screen if the terminal has this ability. The computer is switched to Run. At this point the computer is ready to take instructions.
The program loader takes character input from the terminal and converts it to machine code instructions placed in RAM beginning at location 80Ah. Instructions are entered as four character hexadecimal numbers using upper case letters and the ten Arabic numerals. The program does not check for errors, and lower case letters or characters other than 0-9 and A-F will cause it to behave unpredictably. Each character is echoed back to the terminal, and after the full four characters of each instruction are received, a return/linefeed is sent back to the terminal. No return characters should be entered by the programmer, just the hexadecimal numerals. When all the code has been entered, the programmer enters a control-C character. This causes a jump to 80Ah, and the program begins execution.

© Donn Stewart 2004