Open-Ended Portion (70% of lab grade)

Select one of the following questions per team. The open-ended portion is worth a large fraction of the lab grade, and your grade depends on how complex and interesting your completed project is. Spend an appropriate amount of time and energy on it. Also, have fun with it!

Mix Manufacturing

The goal of this problem is to investigate how effectively (or ineffectively) the compiler might handle the complex C code you create.

Using no more than 15 lines of C code, attempt to produce RISC-V machine code with the maximum ratio of branch to non-branch instructions when run on the 5-stage processor (fully bypassed).1 In other words, try to produce as many branch instructions as possible. You can use code that emits jumps, but unconditional jump instructions do not count as branches. Your C code can contain as many poor coding practices as you like but must adhere to the following criteria:

  • Limit to one statement per line.2 Selection (if, else, switch) and iteration (for, while, do) statements each count as one statement in addition to the body.

  • Do not call functions or execute code not contained within the 15-line block.

  • Do not use inline assembly or comma operators.

  • Limit to one ternary operator (?:) per expression.

  • The code must always terminate.

To access the riscv32-unknown-elf tools, set your PATH variable:

export PATH="$PATH:/home/ff/cs152/bin/riscv-gnu-toolchain/riscv32/bin"

Write your code in ${CHIPYARDROOT}/generators/riscv-sodor/test/custom-bmarks/mix.c. To test for correctness, compile and run it on the functional ISA simulator:

cd ${CHIPYARDROOT}/generators/riscv-sodor/test/custom-bmarks
make CC="riscv32-unknown-elf-gcc -march=rv32i_zicsr -mabi=ilp32"
make run

To produce a disassembly of the code:

make dump

However, to obtain a cycle-accurate trace to determine the actual effect of your program on CPI, you must run the code on the RV32 5-stage processor (fully bypassed):

cd ${CHIPYARDROOT}/sims/verilator
CUSTOM_BMARKS=${CHIPYARDROOT}/generators/riscv-sodor/test/custom-bmarks
make CONFIG=Sodor5StageConfig run-binary BINARY=${CUSTOM_BMARKS}/mix.riscv

Analyze output/chipyard.TestHarness.Sodor5StageConfig/mix.out with the tracer.py script and report the ratio of branch to non-branch instructions achieved with your code. What is the resulting CPI? As more branches were added, did the CPI increase or decrease? Explain why the CPI changed in the direction that it did. In your report, summarize some of the ideas that you tried. Submit this write-up, your lines of C code, and the excerpt of the disassembly that corresponds to your C code.

Define and Implement Your Favorite Complex Instruction

In Problem Set 1, you are asked to implement two complex instructions (ADDm and STRLEN) in the microcoded processor. Imagine that you are adding a new instruction to the RISC-V ISA. Propose a new complex instruction (other than MOVN/MOVZ) that involves an EZ/NZ Br and at least one memory operand.

First, devise an encoding for your new instruction. Consult the RISC-V unprivileged ISA specification to select an appropriate instruction format (see §1.1.2 “Base Instruction Formats”), and then find an unused opcode space (see the base opcode map in §35.1 “RV32/64G Instruction Set Listings”). Note that the custom-0/1/2/3 and reserved spaces are currently available.

Define your instruction in common/instructions.scala (search for a TODO comment in the file). Use the definition of MOVN as an example:

def MOVN = BitPat("b?????????????????????????1110111")

The bit pattern specifies which bits should match a fixed value for decoding (e.g., an opcode). Note that the ? character denotes a “don’t-care” bit location that may take any value (e.g., register specifiers). Underscore _ characters are ignored. The variable identifier is used as a label for the microcode dispatcher.

Once you have assigned an instruction encoding, you will have to write an assembly test for your instruction. As an example, an assembly test for the MOVN instruction is provided in test/custom-tests/movn.S. Since the assembler is not directly aware of our custom instructions, you must numerically encode the instruction with a .word directive.3 You must also write assembly code to load values into registers and memory. Finally, your code should check the correctness of the result.

To access the riscv32-unknown-elf tools, set your PATH variable:

export PATH="$PATH:/home/ff/cs152/bin/riscv-gnu-toolchain/riscv32/bin"

Please modify the file ${CHIPYARDROOT}/generators/riscv-sodor/test/env/p/riscv_test.h by replacing the sptbr with satp on line 69.

We have provided you with an empty assembly template to complete at ${CHIPYARDROOT}/generators/riscv-sodor/test/custom-tests/yourinst.s (search for a TODO comment in the file). Compile your assembly test:

cd ${CHIPYARDROOT}/generators/riscv-sodor/test/custom-tests
make CC="riscv32-unknown-elf-gcc -march=rv32i_zicsr -mabi=ilp32"

Next, work out the microcode implementation on the worksheet provided in the Microcoding handout and used in HW1.. Once you have figured out all the states and control signals, add your microcode to rv32_ucode/microcode.scala (search for a TODO comment in the file). Again, the MOVN instruction provides an example. Once you are done, build the processor and run the assembly test:

cd ${CHIPYARDROOT}/sims/verilator
CUSTOM_TESTS=${CHIPYARDROOT}/generators/riscv-sodor/test/custom-tests
make CONFIG=SodorUCodeConfig run-binary BINARY=${CUSTOM_TESTS}/rv32ui-p-yourinst

Look at the cycle-by-cycle trace written to ${CHIPYARDROOT}/output/chipyard.harness.TestHarness.SodorUCodeConfig/rv32ui-p-yourinst.out to examine the microarchitectural state. Verify that the processor has executed your microcoded instruction correctly. Revise your implementation if necessary.

Feel free to email your TA or attend office hours if you need help understanding Chisel, the processor, or anything else regarding this problem.

Submit the following:

  • A description of your proposed instruction: what it does, its operands, and why it is useful.

  • Your encoding: which base instruction format you chose, which opcode space you used, and why. Include the BitPat you added to instructions.scala.

  • Your completed microcode worksheet and the microcode you added to microcode.scala.

  • Your assembly test and an annotated excerpt of the cycle-by-cycle trace showing your instruction executing correctly.

Processor Design

Propose your own microarchitectural modification to a 3-stage or 5-stage pipeline. Justify the motivation, cost, and overhead of your design modification by explaining which instructions are affected by the changes you propose and in what way.

You may have to draw a block diagram to clarify your proposed changes, and you will very likely have to modify the script to track specific types of instructions not previously traced. Another tactic might be to show that although some instructions are negatively affected, they do not constitute a significant portion of certain benchmarks. Feel free to be creative. Try to justify your case quantitatively, but you do not need to implement your proposed processor design.

Submit a write-up containing:

  • Your proposed modification, with a block diagram if it clarifies the change.

  • Which instructions are affected and in what way, and what the change costs in added hardware, complexity, or cycle time.

  • A quantitative estimate of the benefit. Since you are not implementing the design, base this on the traces you already collected from the unmodified processors: count how often the affected instructions occur (you will likely need to extend tracer.py to track patterns it does not currently report), assume a per-occurrence cost or saving, and estimate the resulting change in CPI.

Your Own Idea

We are also open to your own ideas. Particularly enterprising individuals can even modify the provided Chisel processors as part of a study of their own design. However, you must first consult with the professor or TAs to ensure that your idea is of sufficient merit and manageable complexity.

Feedback Portion

In order to improve the labs for the next offering of this course, we would like your feedback. Please append your feedback to your individual report for the directed portion.

  • How many hours did the directed portion take you?

  • How many hours did you spend on the open-ended portion?

  • Was this lab boring?

  • What did you learn?

  • Is there anything that you would change?

Feel free to write as much or as little as you prefer (a point will be deducted only if you leave this section completely empty).

Notes for this lab

  1. Most compiler optimizations are disabled (-O0) to make this exercise easier. ↩

  2. As defined in ISO/IEC 9899 6.8: http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1570.pdf ↩

  3. Recent versions of the GNU assembler support the more user-friendly .insn directive: https://sourceware.org/binutils/docs/as/RISC_002dV_002dFormats.html ↩