Skip to content

CS 21 25.2 Laboratory Exercise 5

Single-Cycle Processor

Overview

As mentioned in the lectures, the RISC-V single-cycle processor is a sequential circuit made up of registers, memory, multiplexers, and other combinational components.

You will be using Logisim to modify an existing single-cycle processor implementation to support other kinds of instructions.

General Instructions

For this laboratory activity, you are to work on one HOPELEx Checkpoint Item that will aid in your understanding of the RISC-V single-cycle processor.

Important Reminder

You must finish and show your working checkpoint tasks to your lab handler before the end of the laboratory period. HOPELEx checkpoint items contribute 1% to your lab grade.

At the end of the HOPELEx Checkpoints are take-home exercises called TakeHOPE items. These are not graded and will not be submitted, but will help you prepare for the HOPE.

Guided Walkthrough

Overview

A Logisim-Evolution template for a RISC-V single-cycle processor can be downloaded via the link in the previous section. This processor implementation supports the following instructions:

  • lw
  • sw
  • add
  • sub
  • and
  • or
  • slt
  • addi
  • beq
  • jal

Your lab handler will run you through the template.

Note that the ALU is incomplete, causing R-type and I-type instructions not listed above to yield incorrect results.

Walkthrough #1: Running a single instruction

Suppose we want the processor to execute the following instruction:

addi  x1, zero, 21

To do this, its machine instruction equivalent should be loaded into instruction memory.

Do this now!

Convert addi x1, zero, 21 into its machine instruction equivalent in hexadecimal. You may use Ripes to do this quickly.

Select the hand tool (Ctrl-1 or ⌘-1) and click the instmem component laid out in the circuit once for a pink circle and magnifying glass icon to appear at the center of the component.

Next, double-click the magnifying glass icon to enter into the implementation of the instmem subcircuit. You may need to scroll up to find the ROM component.

Use the hand tool to click the first top-left 00000000 word (address 0) on the ROM component–this should have the component circled in pink with the word boxed in red.

Typing hexadecimal symbols here will change the value boxed in red. Type the hexadecimal representation of addi x1, zero, 21 to make address 0 contain the said instruction.

Tip: Alternative method

Copy-pasting values can be done by instead right-clicking the ROM component, selecting Edit Contents, selecting a box to fill up, then hitting Ctrl-v or ⌘-v.

Double-click main under either the Design or Simulate tab (or hit Ctrl-Left key or ⌘-Left key) to return to the main circuit.

Do this now!

Verify that the entered machine instruction is shown as the output of the instmem component and is shown as the value of the Instr probe.

Note that the instruction addi x1, zero, 21 under PC will only take effect after the next triggering edge. Use the State tab to verify that x1 still contains the value 0.

Trace the flow of bits across the circuit and verify that the value 21 will be written to x1 when the register file is triggered.

To make the clock signal tick (i.e., make one full cycle), hit Ctrl-T or ⌘-T twice (or run Simulate > Manual Tick Full Cycle once).

Make the clock tick once, then use the State tab to verify that x1 now contains the value 21 (0x15).

Look for the PC register laid out in the circuit and verify that its current value is now 4 with the current instruction being 00000000.

Hit Ctrl-r or ⌘-r (or run the Simulate > Reset Simulation menu item once) to reset all non-ROM data back to zero. Verify that PC is once again 0 and that all registers are zeroed out.

Reset Simulation

The Reset Simulation menu option of Logisim will zero-out all register and main memory values, but not ROM values (i.e., instruction memory).

This convenience allows you to perform multiple reruns of the same program with all registers and main memory values zeroed out without having to reload the same set of machine instructions into the ROM component over and over.

Walkthrough #2: Running an entire program

Do this now!

Use Ripes to assemble the instructions below into their hexadecimal equivalents.

.text
       addi  sp, zero, 0xff0
       add   gp, zero, zero
       add   t0, zero, zero
       addi  t1, zero, 10
       addi  sp, sp, -32
loop:  beq   t0, t1, done
       lw    t2, 4(sp)
       addi  t2, t2, 10
       sw    t2, 4(sp)
       lw    t3, 8(sp)
       addi  t3, t3, 100
       sw    t3, 8(sp)
       addi  t0, t0, 1
       jal   zero, loop
done:  sub   t4, sp, zero
       not   t4, t4

Ripes version

If the locally installed Ripes on your TL machine is unable to assemble addi sp, zero, 0xff0, kindly switch to https://ripes.upd-dcs.work.

To easily load several instructions into the instruction memory component, create a .txt file as follows:

v3.0 hex words
<eight-hex symbol instruction 1>
<eight-hex symbol instruction 2>
...
<eight-hex symbol instruction n>

Memory image format

The header line v3.0 hex words should be written as is while the instructions in hex should not have 0x.

Tip: Quick conversion shell script

Supposing the output of the Ripes assembly is in assembly.txt, the following command automatically transforms the said output into its Logisim-ready form in logisim.txt:

printf "v3.0 hex words\n%s" "$(cat assembly.txt | grep "^\s" | tr -s " " | cut -d " " -f 3)" > logisim.txt

Open the instmem subcircuit, right-click the ROM component, select Load Image, then select the newly created .txt file.

After verifying that the ROM component indeed contains the correct sequence of instructions, head back to the main circuit.

While you could manually tick the clock until the execution of the last instruction to run the loaded program, it is likely more convenient to make the clock tick automatically by hitting Ctrl-g or ⌘-g (or ticking Simulate > Auto-Tick Enabled).

Clock rate

You may adjust the frequency of clock ticks via Simulate > Auto-Tick Frequency.

Using this approach, PC will eventually point to locations outside the scope of the loaded program which contains the instruction 00000000 by default–you may take this to mean that the program has finished execution.

Reset the simulation state, then run the program until its completion. Take note of the register values in particular.

Tip: State tab

You may use the State tab located at the left side of the Logisim window to examine register values without having to open up the register file.

Run the same program using Ripes and take note of its register values.

Verify that all but one register is consistent between the two sets of register values–this is because xori is not yet supported by the processor.

Self-check

xori does not appear in the assembly version of the program, but why is it present in the assembled version?

Walkthrough #3: Support for xori

Clear instruction memory and load xori x5, zero, -1 into address 0.

Clear instruction memory

You may select Clear Contents to zero-out the ROM component of instmem.

Notice that the ALUControl signal which controls the ALU does not have a valid value.

Do this now!

Zoom into the ALU component by double-clicking it with the hand tool, trace where exactly the ALU uses the ALUControl signal, and examine its purpose in the operation of the ALU.

Ensure you understand why ALUControl = 000 makes the ALU add, 001 makes it subtract, 010 makes it do AND, 011 makes it do OR, and 101 makes it do SLT.

The XOR operation is not yet supported by the ALU–there is no XOR gate in the ALU and it is not mapped to any ALUControl value.

Do this now!

Select a free ALUControl value, then modify the ALU to make it perform SrcA XOR SrcB for that particular ALUControl.

The computation for the ALUControl signal itself should also be fixed.

Do this now!

Return to the main circuit, trace where the ALUControl signal is being generated, and enter that subcircuit.

Ensure you know how priority encoders work before moving forward.

Using the ALUControl value you selected earlier, create an IsXor tunnel in the subcircuit and connect it to the correct input port of the priority encoder.

Create another IsXor tunnel, then connect it to a combinational circuit that:

  • Outputs 1 if ALUOp == 10 (base 2) and funct3 == 100 (base 2)
  • Outputs 0 otherwise

Verify that ALUControl now outputs a valid value for any xori instruction and that the resulting register values of the program loaded earlier are now consistent with those of the Ripes execution.

HOPELEx Checkpoint

Checkpoint Task: auipc

Modify the given Logisim circuit to support the U-type instruction auipc.

Ensure that all other instructions that were supported before by the template still work as intended.

You are allowed to use tunnels.

Save the resulting circuit as lab05.circ.

Demo

Show that the following code:

main:
  auipc x31, 0xf0000
  addi x1, x0, 10

loop:
  auipc x30, 0x12345
  add x31, x31, x30
  addi x1, x1, -1
  beq x1, x0, done
  beq x0, x0, loop

done:
  add x0, x0, x0

results in the following register values (with all unstated registers equal to 0x00000000):

x30 = 0x12345008
x31 = 0xa60b2050

TakeHOPE Problems

Item 1: R-type instructions

Add microarchitecture support for the following instructions:

  1. sub
  2. and
  3. or
  4. xor
  5. sll
  6. srl
  7. sra
  8. slt
  9. sltu

Item 2: I-type instructions

Add microarchitecture support for the following instructions:

  1. andi
  2. ori
  3. xori
  4. slli
  5. srli
  6. srai
  7. slti
  8. sltiu

Item 3: Branch instructions

Add microarchitecture support for the following instructions:

  1. bne
  2. bge
  3. blt
  4. bgeu
  5. bltu

Item 4: Other instructions

Add microarchitecture support for the following instructions:

  1. lui
  2. lb
  3. lbu
  4. lh
  5. lhu
  6. sb
  7. sh

Item 5: Pseudoinstructions

Turn the following pseudoinstructions into basic instructions and add microarchitecture support for them:

  1. not
  2. ble
  3. bleu
  4. bgt
  5. bgtu
  6. beqz
  7. bnez
  8. blez
  9. bgez
  10. bltz
  11. bgtz