157 lines
5.7 KiB
Org Mode
157 lines
5.7 KiB
Org Mode
* Theory questions EX1
|
|
|
|
Keep in mind that your design and your implementation are separate entities,
|
|
thus you should answer these questions based on your ideal design, not your
|
|
finished implementation. Consequently I will not consider your implementation
|
|
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 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.*
|
|
*** Part 1
|
|
**** Part 1½
|
|
*½ points.*
|
|
When decoding the BNE branch instruction in the above assembly program
|
|
#+begin_src asm
|
|
bne x6, x2, "loop",
|
|
#+end_src
|
|
|
|
In your design, what is the value of each of the control signals below?
|
|
|
|
+ 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.
|
|
|
|
*** Part 2
|
|
During execution, at some arbitrary cycle the control signals are:
|
|
|
|
+ regWrite = 1
|
|
+ memRead = 0
|
|
+ memWrite = 0
|
|
+ branch = 0
|
|
+ jump = 1
|
|
|
|
In your design, which intruction(s) could be executing?
|
|
|
|
|
|
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.
|
|
|
|
** Question 2
|
|
*4 points.*
|
|
Partial credit awarded on a case by case basis.
|
|
|
|
Reading the binary of a RISC-V program you get the following:
|
|
|
|
#+begin_src text
|
|
0x0: 0x00a00293 -- 0000 0000 1010 0000 0000 0010 1001 0011
|
|
0x4: 0x01400313 -- 0000 0001 0100 0000 0000 0011 0001 0011
|
|
0x8: 0xfff30313 -- 1111 1111 1111 0011 0000 0011 0001 0011
|
|
0xc: 0x00628463 -- 0000 0000 0110 0010 1000 0100 0110 0011
|
|
0x10: 0xff9ff06f -- 1111 1111 1001 1111 1111 0000 0110 1111
|
|
#+end_src
|
|
|
|
For each instruction describe the format and name and corresponding RISC-V source
|
|
To give you an idea on how decoding would work, here is the decoding of 0x40635293:
|
|
|
|
#+begin_src text
|
|
0x40635293 -- 0100 0000 0110 0011 0101 0010 1001 0011
|
|
|
|
Opcode: 0010011 => Format is IType, thus the funct3 field is used to decode further
|
|
funct3: 101 => Instruction is of type SRAI, the instruction looks like ~srai rd, rx, imm~
|
|
|
|
rs1: 00110 => x6
|
|
rd: 00101 => x5
|
|
shamt: 000110 => 6
|
|
|
|
Resulting in ~srai x5, x6, 6~
|
|
#+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.
|
|
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.*
|
|
Partial credit awarded on a case by case basis.
|
|
|
|
In order to load a large number LUI and ADDI are used.
|
|
consider the following program
|
|
#+begin_src asm
|
|
li x0, 0xFF
|
|
li x1, 0x600
|
|
li x2, 0x8EE
|
|
li x3, 0xBABEFACE
|
|
li x4, 0xBABE07CE
|
|
#+end_src
|
|
|
|
a) Which of these instructions will be split into ADDI LUI pairs?
|
|
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?
|