Beef up add walkthrough
This commit is contained in:
parent
27b7c0556e
commit
8bb3c892a1
2 changed files with 65 additions and 16 deletions
72
exercise.org
72
exercise.org
|
@ -8,12 +8,22 @@
|
||||||
This is done by inserting 4 NOP instructions inbetween each source instruction,
|
This is done by inserting 4 NOP instructions inbetween each source instruction,
|
||||||
enabling us to use the same tests for both exercise 1 and 2.
|
enabling us to use the same tests for both exercise 1 and 2.
|
||||||
|
|
||||||
|
|
||||||
In the project skeleton files ([[./src/main/scala/][Found here]]) you can see that a lot of code has
|
In the project skeleton files ([[./src/main/scala/][Found here]]) you can see that a lot of code has
|
||||||
already been provided.
|
already been provided, which can make it difficult to get started.
|
||||||
|
Hopefully this document can help clear up at least some of the confusion.
|
||||||
|
First an overview of what you are designing is presented, followed by a walk-through
|
||||||
|
for getting the most basic instructions to work.
|
||||||
|
|
||||||
Before going further it is useful to get an overview of what is provided out
|
In order to orient yourself you first need a map, thus a high level overview of the
|
||||||
of the box.
|
processor you're going to design is showed underneath:
|
||||||
|
Keep in mind that this is just a high level sketch, omitting many details as well
|
||||||
|
entire features (for instance branch logic)
|
||||||
|
|
||||||
|
#+CAPTION: A very high level processor schematic. Registers, Instruction and data memory are already implemented.
|
||||||
|
[[./Images/FiveStage.png]]
|
||||||
|
|
||||||
|
Now that you have an idea of what you're building it is time to take inventory of
|
||||||
|
the files included in the skeleton, and what, if anything should be added.
|
||||||
|
|
||||||
+ [[./src/main/scala/Tile.scala]]
|
+ [[./src/main/scala/Tile.scala]]
|
||||||
This is the top level module for the system as a whole. This is where the test
|
This is the top level module for the system as a whole. This is where the test
|
||||||
|
@ -26,7 +36,11 @@
|
||||||
should be declared and wired together.
|
should be declared and wired together.
|
||||||
Some of these modules have already been declared in order to wire up the
|
Some of these modules have already been declared in order to wire up the
|
||||||
debugging logic for your test harness.
|
debugging logic for your test harness.
|
||||||
|
This file corresponds to the high-level overview in its entirety.
|
||||||
*This module is intended to be further fleshed out by you.*
|
*This module is intended to be further fleshed out by you.*
|
||||||
|
As you work with this module, try keeping logic to a minimum to help readability.
|
||||||
|
If you end up with a lot of signal select logic, consider moving that to a separate
|
||||||
|
module.
|
||||||
|
|
||||||
+ [[./src/main/scala/IF.scala]]
|
+ [[./src/main/scala/IF.scala]]
|
||||||
This is the instruction fetch stage.
|
This is the instruction fetch stage.
|
||||||
|
@ -94,10 +108,11 @@
|
||||||
of these settings can be quite useful to alter.
|
of these settings can be quite useful to alter.
|
||||||
The main attraction is the test options. By altering the verbosity settings you
|
The main attraction is the test options. By altering the verbosity settings you
|
||||||
may change what is output.
|
may change what is output.
|
||||||
The settings are
|
The settings are:
|
||||||
|
|
||||||
+ printIfSuccessful
|
+ printIfSuccessful
|
||||||
Enables logging on tests that succeed
|
Enables logging on tests that succeed.
|
||||||
|
You typically want this turned off, at least for the full test runner.
|
||||||
|
|
||||||
+ printErrors
|
+ printErrors
|
||||||
Enables logging of errors. You obviously want this one on, at least on the single
|
Enables logging of errors. You obviously want this one on, at least on the single
|
||||||
|
@ -148,6 +163,12 @@
|
||||||
should make it clear how the already finished modules fit into the grander design,
|
should make it clear how the already finished modules fit into the grander design,
|
||||||
making the skeleton-code less mysterious.
|
making the skeleton-code less mysterious.
|
||||||
|
|
||||||
|
To give you an idea of how a drill down looks like, here is my sketch of the ID stage:
|
||||||
|
#+CAPTION: Instruction decode stage, showing the various signals.
|
||||||
|
[[./Images/IDstage.png]]
|
||||||
|
|
||||||
|
I would generally advice to do these on paper, but don't half-ass them.
|
||||||
|
|
||||||
|
|
||||||
** Adding numbers
|
** Adding numbers
|
||||||
In order to get started designing your processor the following steps guide you to
|
In order to get started designing your processor the following steps guide you to
|
||||||
|
@ -174,11 +195,11 @@
|
||||||
|
|
||||||
**** Step ¾:
|
**** Step ¾:
|
||||||
In your console, type ~testOnly FiveStage.SingleTest~ to run only the tests that you
|
In your console, type ~testOnly FiveStage.SingleTest~ to run only the tests that you
|
||||||
have defined in the [[./src/test/scala/Manifest.scala][test manifest]] (currently set to ~"forward2.s"~).
|
have defined in the [[./src/test/scala/Manifest.scala][test manifest]] (currently set to ~forward2.s~).
|
||||||
|
|
||||||
As you will first implement addition you should change this to the [[./src/test/resources/tests/basic/immediate/addi.s][add immediate test]].
|
As you will first implement addition you should change this to the [[./src/test/resources/tests/basic/immediate/addi.s][add immediate test]].
|
||||||
Luckily you do not have to deal with file paths, simply changing ~"forward2.s"~ to
|
Luckily you do not have to deal with file paths, simply changing ~forward2.s~ to
|
||||||
~"addi.s"~ suffices.
|
~addi.s~ suffices.
|
||||||
|
|
||||||
Ensure that the addi test is run by repeating the ~testOnly FiveStage.SingleTest~
|
Ensure that the addi test is run by repeating the ~testOnly FiveStage.SingleTest~
|
||||||
command.
|
command.
|
||||||
|
@ -188,7 +209,7 @@
|
||||||
In [[./src/test/main/IF.scala]] you can see that the IMEM module is already set to fetch
|
In [[./src/test/main/IF.scala]] you can see that the IMEM module is already set to fetch
|
||||||
the current program counter address (line 41), however since the current PC is stuck
|
the current program counter address (line 41), however since the current PC is stuck
|
||||||
at 0 it will fetch the same instruction over and over. Rectify this by commenting in
|
at 0 it will fetch the same instruction over and over. Rectify this by commenting in
|
||||||
~// PC := PC + 4.U~ at line 43.
|
~// PC := PC + 4.U~ at line 48.
|
||||||
You can now verify that your design fetches new instructions each cycle by running
|
You can now verify that your design fetches new instructions each cycle by running
|
||||||
the test as in the previous step.
|
the test as in the previous step.
|
||||||
|
|
||||||
|
@ -207,10 +228,10 @@
|
||||||
Next you need to ensure that the registers and decoder gets the relevant data from the
|
Next you need to ensure that the registers and decoder gets the relevant data from the
|
||||||
instruction.
|
instruction.
|
||||||
|
|
||||||
This is made more convenient by the fact that `Instruction` is a class, allowing you
|
This is made more convenient by the fact that ~Instruction~ is a class, allowing you
|
||||||
to access methods defined on it.
|
to access methods defined on it.
|
||||||
Keep in mind that it is only a class at compile and synthesis time, it will be
|
Keep in mind that it is only a class during compile and build time, it will be
|
||||||
indistinguishable from a regular ~UIint(32.W)~ in your finished circuit.
|
indistinguishable from a regular ~UInt(32.W)~ in your finished circuit.
|
||||||
The methods can be accessed like this:
|
The methods can be accessed like this:
|
||||||
#+BEGIN_SRC scala
|
#+BEGIN_SRC scala
|
||||||
// Drive funct6 of myModule with the 26th to 31st bit of instruction
|
// Drive funct6 of myModule with the 26th to 31st bit of instruction
|
||||||
|
@ -221,6 +242,20 @@
|
||||||
Your IF should now have an instruction as an OUTPUT, and your ID as an INPUT, however
|
Your IF should now have an instruction as an OUTPUT, and your ID as an INPUT, however
|
||||||
they are not connected. This must be done in the CPU class where both the ID and IF are
|
they are not connected. This must be done in the CPU class where both the ID and IF are
|
||||||
instantiated.
|
instantiated.
|
||||||
|
In the overview sketch you probably noticed the barriers between IF and ID.
|
||||||
|
In accordance with the overview, it is incorrect to directly connect the two modules,
|
||||||
|
instead you must connect them using a *barrier*.
|
||||||
|
A barrier is responsible for keeping a value inbetween cycles, facilitating pipelining.
|
||||||
|
There is however one complicating matter: It takes a cycle to get the instruction from the
|
||||||
|
instruction memory, thus we don't want to delay it in the barrier!
|
||||||
|
|
||||||
|
In order to make code readable I suggest adding a new file for your barriers, containing
|
||||||
|
four different modules for the barriers your design will need.
|
||||||
|
|
||||||
|
Start with implementing your IF barrier module, which should contain the following:
|
||||||
|
+ An input and output for PC where the output is delayed by a single cycle.
|
||||||
|
+ An input and output for instruction where the output is wired directly to the input with
|
||||||
|
no delay.
|
||||||
|
|
||||||
**** Step 4½:
|
**** Step 4½:
|
||||||
You should now verify that the correct control signals are produced. Using printf, ensure
|
You should now verify that the correct control signals are produced. Using printf, ensure
|
||||||
|
@ -251,9 +286,18 @@
|
||||||
io.aluResult := MuxLookup(io.aluOp, 0.U(32.W), ALUopMap)
|
io.aluResult := MuxLookup(io.aluOp, 0.U(32.W), ALUopMap)
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
As with the ID stage, you will need a barrier between ID and EX stage.
|
||||||
|
In this case, as the overview sketch indicates, all values should be delayed one cycle.
|
||||||
|
|
||||||
|
When you have finished the barrier, instantiate it and wire ID and EX together with the barrier in the
|
||||||
|
same fashion as IF and ID.
|
||||||
|
|
||||||
*** Step 6:
|
*** Step 6:
|
||||||
Your MEM stage does very little when an ADDI instruction is executed, so implementing it should
|
Your MEM stage does very little when an ADDI instruction is executed, so implementing it should
|
||||||
be easy. All you have to do is forward signals
|
be easy. All you have to do is forward signals.
|
||||||
|
|
||||||
|
From the overview sketch you can see that the same trick used in the IF/ID barrier is utilized
|
||||||
|
here, bypassing the data memory read value since it is already delayed by a cycle.
|
||||||
|
|
||||||
*** Step 7:
|
*** Step 7:
|
||||||
You now need to actually write the result back to your register bank.
|
You now need to actually write the result back to your register bank.
|
||||||
|
|
|
@ -14,7 +14,12 @@ class InstructionFetch extends MultiIOModule {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: Add signals for handling events such as jumps
|
* TODO: Add input signals for handling events such as jumps
|
||||||
|
|
||||||
|
* TODO: Add output signal for the instruction.
|
||||||
|
* The instruction is of type Bundle, which means that you must
|
||||||
|
* use the same syntax used in the testHarness for IMEM setup signals
|
||||||
|
* further up.
|
||||||
*/
|
*/
|
||||||
val io = IO(
|
val io = IO(
|
||||||
new Bundle {
|
new Bundle {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue