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. You will also be introduced to Git, a version control system that will prove useful for lab 8 as well as future projects.
This section summarizes the E100 CPU that was covered in lecture.
The word size for the E100 is 32 bits. Numbers are stored in 2s complement representation (i.e., bit 31 has a place value of -2147483648). Words thus range in value from -2147483648 to 2147483647. E.g., 32'h80000000 represents -2147483648, 32'hffffffff represents -1, and 32'h7fffffff represents 2147483647. 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 arg1, arg2, and arg3.
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] arg1 memory[PC+2] arg2 memory[PC+3] arg3
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[arg1] = memory[arg2] + memory[arg3] |
sub | 2 | PC = PC+4 memory[arg1] = memory[arg2] - memory[arg3] |
mult | 3 | PC = PC+4 memory[arg1] = memory[arg2] * memory[arg3] |
div | 4 | PC = PC+4 memory[arg1] = memory[arg2] / memory[arg3] |
cp | 5 | PC = PC+4 memory[arg1] = memory[arg2] |
and | 6 | PC = PC+4 memory[arg1] = memory[arg2] & memory[arg3] |
or | 7 | PC = PC+4 memory[arg1] = memory[arg2] | memory[arg3] |
not | 8 | PC = PC+4 memory[arg1] = ~memory[arg2] |
sl | 9 | PC = PC+4 memory[arg1] = memory[arg2] << memory[arg3] |
sr | 10 | PC = PC+4 memory[arg1] = memory[arg2] >> memory[arg3] |
cpfa | 11 | PC = PC+4 memory[arg1] = memory[arg2 + memory[arg3]] |
cpta | 12 | PC = PC+4 memory[arg2 + memory[arg3]] = memory[arg1] |
be | 13 |
if (memory[arg2] == memory[arg3]) { PC = arg1 } else { PC = PC+4 } |
bne | 14 |
if (memory[arg2] != memory[arg3]) { PC = arg1 } else { PC = PC+4 } |
blt | 15 |
if (memory[arg2] < memory[arg3]) { PC = arg1 } else { PC = PC+4 } Comparisons take into account the sign of the number. E.g., 32'hffffffff (-1) is less than 32'h00000000 (0). |
call | 16 | memory[arg2] = PC+4 PC = arg1 |
ret | 17 | PC = memory[arg1] |
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).
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 part1.txt and part2.txt and push the files to the lab 5 repository (see Submission section). Have this assignment completed 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
Your responses should have the following form:
<instruction number> pc:<pc #> mem[<mem location>]:<new mem value>
You only need to insert mem if it changes during that instruction.
Your first line should be:
1 pc:4 mem[37]:12000
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, arg1, arg2, arg3, memory_address) that will occur at the end of that cycle.
Your responses should have the following form:
<cycle number> state:<current_state> <modified_register>:<new_register_value> mem[<mem location>]:<new mem value>
Note that you only need to insert mem or registers if their values change in that cycle.
Acceptable states are found in control.v and include but are not
limited to: (state_reset, state_fetch2, state_decode,
state_fetch1, state_blt1, state_halt).
Registers are found in the datapath and include but are not limited to: (pc, mar [for memory
address register], arg1, arg2, arg3, op1, op2).
When your <current state> is state_halt, you should stop. (Don't have more than one state_halt.)
Your first two lines should be:
1 state:state_reset 2 state:state_fetch1 mar:0The starting value of PC, op1, op2, opcode, arg1, arg2, arg3 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, have the pre-lab assignment completed 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.
Git is a Version Control System (VCS) that you will be using to keep backups of your project. For more on how Git works, we recommend reading the Git tutorial when you are able. For now, we will guide you through how to submit your answers using Git. This process is meant to introduce you to using Git, but its usefulness may not become apparent until later labs.
First, ensure that you have registered for a username on GitHub and have registered your username on the ENGR 100 website (link on the homepage). If you do not receive an email about repository access from GitHub, please notify an instructor. Second, ensure that you have created SSH keys to access GitHub. GitHub offers a great tutorial on this. We also have a tutorial and a tips page that you should take a look at.
When you gain access to the your repository, it should be in the form of ENGR100-W15/[USERNAME]-LAB5. To start, download a copy of the repository (repo, for short) using the following command:
$ git clone https://[USERNAME]@github.com/ENGR100-W15/[USERNAME]-LAB5.git
You should end up with a message similar to
Insert response here
You should now have a directory labeled [USERNAME]-LAB5 in your current directory, which you can verify with ls.
Entering this directory with cd [USERNAME]-LAB5, you should see a few files, including a README, part1.txt, and part2.txt. The README explains the format in which you should submit this assignment, while the other two files provide samples.
When you are finished with your assignment (or if you just want to make a backup), it's time to commit and push your files. Committing is the process of making a backup, or commit, on your local machine (or in this case your CAEN account), and pushing is the processes of sending that backup to GitHub so that the instructors (and in the future, your teammates) may access the files. To commit, we must first add all of the changes that will go in the commit. You can add one file at a time or multiple with either of:
$ git add part1.txt $ git add part1.txt part2.txt
Make sure that you are in the [USERNAME]-LAB5 directory when doing so.
Next, we will commit the files, which makes a local backup. Commits require messages attached to them, which are viewable later. We recommend using detailed commit messages as this will greatly help when trying to look through commits later. For lab 8, we recommend your team come up with a convention for naming commits. Feel free to ask the instructors for ideas. For now, we can use a simple message:
$ git commit -m "Completed part1 and part2 of lab5"
Lastly, you can push this commit to GitHub. It is always a good idea to make sure that you have all the files and changes you need before pushing, because making corrections after pushing is very difficult. After you are sure that everything is in order, push using:
$ git push
You should receive a message similar to the one below, and you can also check that your files are on GitHub through the GitHub website by navigating to your lab5 repo. You can also check with the instructors to verify that your answers are submitted properly.