============================= = Lec-4-HW-2-LC3-instructionFetch ============================= You have seen the three states of the instruction-fetch phase of instruction execution. The three controller states accomplish the following: (state-18) increment the PC and copy the content of the PC to the MAR, simultaneously; (state-33) copy the memory's output to the MDR, repeating until the signal R=1 indicates the memory unit finished the read operation; (state-35) copy the MDR content to the IR. (See LC3-PPappendC.pdf and LC3-ControlStates.txt in docs/.) The global clock signal, "sys_clk", triggers a register to accept the data on its input and propagate it to its output. This is called a register write, and it overwrites the data that was in the register before the clock pulse arrived. Of course, the register's write-enable signal must be 1'b1 for this to occur. Your job in this assignment is to trace instruction fetch operations. If you haven't already, get an up-to-date copy of the library files from projects/LC3-trunk/lib/, and put them in your branch's lib/. You will also be using the verilog file, "top_rtl_testInstr.v", which you will generate yourself from test.jelib:top_rtl_testInstr{sch}. Using Electric, open the "top" cell in the "system.jelib" library. (My notation is "system.jelib:top{sch}".) Investigate the wire and bus connections on which signals will propate during instruction-fetch. You will identify each bus/wire connection path involved. Then you will add verilog code to test.jelib:top_rtl_testInstr{sch} and generate a new simulation/top_rtl_testInstr.v file. The code you will add will be of the form shown in this example, always @( top.PCout ) begin $write("=====(t=%0d)===", $time ); $display("===PCout=%b===", top.PCout); end That bus, "PCout", happens to be the bus connected to the output of the PC in system:top. This will display the signal value on that bus at any time it changes. (Note that for signals you do not give a name to, Electric gives a default name, such as "net@375". When Electric generates verilog code, that will be changed to "net_375" to avoid verilog syntax problems.) That example will allow you to see the last part of the PC <== PC+1 operation in state 18, just after the clock signal causes a write to the PC. You are to add other such statements until you can trace out the entire signal propagation path for that register- transfer operation, including the input and output of devices along the path such as the "plus1" device. In similar fashion, add verilog code so you can trace out the other register-transfer operations that occur in the other states of instruction-fetch phase. The LC3's controller, aka its "micro-sequencer", has instance name "uSeq", and is an instance of the cell uControl.jelib:uSeq{sch}. All control signals come from uSeq. You should also have output statements for the required control signals along your register-transfer path. You will see that all control signals, wires or busses, are named the same as uSeq's output ports. E.g., LD_PC is the name of the wire attached to the PC's write-enable input. Verilog code to display that signal would be, always @( LD_PC ) begin $write("--(t=%0d)---", $time ); $display("-LD_PC=%b---", top.LD_PC); end You will get docs/LC3-uArch-ControlStates.txt. It has, in text, a representation of the complete controller state diagram from PP's appendix C. Each state shows register-transfer language (RTL) for what needs to be done in that state. Fill in for each relevant state the values of all control signals along your register-transfer paths. If you prefer, you can print a copy of docs/LC3-PP-Append-C.pdf and annotate the controller's state diagram instead. WHAT TO TURN IN: Turn in a cover sheet. In your comments section, explain generally how you went about the task assigned. Attach your verilog code output, annotated with comments explaining each step of each register-transfer operation. Explain each signal change and why it is occuring at that time. Also attach your version of docs/LC3-uArch-ControlStates.txt with control signal values filled in for states 18, 33, and 35. -------------------------------------------- NOTES -------------------------------------------- --- Heirarchical naming "top.PCout" names a signal in the instance "top". There is an instance of system.jelib:top{sch} in the cell test.jelib:top_rtl_testInstr{sch} That instance has the name "top". You can look at the name of an object using Edit.ObjectProperties after selecting the object. To refer to an object lower down in the hierarchy, use dot notation: "instance_name.object_name" Do not be confused by identical names: the instance has the name "top", and it is an instance of type "top". The type "top" is defined in system.jelib:top{sch}. In verilog, the instance "top" will be an instance of type "module system__top". --- Identical names Busses and wires may also have the same name as the export they are connected to. For instance, we could name "PCout" to be "out", which is also the name of the PC's output export. --- Naming busses/wires You will have to name buses/wires yourself in many cases. For instance, "net@375" is hard to remember. Seeing it mentioned in your trace output will make it difficult to identify what is going on. You can set the name of any object via Edit.ObjectProperties. --- NAMING A BUS A bus's name MUST indicate the number of wires in the bus. So, a proper name for the bus attached to PC's out export would be "PCout[15:0]". Note that Electric does not bother with that when it creates its own names, but you need to. --- Dissapearing Names in .v files When creating .v files, Electric reduces the design by trimming unnecessary wires, busses, and sometimes objects. E.g., there are several busses attached to PC's out, with names "net@375" and "net@378" and so forth. These are all connected together; so, Electric will eliminate all but one. All connections will use that remaining signal name. Usually, Electric will not eliminate a bus/wire you named. If there seem to be errors due to non-existent references in your verilog code, check the verilog output from Tools.Simulateion(Verilog).WriteVerilogDeck to see if the names you refer to in $display() statements are still present in the .v file. --- Register clocking uSeq has a system clock that runs continuously and sends pulses throughout the LC3. A clock pulse occurs when sys_clk changes from 0 to 1, which happens once every 20 simulation time ticks. The period from one 0-1 pulse to the next is a clock cycle. Most registers change state at the next clock rising edge. Some change at the next falling edge instead. Registers have a delay in propagating their input to their output when they are written. This delay is about two ticks. --- Verilog, installing instructions in memory Recall that the testbench, test.jelib:top_rtl_testInstr{sch} has verilog code to load an instruction into memory. E.g., top.mem.data[ 16'h0200] = 16'b0001010111000101; This will put 16 bits "0001010111000101" into the memory cell at address "0200" (a 16-bit address in hex notation). Recall that the PC initially contains x0200 at startup. You can edit that code to put any instruction you want into the memory at any cell you want. By the way, just to be perfeclty clear, 16'h0200 and 16'b0000001000000000 and 16'd512 are three ways of specifying the same 16-bit value. --- Memory-IO bus control signals The Memory-IO bus consists of three parts: (1) the address bus, (2) the data bus, and (3) the control bus. It has tri-state buffers to control access to the data bus and the MDR input. The output of the MAR is connected to the address input of the memory unit via the address bus so the memory knows which cell to access. The memory unit also needs to know that the controller wants the memory to respond to the address. This is done via the control bus and some additional logic attached to the address bus. There are three bits the memory unit needs: (1) a bit indicating that the address on the address bus is within the range of addresses handled by the memory unit. (Other devices may be handling some addresses.) (2) a bit that lets the memory unit know that the controller is doing a Memory-IO operation. (3) a bit indicating whether it is a read or a write. (1) As the output of the MAR is always affecting the address bus, the memory unit does not need to do anything to get the address. But, also attached to the address bus is an "address decoder". This device detects whether the address is within the range that the memory unit should respond to. If the value on the address bus is within that range, it will output the signal, isMemoryAddress = 1 and otherwise that signal will be 0. (2) Just because the address on the address bus is appropriate for the memory unit does not mean the controller is currently trying to do a memory or IO (input/output) access. The controller indicates that by setting the control signal, MIO_EN = 1. (3) The controller also indicates the type of operation by setting, R_W (0 for read, 1 for write) For instance, in state-33 the controller is trying to read and sets MIO_EN = 1 and R_W = 0. The controller then waits in state-33 until the operation is completed. The memory or IO unit that is handling the operation will send back to the controller a signal indicating it finished. This signal is, R (0 for "I am not yet finished", 1 for "All done, ready".) The two signals, MIO_EN and R_W, go from uSeq to the BusLogic unit. For clarity, the BusLogic unit translates the combination into two separate control-bus signals, one for a memory or I/O read operation, MIO_R ( == 1 if MIO = 1 and R_W = 0) and another for a memory or I/O write operation, MIO_W ( == 1 if MIO = 1 and R_W = 1) The memory unit has logic to combine the three signals, MIO_R, MIO_W, and isMemoryAddress and produces these signals, MEM_R (1 if MIO_R = 1 and isMemoryAddress = 1 ) MEM_W (1 if MIO_W = 1 and isMemoryAddress = 1 ) and uses them to activate the memory unit via its MEM_EN input. It also uses the R_W signal directly for its own R_W input. It might seem to be a wasted effort to produce the MEM_R and MEM_W signals, but there are tri-state buffers that need to be controlled and it is easier to understand their function if these signals are available. Each Memory-IO device has its own "ready" signal. These signals are combined in BusLogic into one control bus signal, MIO_READY, and passed back to the controller as the "R" signal. When the correct data becomes available at the data output of the memory unit, the memory unit's output must be connected to the MDR's input via tri-state buffers. However, it is easier to connect it continously until the operation completes successfully, continuously clocking the MDR (by setting its LD_MDR write-enable signal to 1 for state-33). Only the correct data will be present in the MDR when the controller changes to state-35.