Computer Science 281
Computer Organization

Denison

Project 1

DSCPU
The Denison Simple
CPU Simulator

Test Files

File Comments
test0.txt
Program from description below.
test1.txt
 
test2.txt
 
test3.txt
 

CPU Description

The following CPU description is based on The Relatively Simple CPU defined by John D. Carpinelli in his textbook, Computer Systems Organization & Architecture. A few changes and additions have been made to make the model more challenging. We will call this CPU the Denison Simple CPU, or DSCPU.

The DSCPU has 8-bit opcodes and 16-bit addresses. Instructions are variable length, depending on the instruction, and may be either 8 bits (an opcode and no explicit operands), 16 bits (an opcode and an 8-bit immediate value as a source operand), or 24 bits (an opcode followed by a 16-bit source operand address).

Registers

There are 3 registers directly controlled by the programmer:

Programmer Visible Registers
Name Size (bits) Description
AC
8
Accumulator. AC receives the result of arithmetic and logic instructions. It provides one of the operands for two-operand arithmetic and logic instructions. Data is loaded to/from AC from/to memory.
R
8
General purpose register. R supplies the 2nd operand of all two-operand arithmetic and logic instructions. It can also be used as a temporary storage area.
Flag
4
Status flags given as follows:
Z
1
Zero flag. This bit is set/reset as a result of arithmetic or logic operations. If the result of an arithmetic/logic operation is zero, then Z is set to 1. If the result of an arithmetic/logic operation is not zero, then Z is set to 0. Z is set/reset as a result of ADD, SUB, INAC, CLAC, AND, OR, XOR, NOT, RL, RR, LSL, and LSR.
C
1
Carry flag. This bit reflects the result of the carry out of the most significant bit of the result of the last executed arithmetic operation. In other words, if data is treated as unsigned, it represents the result too large in the case of add or a borrow in the case of subtract. C is set/reset as a result of ADD, SUB, INAC, RL, RR, LSL, LSR.
V
1
Overflow flag. This bit is set if the carry into the most significant bit of the result does not equal the carry out of the most significant bit of the result of the last executed arithmetic operation. It is reset if the carry into of the most significant bit equals the carry out of the most significant bit of the result of the last arithmetic operation. This is like the carry except for signed data, the addition of two positive numbers results in a negative number. V is set/reset as a result of ADD, SUB, INAC, RL, RR, ASL, and ASR.
N
1
Negative flag. This bit is set if the result of the operation is negative - the msb of the result is set. N is set/reset as a result of ADD, SUB, INAC, CLAC, AND, OR, XOR, NOT, RL, RR, SL, and ASR.

The DSCPU also contains several registers in addition to those specified in the instruction set:

CPU Hidden Registers
Name Size (bits) Description
PC
16
Program counter. PC contains the address of the next instruction to be executed or the address of the next operand of the current instruction.
IR
8
Instruction register. IR contains the opcode, as fetched from memory, of the instruction currently being executed.
AR
16
Address register. AR is used in the interface to memory and holds the address for a memory request. The AR must be loaded prior to a request to read memory (for a load) or for a write to memory (for a store).
DR
8
Data register. DR is also used in the interface to memory. It holds the data value to store on a memory write operation, and must be loaded prior to the write request. It holds the value read from memory following a read request.
TR
8
Temporary register. TR holds data during the execution of an instruction.

Memory

The DSCPU has access to 65536 bytes of physical memory, mem. Addresses are 16 bits in length, and every memory byte is accessible by an address in the range 0 to 65535. Reads and writes from/to memory and achieved through the use of AR and DR. To perform a read, AR is loaded with the desired address, a, and then a memory read is requested. The completion of the read results in the contents, mem[a], in DR. To perform a write, AR is loaded with the desired address, a, and the data value to be written, d, is loaded into DR. The memory write is then requested.

Instruction Set

In the following table, an A operand refers to a 16-bit memory address and is composed of the two bytes (MSB followed by LSB) following the opcode in memory. An I operand refers to an 8-bit immediate value and is found in the byte immediately following the opcode in memory.

Instruction Opcode
(binary)
Operand Semantics
NOP
0000 0000
-
None (other than advancing PC)
LDAC
0000 0001
A
AC <- mem[A]
STAC
0000 0010
A
mem[A] <- AC
MVAC
0000 0011
-
R <- AC
MOVR
0000 0100
-
AC <- R
JUMP
0000 0101
A
PC <- A
JMPZ
0000 0110
A
if (Z==1) then PC <- A
JPNZ
0000 0111
A
if (Z==0) then PC <- A
JMPC
0001 0000
A
if (C==1) then PC <- A
JMPV
0001 0001
A
if (V==1) then PC <- A
JMPN
0001 0010
A
if (N==1) then PC <- A
ADD
0000 1000
-
AC <- AC + R; ZCVN update
SUB
0000 1001
-
AC <- AC - R; ZCVN update
INAC
0000 1010
-
AC <- AC + 1; ZCVN update
CLAC
0000 1011
-
AC <- 0; ZCVN update
AND
0000 1100
-
AC <- AC & R; ZN update {bitwise AND}
OR
0000 1101
-
AC <- AC | R; ZN update {bitwise OR}
XOR
0000 1110
-
AC <- AC ^ R; ZN update {bitwise XOR}
NOT
0000 1111
-
AC <- !(AC); ZN update {bitwise complement}
RL
0001 0110
-
AC <- AC rotated left one bit position; ZCVN update
RR
0001 0111
-
AC <- AC rotated right one bit position; ZCVN update
LSL
0001 0100
-
AC <- AC shifted left one bit position, zero fill in lsb; ZCVN update
LSR
0001 0101
-
AC <- AC shifted right one bit position, zero fill in msb; ZCVN update
MVI
0001 0011
I
AC <- I
HALT
1111 1111
-
Halt execution

Assignment

Using appropriate data structures to represent memory and ALL registers (both programmer visible, and the hidden CPU registers), write a simulator to simulate DSCPU. To do this, we need a mechanism to load code and data into the memory of the simulator.

Top-level Interaction

  1. Your program must first output your name and a description of the program.
  2. Your program must prompt the user for the name of a file containing the program.
  3. Your program should echo the name of the file.
  4. You will then load the program into memory. Always load the program beginning at mem[0], and then initialize PC to 0.
  5. Once loaded, the program will print out the initial values of the complete register set: AC, R, Flag, PC, AR, DR, IR, and TR.
  6. Begin executing the program, using a fetch-decode-execute cycle. Give the user the option to either single-step through the program, or to execute the program without further user interaction.
  7. Execution of a HALT instruction terminates the simulation, and the complete register set is again printed out.

Executable File Format

The programs to be run by your DSCPU simulator will be stored in a text file. Each line of the text file represents a single byte to be stored in successive location of the DSCPU memory. Each byte will be represented by two ASCII characters for the two hexidecimal digits required for the byte. Hex digits may be in lower or upper case. From the perspective of loading a program, there is no distinction between the code and data of the program. Also, there is no stack. A file containing the following lines:

00
0b
0a
02
20
00
00
ff

is a 6 instruction program :

NOP
CLAC
INAC
STAC 0x2000
NOP
HALT

Instruction Execution

Fetch/Decode

The fetch cycle of the DSCPU consists of 3 subphases:

Fetch1, Fetch2, and Fetch3 must be done consecutively. However note, Fetch2 and Fetch3 each have two operations. Those two operations could be done simultaneously in hardware. You must provide a fetch function.

At the completion of Fetch1, print out the label Fetch1 and the values of AR and PC. At the completion of Fetch2, print out a label Fetch2 and the values in DR and PC. At the completion of Fetch3, print out a label Fetch3 and the value of IR and AR. Be sure to identify the data printed.

In the Decode Cycle, determine the instruction contained in IR and call the appropriate function to execute the instruction. You must provide a function for each instruction.

Execute Cycle

For all instruction functions:

PC, AC, R, Flag, AR, DR


NOP Instruction

Return, no action

LDAC Instruction

This is a 3-byte instruction: Opcode, high-order half of address, and low-order half of the address. The execution function must first get the address from memory then the data from the memory location and load it into the accumulator.

Note that, based on the fetch phases above, PC and AR point to the first byte of the address - the high-order half of the address A.

The execution of the LDAC instruction is as follows:

Phase
Register Transfer
Comment
LDAC1
DR<-mem[AR]
Read the high-order half of the address A into DR
PC<-PC + 1
Increment PC
AR<-AR+1
Increment AR
Print out registers PC, AR, DR labeled with LDAC1
LDAC2
TR <- DR
Save high-order half of address A
DR <- mem[AR]
Get low-order half of address A
PC <- PC + 1
Increment PC
  Print out registers PC, AR, DR, TR labeled with LDAC2
LDAC3
AR <- TR || DR
Form address A and put in AR
  Print out register AR labeled with LDAC3
LDAC4
DR <- mem[AR]
Read memory at address A
Print out register DR labeled with LDAC4
LDAC5
AC <- DR
Update AC with value read
  Print out register AC labeled with LDAC5

LDAC1 through LDAC5 are execution subcycles. The subcycles must be executed in consecutively. Like execute, there are multiple operations going on in some of the subphases. Some could be done in parallel in hardware.

Remaining Instructions:

The LDAC is one of the more complex instructions. I have provided you with the details of the exection subphases of LDAC and exactly what to print out. Using LDAC as a guide, use the definition of the instruction given in the table above to determine the execution subphases for each instruction. At the completion of each subphase you must print out all registers that are modified during the subphase.

For the STAC Instruction, prior to storing the data in memory, you must print the location to be stored and print the same data after memory has been updated.

Deliverables

Using a word processor and the guide presented for LDAC, for each instruction, provide the execution subphases and the operations in each subphase.

Your finished project must be submitted via email. It is assumed that you wrote your program in C++. Your main program must be dscpu.cpp. In my own solution, I have C++ classes defined for the register set, for memory, for the alu, and for the cpu. Each of these consists of a separate ".h" file for the interface specification and a ".cpp" file for the implementation. You are free to design as you see fit, but structure is important. Also, at least 15% of the grade will be based on the comments and following the Denison C++ coding conventions, and style/neatness. Programs that do not compile are not worth any points. Programs that do not properly run to a normal completion are worth very little. You must test your code to ensure that every instruction produces the correct result.

Please Note: My program is around 1000 lines. If you wait until the day before this assignment is due, it is very unlikely that you will be successful.