Remove MemToReg.

Pretty sure MemToReg is a MIPS relic, it is redundant so long as
all memory reads are put into registers.
This commit is contained in:
peteraaser 2020-06-02 14:58:06 +02:00
parent 743734c346
commit 8dc92fb8e1
5 changed files with 100 additions and 35 deletions

View file

@ -6,12 +6,15 @@
when grading these questions, thus even with no implementation at all you
should still be able to score 100% on the theory questions.
All questions can be answered in a few sentences. Remember that brevity is the
soul of wit, and also the key to getting a good score.
All questions can be answered in a few sentences. Remember that brevity is wit,
and also the key to getting a good score.
You should easily be able to fit your entire answer on a single screen.
** Question 1
2 points.
*2 points.*
*** Part 1
**** Part 1½
*½ points.*
When decoding the BNE branch instruction in the above assembly program
#+begin_src asm
bne x6, x2, "loop",
@ -19,13 +22,27 @@
In your design, what is the value of each of the control signals below?
+ memToReg
+ regWrite
+ memRead
+ memWrite
+ branch
+ jump
**** Part 1¼
*½ points.*
When decoding the LW instruction in the above assembly program
#+begin_src asm
jal x1, 0x10(x1)
#+end_src
In your design, what is the value of each of the control signals below?
+ regWrite
+ memRead
+ memWrite
+ branch
+ jump
Keep in mind that your design and your implementation are separate entities, thus
you should answer this question based on your ideal design, not your finished
implementation.
@ -33,7 +50,6 @@
*** Part 2
During execution, at some arbitrary cycle the control signals are:
+ memToReg = 0
+ regWrite = 1
+ memRead = 0
+ memWrite = 0
@ -48,7 +64,10 @@
implementation.
** Question 2
4 points.
*4 points.*
*NO PARTIAL CREDITS*
Since you can test your solution with the testing framework I will not offer any
points for a near correct solution to this problem.
Reading the binary of a RISC-V program you get the following:
@ -77,11 +96,23 @@
#+end_src
*Your answer should be in the form of a simple asm program.*
(hint 1: the original asm program had a label, you need to infer where that label was)
(hint 2: verify your conclusion by assembling your answer)
+ hint 1:
the original asm program had a label, you need to infer where that label was
+ hint 2:
Verify your conclusion by assembling your answer.
To do this, make an asm program, place it with the rest of the tests and set
~printBinary~ to ~true~ in ~singleTestOptions~ in ~Manifest.scala~ which will
print the full binary of your program.
As long as your program generates the same binary as the supplied your program
is correct.
** Question 3
4 points.
*4 points.*
*NO PARTIAL CREDITS*
Since you can test your solution with the testing framework I will not offer any
points for a near correct solution to this problem.
In order to load a large number LUI and ADDI are used.
consider the following program
@ -94,5 +125,37 @@
#+end_src
a) Which of these instructions will be split into ADDI LUI pairs?
b) Why do the two last instructions need to be handled differently from each other?
(hint: The parser and assembler in the test suite can help you answer this question)
b) Explain in 3 sentences or less *how* the two last ops are handled differently and *why*.
+ hint 1:
The parser and assembler in the test suite can help you answer the first part of
this question (a).
Create an asm file, put it with the rest of the tests and run it, setting the correct
test options in ~singleTestOptions~ defined in ~Manifest.scala~ and observe the output.
+ hint 2:
While it's probably easier to solve this problem using the internet, however you
can also figure out what is happening by browsing the assembler source code which
will hopefully give you a deeper insight into what is going on here.
Look at ~Parser.scala~, specifically what happens when an ~li~ instruction is parsed.
When parsing an instruction the parser first attempts to apply the
~singleInstruction~ rule, however this only succeeds if the immediate value
obeys certain restrictions (~nBits <= 12~), if not it fails.
If the ~singleInstruction~ rule fails the parser then attempts to apply the
~multipleInstructions~ rule instead which expands operations into a list of real ops.
When this happens the resulting operations are defined as the following:
#+begin_src scala
stringWs("li") ~> (reg <~ sep, (hex | int).map(_.splitHiLo(20))).mapN{ case(rd, (hi, lo)) => {
List(
ArithImm.add(rd, rd, lo),
LUI(rd, if(lo > 0) hi else hi+1),
)}}.map(_.widen[Op]),
#+end_src
This is quite a lot to unpack, but you can focus on the line where the ~LUI~ is constructed.
~hi~ and ~lo~ are the results of ~splitHiLo~ which splits a 32 bit word into a 12 bit and a
20 bit.
Try this for yourself on paper; what happens when ~lo~ ends up being a negative number?
What is the interplay between incrementing ~hi~ with 1 and adding a ~lo~ that is represented
as a negative value?