next up previous
Next: About this document ...

CSE467 -- Advanced Digital Logic
Lab 6 -- Decoding and Control FSM
Design review in your lab the week of November 16th
Design due Wednesday November 25th

Overview After Lab 5, the only remaining design tasks for your processor are the instruction decoding logic and the control finite state machine. There are still a few logistical tasks (place and routing the FPGA, writing test programs, downloading and uploading memory from the PC), But with the addition of some decode logic and a control state machine, your processor should be able to process! This week's lab is basically to finish off the design of the whole machine and have it simulating code by the final design check off. With any luck, the code that it is simulating might even be generated from the cr16 assembler.

Control Flow  

Now that you have a datapath that is capable of executing all the instructions in your instruction set, you need to think about what's involved in actually executing each instruction. Since we are not building a pipelined machine, the execution model is pretty simple. Basically your control needs to sequence some actions in the machine that will result in the instruction being executed.

Instruction Fetch:
Before you can execute an instruction, you need to fetch it from memory. Think about what this involves. First you have to get the current PC value into the MAR. Then you read from the SRAM (set the WE and OE signals appropriately). The returned data should then be transferred into the instruction register The result of this sequence of actions is that you fetch the next instruction into the instruction register so you now know which instruction you are about to execute.

Instruction Decode:
In this phase of execution you use the information in the instruction register to set up all the state in the control path that you need to execute the instruction. This may or may not involve a separate clock phase depending on how your datapath is arranged. Things that get decoded include: mux settings, register file addressing, immediate fields (including sign extension), and register enables.

Instruction Execution:
Now that everything is set up by the instruction decode logic, you can execute the instruction. In this non-pipelined case this simply means allowing the correct data to go through the datapath and compute a result. Make sure you understand each and every instruction. Note that loads and stores may require some extra work here because you need a bus cycle to execute the load or store. Also note that a PC operation must be performed somewhere. If the instruction is not a branch or jump, the PC needs to be incremented by one 16-bit word. If it is a taken branch, then the PC must be added to a signed offset from the instruction, and if it's a jump, the PC must be loaded from a register. If it's a jump-and-link, then the incremented PC must be stored in a register. Remember to get the details of JAL right! It's a tricky instruction.

Writeback to the Register File:
Once the answer is computed for that instruction, you need, in most cases, to write back the answer to the register file. Presumably you have already set up all the relevant information in the datapath (like destination addresses and mux settings), so this is probably nothing more than enabling the register file to do a write on the next cycle.

This cycle then repeats itself for each new instruction.

Instruction Decoding Logic

The main things that the instruction decode logic does are to pick out the fields of the instruction word that are important, and to use combinational logic to generate datapath control signals from those fields. Some are easy. For example, the src and dst register addresses should always be in the same place in the instruction word. These fields of the instruction register can be wired directly to the address inputs of your register file.

Some are a little trickier. There are at least three different immediate formats: immediate ALU operations, branch offsets, and load/store offsets. Each of these need to be extracted from the instruction word (they're all in different places in the instruction word), sign-extended, and routed to the ALU through muxing of some sort. Still, that's not much more than wiring copies of sign bits to various mux inputs.

Another piece of the instruction decoder looks at the opcode information and uses that to decide how to set the other control bits of the data path. For example, on a MOVW instruction, the datapath muxes should be set to allow the src register to be written back without modification to the destination register. This might involve mux settings, it might involve tri-state enable signals, it might also involve function code bits to set the ALU function to pass a value through unmodified. The form of this logic is opcodes as input (from the instruction register), and datapath control bits as outputs (mux selects, function codes, etc). There are lots of ways to generate this logic (i.e. espresso, misII, ABEL, K-maps, etc).

Finite State Machine Controller

The finite state machine simply sequences actions that are already set up by the instruction decode logic. For example, in the cycle description in Section [*] you start by doing an instruction fetch. This means that you have to select the PC to the MAR (this is independent of the old instruction already in the instruction register so this is a bit of logic that depends both on the decode and on the state machine outputs), do a read cycle, and transfer the data to the instruction register (enabling the instruction register to latch on the next clock edge). Note that most of these actions involve enabling certain things to happen. These enable signals are outputs from your state machine.

The instruction fetch part of your state machine is the same for any instruction. Once you fetch the instruction, you may have to have the state machine do something different depending on which instruction is being executed. Most instructions will be pretty similar since most of the datapath control points will have already been set up by the decode logic. What is left for your state machine to do is probably just enable the register file to write on the next clock. On the other hand, some instructions will be different. On a load, for example, you will have to compute the address to load from, put that address into the MAR, do a read cycle to memory , and transfer that data into the register file (enable the RF to write on the next clock). A store is also a strange one. You need to compute the address and put it in the MAR, and also compute the data to store and put that into the MDR. This can be done sequentially, or if you're clever and your datapath is set up right you can do it all at once. Then you do a write cycle on the bus (which means enabling the data and address to drive the bus at the right time, and setting the control signals for a write). Make sure you understand the needs of each and every instruction before you design the state machine. For your state machine you can use the FSM editor in the Foundation tools, or you can write ABEL code by hand.

What to do

Finish the machine to the point where you can simulate running code. Note that we don't yet have a simulation model of the UART (and might not have one...) so the program that you simulate should be loaded into your machine's memory (either RAM, ROM or both) using simulator commands. More on the simulator's memory model later. In the meantime you can read the documentation on the memory models in the simulator using the on-line help system.

During the preliminary checkoff I would like to see schematics of the decoder and state machine as far along as you have, and a design for anything that you haven't built yet. Simulations of pieces of the circuits should also be shown. Treat this as a design review to make sure you are headed in the right direction.

For the final checkoff I would like to see evidence that the machine is actually running code in simulation. You will need to write test programs that test that your machine is actually running code correctly. This means you need to think about what types of instruction sequences really test the processor. At the very least you should execute every instruction in the instruction set and make sure each one does the right thing. The simulation should model both the FPGA processor and also the memory that is on the Xess board. You can use Viewsim commands to supply the clock and reset, and to load the instructions into memory, but then the simulation should just run on its own. Instructions should be fetched from memory, executed, and, in the case of stores be loaded back into the memory all as part of the simulation.

Part of having the simulation running code is to put all the infrastructure around your processor that is needed by the FPGA tools. The simulation should behave as though the processor is actually in the FPGA (or FPGAs). That is, it should communicate only with the pins of the FPGA. You shouldn't use the simulator to drive internal signals directly in the simulation. This also means putting all the external signals on pads (note that the memory pads are already included in the XSRAMX32 macro, so the pads you need to worry about are the LED pins and the parallel port pins to and from the PC), and assigning pin locations for each of the pads that you use. For the final checkoff I'd like to see that every group has run the FPGA place and route tools at least once.



 
next up previous
Next: About this document ...
Erik Brunvand
1998-10-25