Homework 7A
What’s due & why
- Updated RISC-V design that implements additional instructions and any corresponding updates to your work from Homework 6B and 6A. As with prior assignments, your completed code needs to be submitted (via GitHub) to Gradescope. A significant portion of the grade comes from passing unit tests. (Unit tests will only include the hardware updates, not changes to the code. The code will be a part of the demo)
- Questions: The GitHub submission needs to include completed answer to the questions in
questions.md
in the repo. - An in-person demo (during office hours) is required for full credit.
Why
The goals of this assignment are to summarize and combine multiple aspects of the course:
- Continue to explore the design of computers by taking a deep look at the control and data path for a RISC-V single-cycle microarchitecture.
- Ensure everyone has another opportunity to take a digital design and generate real-world hardware that implements that design.
(Both are overall learning outcomes for the course)
Overview & Context
Now that SH Enterprises has developed a RISC-V controller for their Wonder Washer line (Homeworks 6A & 6B), they’ve run into a bit of a common engineering dilemma: Their supply chain has been disrupted by world events. In particular, the RISC-V processors they were planning to use have limited availability and are substantially more expensive than they were when the were doing R&D on the new design! This means they won’t be able to build enough Wonder Washers (their main problem) and the ones they can build will be a bit more expensive (lesser concern).
Fortunately they acquired a huge inventory of FPGAs for the original model of the Wonder Washer (i.e., Homework 4B). They considered re-designing the RISC-V Washer implementation (from Homeworks 6A and 6B) to use a HDL….but then the co-CEOs had an insight: The RISC-V processors are more expensive for everyone and SH Enterprises has a huge inventory of unused FPGAs! They may be some advantage to turning their existing inventory of FPGAs into RISC-V processors for both their needs and to potentially sell to others.
SH has tasked you to become their Director of Washing and Computing (also known as the “Director of Cleaning Computing”). They ask that you update a HDL implementation of a RISC-V processor to support instructions needed for the Washer code (from 6A and 6B). (They’re calling it “Project RISCy”) If that effort is successful, they’ll consider further updates that would allow the FPGAs to become full featured RISC-V processors, and then they can take advantage of the current market demand for RISC-V processors! (Your role is just this initial proof-of-concept processor that’s focused on the Washer from 6A & 6B)
Part 0: Setup
Link to get the repository / codespace: link
Part 1: Adding Instructions
Caution!
This is a real-world example of a significant computer engineering task. You need to have a plan rather than just opening the Verilog file and typing.
The risc-v
folder contains a Verilog implementation of a partial RISC-V processor (an implementation that corresponds to our textbook). The Edit riscvsingle.sv
task can be used to open it.
It is a single-cycle CPU and includes a full data path and the elements that control the datapath. It supports only the following instructions: lw
, sw
, add
, sub
, and
, or
, xor
, sll
, srl
, slt
, addi
, andi
, ori
, xori
, slli
, srli
, slti
, beq
, bne
, and jal
.
An analysis of the code needed for the Wonder washer highlighted two significant omissions:
- All interactions with the 7-segment displays, LEDs, and buttons, like
set_segments()
, use anli
instruction likeli t4, 0x8000
.li
is a pseudo-instruction that is converted to other instructions. Sometimes it’s replaced with a simpleaddi
, which the processor supports, but it’s often converted to anlui
or a combination of both anlui
and anaddi
. Theriscvsingle.sv
model does not currently supportlui
. - The code uses functions, which are called by either
jal
orcall
(call
is a pseudo-instruction that is translated intojal
). Fortunately the processor supportsjal
…However, code returns viajr ra
orret
, both of which are psuedo-instructions and translated into ajalr
instruction. Theriscvsingle.sv
model does not currently supportjalr
.
Part 1.1: Process and lui
- Start with:
- a diagram of the single-cycle CPU:
(Figure 7.15 from Digital Design and Computer Architecture, RISC-V Edition by Harris & Harris)
-
Review
lui
, its meaning/behavior (also referred to as its “semantics”), and its format in Figure B.1 and Table B.1. In particular the last column (Operation) gives a precise description of how the instruction impacts the machine state. -
You’ll also need to understand how various parts of this CPU implementation that aren’t fully described in the diagram behave. The parts that aren’t shown in the diagram are the ALU (Table 7.3, page 409) and the Extend unit (Table 7.5, page 412).
-
Develop a plan for how the existing design can be modified to support
lui
and annotate it on the diagram. It may help to re-read/review 7.3 of the text.Caution!
If you come to office hours or need help on this part, the first question will be “show us your diagram”. We will need to know what you want to do before we can help.
-
Code review: The HDL model in
riscvsingle.sv
represents a significant part of a RISC-V CPU. It contains a hierarchy of multiple modules. At the top of that hierarchy is theriscvsingle
module. It contains the two major aspects of a simple CPU: acontroller
, which decodes instructions, and configures the other element, thedatapath
. As the name implies, thedatapath
encompasses all the components that process data.- Review the various modules in
riscvsingle.sv
and update your diagram with details about which modules correspond to which parts of the diagram. For example, there are actually two Verilog modules that correspond to the Control Unit. Also, look carefully for the types of signals that are important for your approach to supportinglui
.
- Review the various modules in
- Identify a plan to update
riscvsingle.sv
to supportlui
(there are multiple valid approaches). Updateriscvsingle
and check your work with the provided testbenches.-
RISC-V lui Testbench
(risc-v-lui-tb.sv
): This tests a few variations oflui
instructions and confirms that machine state is altered in expected ways. It also includes some checks to confirm it’s not altered in unexpected ways. This will help test that yourlui
works without consideration for other instructions. If successful, thePROBLEMS
panel will show an entry forrisc-v-lui-tb.sv
that says “All tests passed!”. If not successful, it will contain some details about the specific instruction that failed. As usual, you can use the waveform views to try to better understand errors.
-
Part 1.2: jalr
Repeat the steps/process described above to add support for the jalr
instruction. You can use the RISC-V jalr Testbench
(risc-v-jalr-tb
) to confirm that your implementation seems to behave correctly for a few test cases.
More Testing
The prior test benches only help confirm that execution of the new instructions themselves may be ok. Often making changes can have side-effects that break things that worked before. RISC-V general Testbench
(risc-v-gen-tb
) tries nearly all instructions once, including the lui
and jalr
. It isn’t a very rigorous test, but it will help confirm that changes probably didn’t interfere with the behavior of other instructions. If successful, the PROBLEMS
panel will show an entry for risc-v-gen-tb.sv
that says “All (252) test passed!”.
RISC-V Program Testbench
(risc-v-prog-tb
) runs a full program that test many, but not all, instructions (it does not test jalr
). If successful, it will show Simulation succeeded!
in the Problems
tab.
Debugging the Data Path
The waveform view allows you to see the step-by-step execution of a program and look at all components of device under test (that is, the CPU). Here’s an example of using waveforms to understand what’s going on:
Do-overs
You may find that you want to Revert your changes if things aren’t working out. You can easily retrieve the original code via git
or GitHub. Here are two approaches:
- Go to the repository on GitHub.com, click on the file of interest, then click on the
History
button, and finally select a specific version to view (if you haven’t pushed updates to GitHub, only the original version will be shown). You can copy/paste the code as needed. - Right-click on a file in the CodeSpace file explorer and select
Open Timeline
. ATIMELINE
view will be shown in the explorer panes and you can select an older version of the work, which will be compared with the current version. The timeline includes bothgit
commits and the times the file has been saved since you opened the Codespace session.
Part 2: Code
Caution!
Our processor is small, and limited. You may have to adjust your code to conform to the limitations:
- It only supports
lw
,sw
,add
,sub
,and
,or
,xor
,sll
,srl
,slt
,addi
,andi
,ori
,xori
,slli
,srli
,slti
,beq
,bne
,jal
, and (now)lui
andjalr
. Check that the generated ROM only contains these instructions.- Pseudo-instructions that are converted to the supported instructions can be used in your source assembly language. For example,
li
is ususally converted to a combination ofaddi
and/orlui
,call
is often converted tojal
, etc.
- Pseudo-instructions that are converted to the supported instructions can be used in your source assembly language. For example,
- It does not support using
.data
(for global variables) at all. - It is limited to 2047 words of RAM.
- The ROM is limited to about 500 words (500 instructions!)
Part 2.1: delay()
(with more accuracy)
The delay.s
(Edit delay.s
) is mostly empty. You should start by copying your delay()
code from prior assignments. However, we now have a single-cycle processor that operates on a clock cycle of 6 MHz. That is much, much faster than the simulator and will be pretty consistent. Consequently, you can come up with a pretty precise formula for how many instructions would execute in a given time. Update your code to work with this new clock cycle. Of course, you are limited on the instructions you can use (no div
or mul
). Update your implementation of delay()
so that it will be within about 10% accuracy (you can assume it’ll only be used on values >100ms). Be sure to heed the warnings above!
The Simulate delay.s
task will loop through showing the numbers 1, calling delay(1)
, 2, calling delay(2)
, and 5, calling delay(5)
. Instructions in the simulator are much slower than on the real processor, so it is being called with 1/1000th of the time that will be used on hardware. The simulator can be used to quickly check if your code has syntax errors and if the times are roughly the right proportions (2 is twice as long as 1), but it will be much much slower than the hardware!
Once you feel that your code is correct, you can convert it to a “ROM” suitable for your hardware via the Convert delay.s+driver for iCE40 ROM
task. The resulting file includes both some driving code (first) and your delay()
’s code. Review the details of the ROM to confirm that it meets the above requirements! (That is, not using unsupported instructions, not using anything in .data
, and not too long)
Finally, you can use the RISC-V+delay.s bitstream
to create a file to program your FPGA. This design is more complex than prior designs, so this process will take longer!
Part 2.2: Re-spinner()
ing
Edit spinner.s
can be used to edit a empty version of the spinner()
function. As before, paste in your code from prior assignments. The simulated version of the spinner will iterate through two examples. It uses your delay()
function with delays of 1
and 2
, which may still be very slow. You can use the Convert spinner.s+driver for iCE40 ROM
task to convert it to machine code. As before, make sure your code meets the requirements.
Once done, you can use the RISC-V+spinner bitstream
task to convert it for programming the FPGA.
Part 2.3: Wonder Washout
Once the prior two parts work on the hardware, it’s time to try the complete washer state machine! Again, use Edit washer.s
to add your prior work and review the requirements, making any updates that may be needed.
Caution!
Note: A Simulate
task is provided, but it will probably use times in spinner()
that are way too large for the simulate environment. If you use the simulator for any testing you may need to adjust your delay
or the times used in spinner()
.
The Convert washer.s+driver for iCE40 ROM
can be used to view the machine code, which will include a driver function, your delay()
, spinner()
and washcycle()
. The RISC-V+washer.s bitstream
can be used to prepare it for the FPGA. It will use hardware as follows:
And a demo:
Part 3: questions.md
As in past assignments, complete the questions in questions.md
.
Submission
As with Homework 6A, you will need to commit and push work to GitHub and then go to Gradescope to “pull” the work over.
For full credit you also need to do an in-person demo during Office hours. You should bring any diagrams/notes about how you modified the CPU to support lui
and jalr
and be prepared to discuss your work.
- Submission Link: Gradescope