=============================== = Lec-4-HW-3-LC3-ifetch =============================== The prior two exercises got the LC3's first state of the instruction-fetch phase working. The remaining two states of this phase are state-33 and state-35, in which the MDR and IR are loaded with the next instruction to be executed. This exercise is to complete the instruction fetch phase. At this point you should be able to write your own test bench code to observe specific signals in the LC3. You will be introduced to a test bench that provides information after each state change of the controller. This information includes the simulation time, the controller's state, and the contents of all registers, including the PC, MAR, MDR, IR, and PSR (and the CC bits of the IR). As before, refer to docs for state information, and refer to Lec-4 lecture notes for operations and wire paths, as well as state information and control signals. The first step is to verify that there are connected paths between the bus interface (MDR and MAR) and the memory unit on the Memory-IO bus, and between the MDR and the IR. The Memory-IO bus consists of three parts: (1) the address bus, (2) the data bus, and (3) the control bus. The output of the MAR must be connected to the address input of the memory unit for the memory to know which cell to access. This is done via the address bus. 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, and consists of three bits of information: one bit indicates that the address on the address bus is within the range of addresses handled by the memory unit; one bit lets the memory unit know that the controller is interested in doing a Memory-IO operation; and one bit indicates whether it is a read or a write. 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 except have a wire/bus path from the address bus to its address inputs. 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 a signal isMemoryAddress = 1 and otherwise that signal will be 0. 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 this by setting the control signal, MIO_EN = 1. The controller also indicates the type of operation by setting R_W (0 for read, 1 for write) So, 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) go between the BusLogic unit and the controller, uSeq. For clarity, BusLogic translates the combination into two separate control bus signals, MIO_R (1 for MIO = 1 and R_W = 0, 0 otherwise) MIO_W (1 for MIO = 1 and R_W = 1, 0 otherwise) 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 sends back its own "ready" signal. These signals are combined into one control bus signal "MIO_READY", and passed back to the controller via BusLogic as the "R" signal. When the correct data becomes available at the data output of the memory unit, the memory unit's data output must be connected to the MDR. It is easier to connect them continously until the operation completes successfully and continuously clock 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. Now that the instruction (the 16-bits of the cell referenced by the MAR) is in the MDR, those bits need to be sent to the IR. The MDR must be connected to sys_bus, its tri-state activated, and the IR have its LD_IR write-enable signal activated for state-35. The instruction will then be in the IR when the controller is in state-32 "instruction decode" where it can decide what to do next depending on the instruction's opcode bits. TESTING Use your own testbench code to display the values of any signals you need to see. Use names on wires for this. CAVEAT: if you name a bus, be sure to indicate its size, e.g., MDR_in[15:0]; otherwise your bus signals will be disconnected. You can also use test.jelib:top_rtl_testInstr. It has display code for all registers. It will be somewhat useless to use this code unless there is some instruction in the LC3's memory that is not all zeroes, as the LC3's hardware sets all registers (except the PC and PSR) to all zero bits at system startup, including the memory content. You won't be able to tell whether a memory read operation sent the correct bits to the MDR if the bits are all zero both before and after the operation. (Of course, you can see that something went completely wrong if you get "x" or "z" for bit values.) The verilog code in top_rtl_testInstr includes code to initialize memory: top.mem.data[ 16'h0200] = 16'b0001010111000101; This will put 16 bits "0001010111000101" into the memory cell at address "0200" (16-bit address is expressed in hex). You can edit that code to put any instruction you want into the memory at any cell you want. Recall that the PC initially contains the address 0200 (in hex) at system startup. By the way, just to be perfeclty clear, 16'h0200 == 16'b0000001000000000 are two ways of specifying the same values of 16 bits. WHAT TO TURN IN Check in your changes to your lib/ files and any other files you created in the course of your work (excepting obviously temporary files such as "a.out" " files). Turn in a paper coversheet explaining your progress, difficulties, steps you took, the state of things, joys, angst, hopes, fears, ....