This lab will exercise your understanding of the E100's instruction set and introduce you to a datapath and finite-state machine that implements some of this instruction set. You will demonstrate your understanding of the E100 by showing the results of an E100 program and by tracing through the execution of another E100 program on the datapath and finite-state machine provided.
This section summarizes the E100 CPU that was covered in lecture.
The word size for the E100 is 16 bits. Numbers are stored in 2s complement representation (i.e., bit 15 has a place value of -32768). Words thus range in value from -32768 to 32767. E.g., 16'h8000 represents -32768, 16'hffff represents -1, and 16'h7fff represents 32767. The calculator on the course web page converts between hexadecimal and signed numbers.
The E100 has instructions for arithmetic, array access, branches, function calls, and I/O. Each E100 instruction is composed of 4 memory words. The value of the first word of the instruction is called the opcode and specifies the operation for the instruction. The values of the next three memory words of an instruction are called addr0, addr1, and addr2.
The E100's program counter (PC) contains the address of the first word of the current instruction, so the current instruction can be pictured as follows:
memory[PC+0] opcode memory[PC+1] addr0 memory[PC+2] addr1 memory[PC+3] addr2
The following table describes the effect of each instruction on the E100's program counter (PC) and memory.
| Instruction name | Opcode | Effect |
|---|---|---|
| halt | 0 | PC = PC+4 stop executing instructions |
| add | 1 | PC = PC+4 memory[addr0] = memory[addr1] + memory[addr2] |
| sub | 2 | PC = PC+4 memory[addr0] = memory[addr1] - memory[addr2] |
| mult | 3 | PC = PC+4 memory[addr0] = memory[addr1] * memory[addr2] |
| div | 4 | PC = PC+4 memory[addr0] = memory[addr1] / memory[addr2] |
| cp | 5 | PC = PC+4 memory[addr0] = memory[addr1] |
| and | 6 | PC = PC+4 memory[addr0] = memory[addr1] & memory[addr2] |
| or | 7 | PC = PC+4 memory[addr0] = memory[addr1] | memory[addr2] |
| not | 8 | PC = PC+4 memory[addr0] = ~memory[addr1] |
| sl | 9 | PC = PC+4 memory[addr0] = memory[addr1] << memory[addr2] |
| sr | 10 | PC = PC+4 memory[addr0] = memory[addr1] >> memory[addr2] |
| cpfa | 11 | PC = PC+4 memory[addr0] = memory[addr1 + memory[addr2]] |
| cpta | 12 | PC = PC+4 memory[addr1 + memory[addr2]] = memory[addr0] |
| be | 13 |
if (memory[addr1] == memory[addr2]) {
PC = addr0
} else {
PC = PC+4
}
|
| bne | 14 |
if (memory[addr1] != memory[addr2]) {
PC = addr0
} else {
PC = PC+4
}
|
| blt | 15 |
if (memory[addr1] < memory[addr2]) {
PC = addr0
} else {
PC = PC+4
}
Comparisons take into account the sign of the number. E.g., 16'hffff (-1) is less than 16'h0000 (0). |
| call | 16 | memory[addr1] = PC+4 PC = addr0 |
| ret | 17 | PC = memory[addr0] |
| in | 18 | PC = PC + 4 memory[addr1] = data from I/O port addr0 |
| out | 19 | PC = PC + 4 I/O port addr0 = memory[addr1] |
The following Verilog files implement an E100 datapath (except for hexdigit.v) and partial control unit for the E100. Create a new Quartus project with these files (most should look familiar). For your convenience, here is a ZIP file containing all the Verilog files (extract them with the unzip command).
Read top.v and control.v, and review the truth table for the portion of the control unit that we covered in lecture (fetch, decode, and execute for the add and be instructions). Familiarize yourself with the signals used to control the datapath, and trace through the execution of a simple instruction (e.g., add).
Your pre-lab assignment is to answer questions about the E100 instruction set and implementation. Write your answers to a PDF file (remember to include your name) and submit it before you arrive in lab; your time in lab will be spent writing assembly-language programs. Bring the file with your answers to lab in case you need to revise and re-submit your answers.
memory[0] = 12 memory[1] = 30 memory[2] = 32 memory[3] = 31 memory[4] = 11 memory[5] = 38 memory[6] = 42 memory[7] = 45 memory[8] = 16 memory[9] = 20 memory[10] = 39 memory[11] = 0 memory[12] = 1 memory[13] = 41 memory[14] = 28 memory[15] = 29 memory[16] = 0 memory[17] = 0 memory[18] = 0 memory[19] = 0 memory[20] = 2 memory[21] = 40 memory[22] = 28 memory[23] = 29 memory[24] = 17 memory[25] = 39 memory[26] = 0 memory[27] = 0 memory[28] = -100 memory[29] = 197 memory[30] = 12000 memory[31] = 5 memory[32] = 600 memory[33] = 599 memory[34] = 598 memory[35] = 597 memory[36] = 596 memory[37] = 10000 memory[38] = 11000 memory[39] = 13000 memory[40] = 14000 memory[41] = 15000 memory[42] = 900 memory[43] = 800 memory[44] = 700 memory[45] = 2
memory[0] = 15 memory[1] = 8 memory[2] = 12 memory[3] = 13 memory[4] = 0 memory[5] = 0 memory[6] = 0 memory[7] = 0 memory[8] = 0 memory[9] = 0 memory[10] = 0 memory[11] = 0 memory[12] = 1000 memory[13] = 2000Trace through how the datapath and finite-state machine provided would execute this program. For each cycle, list the state that the finite-machine is in during that cycle and any changes to memory or registers (PC, op1, op2, opcode, addr0, addr1, addr2, memory_address) that will occur at the end of that cycle. The starting value of PC, op1, op2, opcode, addr0, addr1, addr2 are all 0. The starting value of memory_address is undefined. The starting contents of memory are given above.
To get you started, here are the answers for the first few cycles:
Cycle 1:
Cycle 2:
Cycle 3:
There is no in-lab demonstration for this lab. Instead, submit your answers to the questions above before you arrive in lab (you may revise and re-submit your answers up to the end of the due date). During the lab, you will discuss the E100 instruction set and implementation, and you will practice writing assembly-language programs.