Programming and Operation

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 OpcodeInstruction MnemonicOperation Performed
0ADDAdds contents of memory to accumulator
1ADCAdds contents of memory and carry to accumulator
2SUBSubtracts contents of memory from accumulator
3SBCSubtracts contents of memory and complemented carry from accumulator
4ANDBinary AND of memory with accumulator
5ORBinary OR of memory with accumulator
6XORBinary XOR of memory with accumulator
7NOTComplements accumulator (operand ignored)
8LDILoads 12-bit value of operand into accumulator (immediate load)
9LDMLoads contents of memory into accumulator
ASTMStores contents of accumulator to memory
BJMPJumps to memory location
CJPIJumps to contents of memory location (indirect jump)
DJPZIf accumulator = zero, jumps to memory location
EJPMIf accumulator is negative (minus), jumps to memory location
FJPCIf 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:

000h to 7FFh (2048 words) Programmable, read-only memory (ROM)
800h to BFFh (1024 words) Static random-access memory (RAM)
C00h to FFFh (1024 ports) Input/output (I/O)

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:

AddressInputOutput
C00hDIP switch bank 1LED bank 1
C01hDIP switch bank 2LED bank 2
C02hByte switcherByte switcher
C03hUART dataUART data
C04hUART statusUART control

The very first program I ran was a simple port reflector:

Code in ROM
LabelLocation (hex)Machine Code (hex)MnemonicOperandComment
Start0 009 C 00LDMPort_0Get number from switches
0 01A C 00STMPort_0Display number on LED's
0 02B 0 00JMPStartDo 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
LabelLocation (hex)Machine Code (hex)MnemonicOperandComment
Start0 009 C 00LDMPort_0Get number to factor from input port
0 01A 8 00STMOriginal_numberStore number to factor in memory
0 02A 8 01STMFactorStarting factor = original number
Loop_10 039 8 01LDMFactorFactor loop
0 042 0 0FSUBOneNew factor = old factor - 1
0 05D 0 0CJPZQuitIf factor = 0, better quit (mistake)
0 06A 8 01STMFactorStore new factor
0 079 8 00LDMOriginal_numberTest factor by
Loop_20 082 8 01SUBFactorsubtracting repeatedly from original number
0 09D 0 0CJPZQuitFactor found-quit
0 0AE 0 03JPMLoop_1Went past zero, not a factor
0 0BB 0 08JMPLoop_2Still testing
Quit0 0C9 8 01LDMFactorGet the proven factor and
0 0DA C 00STMPort_0Display on the output
0 0EB 0 00JMPStartStart over
One0 0F0 0 01(constant)
Variables in RAM
LabelLocation (hex)
Original_number 8 00
Factor8 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.

Computer Operation

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