Design and Implementation of a Simple
8-Bit CPU
Copyright © 1997, 2000 by Rex N. Fisher
3.1 Overview
There are 16 different P8 instructions. Research on instruction set usage was the basis for instruction selection. Each instruction has at least two addressing modes, with most of them having four. The instruction set is orthogonal, i.e., each instruction implements every relevant addressing mode.
3.2 Design Rationale
One of the requirements of a good instruction set is completeness. A complete instruction set can be used to evaluate any mathematical or logic function. The instruction set of an educational CPU should be complete, and should illustrate the types of instructions normally supported by actual CPUs.
The instruction set should also be simple. There is research that indicates that even very simple instruction sets can be complete. As early as 1956 a simple 1-instruction computer was developed that met the requirement of completeness (Hayes, 1988, p. 210). Of course, an excessively simple instruction set requires very complicated programs to perform even the simplest tasks.
The P8 instruction set is both complete and reasonably simple. Its completeness can be informally proven by writing a sequence of instructions to implement common operations that have not been included. For example, multiplication can be performed, even though there is no multiply instruction, with a sequence of adds and shifts. Similarly, the nonexistent AND function can be implemented because both OR and NOT are available.
Another desirable characteristic of an instruction set is regularity. A regular instruction set includes normally expected operations. In this case, some commonly encountered instructions have been omitted. This was done primarily for two reasons:
1. The 74181 4-bit ALU used for this CPU has a limited repertoire of functions. For example, it implements a shift left and decrement, but not a shift right or increment. While this can lead to awkward code composition, and may sometimes require a little creative programming, it is possible to work around the missing functions.
2. This CPU is a teaching tool. A powerful instruction set is not a requirement. In fact, a simple instruction set, that implements only the most common instruction types is easier to understand. In the interest of simplicity, the instruction set has been limited to 16 different operations.
Regularity also implies orthogonality. An orthogonal instructions set is one where each instruction can use every relevant addressing mode. This simplifies compiler design by making the rules for operand address specification consistent. While this is not an important consideration for the P8 CPU, it demonstrates the principle.
Research on instruction mixes for several types of processors
has been compiled over the years. Of the various processors that have been
benchmarked, the Intel 8086 most closely resembles the P8 CPU for this project (Hennessy & Patterson, 1990, p. 178). The
frequency of instructions used by the 8086 is shown in Figure 3.1. This information
is a reasonable guide for determining the most appropriate instruction mix for a simple,
accumulator-based CPU like this one. Instructions that are used often should be included,
if possible.
8086 Instruction Average Frequency of Use
Move 27%
Conditional Jump 10%
Compare 7%
Push 7%
Pop 5%
Shift Left, Shift Right 5%
Loop 4%
Call 4%
Return 4%
Increment, Decrement 3%
Or, Xor 3%
Add 3%
Subtract 2%
Jump 2%
All other instructions had a frequency of use less than 2%.
Figure 3.1: Distribution of Instruction Frequencies on the Intel 8086.
Most instructions with a usage-frequency less than 2% have not been implemented.
Additionally, there are several common instructions that cannot be fully implemented on
the P8 CPU:
Conditional Jump: The only condition flag is zero. Conditional jumps can only be based on whether the zero flag is set. This illustrates the principle while maintaining a simpler hardware implementation.
Compare: Only equality can be evaluated.
Push & Pop: Eliminating the stack pointer simplified the hardware significantly, but precluded the use of these instructions.
Call & Return: Again, the lack of a stack pointer makes these difficult to implement. The functions could be performed by jumping to predetermined addresses, but the programming would not be straightforward.
Loop: This operation must be implemented with a sequence of simpler instructions.
Increment: This function is not available on the 74181 ALU. The additional circuitry required to implement this would not contribute to the goal of simplicity. If an increment is required, it can be done by the add instruction with immediate data of 01h.
Operations chosen for inclusion in this instruction set represent those used nearly two-thirds of the time in the 8086 benchmarks.
An educational CPU should also implement common addressing
modes. Benchmark results of commonly used 8086 addressing modes for various
application programs (Hennessy & Patterson, 1990,
p. 177) can be seen in Figure 3.2.
8086 Addressing Mode
Frequency of Use
Memory
Absolute
12%
Indirect
5%
Displacement
24%
Register
51%
Immediate
8%
Figure 3.2: Distribution of Addressing
Mode Frequencies on the 8086.
Even though displacement addressing is very powerful, and used frequently on the 8086, it has not been implemented because hardware complexity would be increased.
3.3 Programmers Model
The P8 CPU consists of three 8-bit registers and one 1-bit condition register. See Figure 3.3. It is an accumulator-based design. This means that the number in the accumulator (A register) is an operand for most ALU operations. Additionally, all ALU results are placed in the A register, and overwrite its previous contents. It is also used for reading input ports and writing output ports. The R register may be used to store general data or a second operand. It also contains the memory address of operands for instructions using indirect addressing.
Because the instruction pointer is an 8-bit register, only 256 bytes of memory may be addressed. Similarly, there are 256 available I/O ports, which do not share the memory space.
The Z register is a 1-bit register that stores the results of
the last compare operation. If the result was zero, the Z register contains a
"1", otherwise it is "0".
CPU Registers
+----------------+
| |
Instruction Pointer (Program Counter)
+----------------+
| | A
Register (Accumulator)
+----------------+
| | R
Register (Data/Address Register)
+-+--------------+
| |
Z
Register (Zero Flag Register)
+-+
Memory Space
I/O Space
+----------------+
+----------------+
|
|
Address 00h |
|
|
|
| |
|
|
| |
|
|
| |
|
|
Address FFh |
|
+----------------+
+----------------+
Figure 3.3: Programmers Model of P8 CPU.
3.4 Instruction Types
P8 CPU instructions fall into five major instruction categories:
1. Input / Output. These instructions transfer data between the accumulator and external I/O devices.
IN = Read Input Port
OUT = Write Output Port
2. Program Control. These instructions change the sequence of program execution. They are often called branch instructions.
JMP = Unconditional Jump
JNZ = Jump If Not Zero (Conditional Jump)
JZ = Jump If Zero (Conditional Jump)
CMP = Compare (Sets / Resets Zero Bit For Conditional Jumps)
3. Data Transfer. These instructions cause data in one location (either the internal registers or external memory) to be copied to another location.
LDA = Load A Register
LDR = Load R Register
STA = Store A Register
STR = Store R Register
4. Arithmetic. These instructions perform numerical operations on data. (Floating point operations are not supported.)
ADD = Add To A Register
SUB = Subtract From A Register
DEC = Decrement
5. Logical. These instructions perform Boolean operations on data, including bit shifting.
OR = Or With A Register
INV = Invert & Move To A Register
SHL = Shift Left & Move To A Register
3.5 Addressing Modes
Four common addressing modes have been selected for this instruction set. They account for those used two-thirds of the time in Intel 8086 benchmarks. They are:
1. Direct. This is the same as absolute addressing. The address of the required data is part of the instruction. In this case, it will be the second byte of the instruction.
2. Indirect. The address containing the address of the required data is specified. There are normally two types of indirect modes: 1) memory-indirect; and 2) register-indirect. An instruction with memory-indirect addressing specifies the memory address in which the address of the required data is stored. A specified register contains the address of the data when register-indirect addressing is used. The indirect mode for this instruction set will be limited to register-indirect, and the register containing the address will always be the R Register.
3. Register. This is sometimes called inherent addressing. The required data is in a register.
4. Immediate. The required data is part of the instruction. For this architecture, it is the second byte of the instruction.
3.6 Instruction Format
Each instruction has an 8-bit opcode. The eight bits are divided into two fields: 1) the operation; and 2) the addressing mode (Figure 3.4).
All instructions that use register addressing or
indirect addressing require only one byte. A second byte is required for the other
two addressing modes. The second byte of a direct instruction contains the 8-bit
address, and the second byte of an immediate instruction specifies the immediate data.
-----------------
|X|X|X|X|X|Y|Y|Y| 8-Bit Opcode
-----------------
-----------------
|Z|Z|Z|Z|Z|Z|Z|Z| 8-Bit Address or Immediate
Data
-----------------
Figure 3.4: Instruction Format for 1-Byte & 2-Byte Instructions.
The operation is encoded in the 5-bit field labeled XXXXX.
5-Bit Operation Code Instruction Type
00001 IN
00010 OUT
00100 JMP
00101 JNZ
00110 JZ
00111 CMP
01000 LDA
01001 LDR
01010 STA
01011 STR
01100 ADD
01101 SUB
01110 DEC
10000 OR
10001 INV
10010 SHL
The addressing mode is encoded in the 3-bit field labeled YYY.
3-Bit Code Addressing Mode Data Location
000 Direct Memory Address in Byte 2
001 Not Used ---
010 Register A Register
011 Register R Register
100 Indirect Memory Address in R Register
101 Not Used ---
110 Immediate Byte 2 of Instruction
111 Not Used ---
3.7 Instruction Set Repertoire
See Appendix 7.1 for a more comprehensive description of the instruction set.
Instruction Addressing Mode Operation Performed # Bytes
ADD address Direct
A <- A +
MEM(address)
2
ADD A Register
A <- A + A
1
ADD R Register
A <- A +
R
1
ADD M Indirect
A <- A + MEM(R)
1
ADD I, data Immediate
A <- A +
data
2
CMP address Direct
If A -
MEM(address) = 0: Z <- 1 2
CMP A Register
If A - A = 0: Z <-
1
1
CMP R Register
If A - R = 0: Z <-
1
1
CMP M Indirect
If A - MEM(R) = 0: Z <- 1
1
CMP I, data Immediate
If A - data = 0: Z <-
1 2
DEC address Direct
A <-
MEM(address) -1
2
DEC A Register
A <- A -
1
1
DEC R Register
A <- R -
1
1
DEC M Indirect
A <- MEM(R) -
1
1
DEC I, data Immediate
A <- data -
1
2
IN address Direct
A <-
PORT(address)
2
IN P Indirect
A <-
PORT(R)
1
INV address Direct
A <-
[MEM(address)]
2
INV A Register
A <-
[A]
1
INV R Register
A <-
[R]
1
INV M Indirect
A <- [MEM(R)]
1
INV I, data Immediate
A <-
[data]
2
JMP address Direct
IP <-
address
2
JMP R Register
IP <-
R
1
JNZ address Direct
If Z = 0: JMP
address 2
JNZ R Register
If Z = 0: JMP R
1
JZ address Direct
If Z = 1: JMP
address
2
JZ R Register
If Z = 1: JMP
R
1
LDA address Direct
A <-
MEM(address)
2
LDA A Register
A <-
A
1
LDA R Register
A <-
R
1
LDA M Indirect
A <-
MEM(R)
1
LDA I, data Immediate
A <-
data
2
LDR address Direct
R <-
MEM(address)
2
LDR A Register
R <-
A
1
LDR R Register
R<-
R
1
LDR M Indirect
R <-
MEM(R)
1
LDR I, data Immediate
R <-
data
2
OR address Direct
A <- A OR
MEM(address) 2
OR A Register
A <- A OR
A
1
OR R Register
A <- A OR
R
1
OR M Indirect
A <- A OR
MEM(R)
1
OR I, data Immediate
A <- A OR data
2
OUT address Direct
PORT(address)
<-
A
2
OUT P Indirect
PORT(R) <- A
1
SHL address Direct
A <-
[MEM(address)]6..0 ## 0 2
SHL A Register
A <- [A]6..0 ##
0
1
SHL R Register
A <- [R]6..0 ##
0
1
SHL M Indirect
A <- [MEM(R)]6..0
## 0 1
SHL I, data Immediate
A <- [data]6..0 ## 0
2
STA address Direct
MEM(address) <-
A
2
STA M Indirect
MEM(R) <- A
1
STR address Direct
MEM(address) <-
R
2
STR M Indirect
MEM(R) <- R
1
SUB address Direct
A <- A -
MEM(address) 2
SUB A Register
A <- A -
A
1
SUB R Register
A <- A -
R
1
SUB M Indirect
A <- A - MEM(R)
1
SUB I, data Immediate
A <- A - data
2
[Back to top][Back to Table of Contents][<== Previous Section][Next Section ==>]