User Tools

Site Tools


tutorial:wtg:decoder

Instruction decoder and controller

An Instruction Decoder is a circuit that processors implement in order to interpret instructions coming from memory. In synchronous designs, this circuit feeds the appropriate operands into the datapath of the processor, according to the instruction. Additionally, it must communicate with a Controller, whose role is to direct the flow of the execution at every stage of the pipeline.

In this exercise we are interested in implementing the instruction decoder and controller for a small asynchronous processor. While these are often different circuits, in this case the simplicity of the processor allows us to incorporate all the functionality into a single module. From now on, in this exercise, we will refer to this combined module simply as Decoder.

The following figure shows a block diagram of the relevant processor modules.

tutorial:wtg:instruction_decoder-diagram.svg

The diagram contains 6 blocks. Your task is to implement the block labelled as DEC. All the input and output signals for DEC are colored in red and blue, respectively. Signals in black do not interact with DEC and are shown only to provide context.

The different modules operate in the following way:

  • The instruction controller INST loads an instruction from memory and sets it into the instruction bus. When the bus is stabilised, it initiates a decoding request by firing the signal dec. After the instruction has been executed, as indicated by the dec_ack signal, this module requests a new address from the IPC module and loads it from memory.
  • The data memory DATA MEM has an address port @ obtained directly from the instruction bus. It supports two types of operations, read and write, that are requested with the signals mr and mw, respectively. After a read operation is finished, DATA MEM will set the memory value from the address in @ into the read port r and enable mr_ack. Write operations are similarly handled with the signals mw and mw_ack. In this case, the data to write must be stable before mw is enabled.
  • The register block REG contains a small number of registers that can store values to perform arithmetic operations. It contains two read ports, a and b, and one write port d. Like in the case of DATA MEM, the port addresses are obtained directly from the instruction bus. The signals rgr and rgw are used to request read and write operations, respectively. The signals rgr_ack and rgw_ack acknowledge these operations in the same way as in the DATA MEM module.
  • The ALU module performs arithmetic operations. It decides what operation to execute according to the op port that comes from the instruction bus. It has three ports for its operands: imm, a and b. The first port allows the ALU to obtain values directly from the instruction bus, while a and b must be read from the register. The signal alu informs the ALU that the operands are set and an operation can take place. The result of this operation is placed in the output port d. After an operation is complete, the signal alu_ack is enabled. Furthermore, a signal z is enabled if the result of the operation was zero. This value is guaranteed to remain stable until after the following operation is requested.
  • The IPC module stands for Instruction Process Counter, and its role is to keep track of the address for the instruction memory. In general, it keeps a copy of the last address loaded and increases it by one when the instruction controller requests a new address. It is also possible to request the module to add an offset different than one to the next address by enabling the signal jmp. The offset is obtained from the port imp_ofs directly from the instruction bus.

The processor implements four instructions that must be decoded and controlled by DEC:

  • Arithmetic operation. Performs an arithmetic operation and stores the result in the register. Corresponds to the code op0 = 0, op1 = 0.
  • Branch operation. If the result of the last arithmetic operation is a 0, adds an offset into the next instruction address. Corresponds to the code op0 = 0, op1 = 1.
  • Load from memory. Reads from memory and stores the value into the register. Corresponds to the code op0 = 1, op1 = 0.
  • Store in memory. Stores a value from the register into memory. Corresponds to the code op0 = 1, op1 = 1.

Exercise 1: Arithmetic Instructions

The first instruction you have to implement is the arithmetic instruction. But before that, it is always a good idea with WTG to first set the basic structure of the controller. This not only makes it easier to approach the problem, but also allows Workcraft to infer signal values when possible.

Let us first define the initialization and leave a waveform for every instruction. Remember to rename every waveform with the instruction it intends to solve.

Detailed instructions

The WTG should look similar to the following figure.

tutorial:wtg:instruction_decoder-wtg_structure.svg

You can now implement the arithmetic instruction controller.

Detailed instructions

The implementation for the first signal can be seen in the next figure.

tutorial:wtg:instruction_decoder-arithmetic.svg

Exercise 2: Branch Instructions

The next instruction we will implement is the branching instruction. This instruction allows the processor to alter the execution flow depending on logic conditions. Any operation performed in the ALU will set the signal z to high if the result was zero. It will set low otherwise. By using this signal we can determine whether to branch or not.

This instruction will need to use guards. Implement structure of the WTG for the branch instruction and the common waveform before the guard. Keep in mind that z has to be initialized in a similar way to op0 and op1. The value of this signal is only relevant to the branch operation, so it should remain unstable in every waveform and become stable when we need it.

Detailed instructions

The resulting WTG can be seen in the following figure.

tutorial:wtg:instruction_decoder-branch_structure.svg

The simplest scenario occurs when z is low. In this case, there is nothing to do and DEC immediately acknowledges the instruction after the decoding request. Implement the waveform for this scenario.

Detailed instructions

You can see the implementation of no_jmp in the following figure.

tutorial:wtg:instruction_decoder-branch_no_jmp.svg

Finally, implement the last waveform for the branch instruction.

Detailed instructions

The next figure shows a complete implementation of the branch instruction.

tutorial:wtg:instruction_decoder-branch.svg

Exercise 3: Simplify the model

By looking at our current design, you can observe that the instructions always finish in the same way. This is due to the protocol between DEC and INST. In this exercise, your task is to identify the common parts and create a new waveform called instruction_finished that produces the necessary transitions between completing an instruction and waiting for the next.

Detailed instructions

The simplified WTG can be seen in the next figure.

tutorial:wtg:instruction_decoder-simplified.svg

Exercise 4: Load and Store Instructions

The remaining instructions have to access the DATA MEM module for read and write operations. This module uses a similar handshake protocol to the REG module. Complete the DEC module by adding the Load and Store operations to the WTG.

This exercise intentionally lacks detailed instructions to encourage working on it independnetly. You can compare your solution to the complete WTG of the decoder: instruction_decoder.wtg.work (21 KiB)

Solutions

Download all the Workcraft models discussed in this tutorial here:

All instruction decoder WTGs (149 KiB)