Verilog Mode in emacs
For those who want to use a Verilog-mode in their emacs editor, read and follow the instructions in the ~hyde/elisp/ReadMe-verilog-mode file.
Exercise #1: ULTRA2 - the 16-bit Register Version
Copy the Verilog code of the (your) ULTRA computer of Lab #1 to a new file called ULTRA2.v.
Modify the new file, containing the new ULTRA2, to do the following:
A). Memory words are now 16 bits in length.
B). Expand memory to 256 words.
C). Expand the instruction length to 16 bits to allow
for several more instructions (maximum of
sixteen) (IR[0:3]), four general purpose registers, four
addressing modes and the address field (IR[8:15]).
The machine in Lab 1 was an accumulator
machine which you can think of as a machine with one general-purpose
register. Historically, many old computers (1940-50s) were accumulator
machines because registers were expensive and compiler technology was
primitive.
This new machine has four 16-bit general purpose registers, R[0], R[1], R[2] and R[3] which replace the AC. In Verilog, you declare R as a bank of registers much like we do MEM:
reg [0:15] R[0:3];and, since registers are usually on the CPU chip, we have no modeling limitations as we do with MEM - with MEM we have to use the MA and MD registers to access MEM. Therefore, in a load you could use R as follows:
#1 R[IR[4:5]] <= MD;where the 2 bits in the IR specify which R register to set.
Modify the four instructions of the old Ultra of Lab 1 to the following new form:
LOAD R[i],M loads the contents of memory word M into R[i].In this exercise, the Ultra2 still uses a MA, MD, IR and PC register but the size of each is expanded. To test your ULTRA2 design, perform the following program where PC starts at 10.
STORE R[i],M stores the contents of R[i] in memory word M.
ADD R[i],R[j],R[k] adds contents of R[j] and R[k] and places result in R[i].
JUMP M jumps to location M in memory.
3 DATA 2HAND IN
4 DATA 1
10 LOAD R1,3
11 LOAD R2,4
12 ADD R1,R1,R2
13 STORE R1,5
14 JUMP 12
Hand in Verilog code and output which demonstrates that this portion of the ULTRA2 works properly. The output should include $time, all the registers and appropriate memory locations in hex format (Use %h). Also, use a $display to show the start and identity of each instruction execution. In the Verilog code include comments for each section, e.g., //load. On the output(s), hand write comments explaining what's happening and what you are testing and why you think it is correct.
Exercise #2: Add displacement addressing to the ULTRA2.
Modify the file, containing the ULTRA2, to do the following:
Modify the LOAD, STORE and JUMP instructions to allow either direct addressing or displacement addressing depending on IR[6]. The displacement is contained in R3. A "D" at the end of the instruction signifies it uses displacement address in R3.
For example, a LoadD R1,10 means R1 <- MEM[10 + R3]. Note that this is not a permissible way to
access memory, you must use MA and MD. Semantically this is
correct, but the direct implementation is not.
To use displacement addressing, the programmer needs a way to move values into R3. If we assume that R0 always contains a 0 then a MOVE operation which transfers the contents of R[i] to R[j] (j != 0) can be accomplished by an ADD using R0 as the second or third arguement.
Add R1,R2,R0 R1 <- R2
Therefore, implement ULTRA2 to always have a zero in R0. Consider
how this impacts all instructions.
Hand in the following test with hand written comments explaining what you are doing. Output $time, all the registers and appropriate locations in MEM. Output should be in hex except for $time. Insert $display statements to write out when an instruction starts.
PC = 10
MEM[1] Data 2
MEM[2] Data 6
MEM[3] Data 11
MEM[4] Data 14
MEM[5] Data 7
MEM[10] Load R3,1
MEM[11] LoadD R2,2 // Displacement addressing
MEM[12] Add R2,R2,R2
MEM[13] Store R2,6
MEM[14] Load R0,6
MEM[15] StoreD R2,6 // Displacement addressing
MEM[16] JumpD 10 // Displacement addressing
Exercise #3: Add immediate addressing to the ULTRA2.
You may want to copy the working code of Exercise 2 to a new file.
If bit (IR[7])is a one in a LOAD or JUMP instruction, the last eight bits are not an address but an operand. The operand is in the range -128 to 127.
If immediate addressing is used in an LOAD, the operand is loaded into the register.
LoadI R1,8 R1 <- 8
If immediate addressing is used with the JUMP instruction, it means jump relative to the current instruction (PC relative).
If immediate addressing is used in LOAD or JUMP, no displacement addressing is allowed. Notice that immediate addressing in a STORE instruction is ignored.
Worry about negative numbers, i.e., when bit 8 in the instruction register is a one. What changes are needed to make negative numbers work? Assume a 2's complement number representation. You can repeat bit 8 eight times by the following Verilog notation.
{ 8{IR[8]} }
Hand in the following test with hand written comments explaining what you are doing. Output all the registers and appropriate locations in MEM. Output should be in hex except for $time. Insert $display statements to write out when an instruction starts.
PC = 10Note: your final machine should be able to correctly run the three "software"programs of all three exercises. Be careful not to destroy the features of previous exercises. You should test this and include output in your handin file to show that your final version of the Ultra2 works properly with all three programs.
MEM[10] LoadI R1,3 // Load immediate
MEM[11] Store R1,4
MEM[12] LoadI R2,-4
MEM[13] Add R2,R2,R1
MEM[14] Store R2,5
MEM[15] JumpI -2 // Jump PC relative