| @@ -3,23 +3,25 @@ | |||||
| read -p "Enter your student username (the one you use on badboard): " username | read -p "Enter your student username (the one you use on badboard): " username | ||||
| echo "Cleaning your project" | echo "Cleaning your project" | ||||
| ./sbt.sh clean | |||||
| # ./sbt.sh clean | |||||
| echo "Creating archive" | echo "Creating archive" | ||||
| mkdir wrap | mkdir wrap | ||||
| mkdir wrap/project | |||||
| cp -r src ./wrap/ | cp -r src ./wrap/ | ||||
| cp build.sbt ./wrap | cp build.sbt ./wrap | ||||
| cp project/Dependencies.scala ./wrap/project/Dependencies.scala | cp project/Dependencies.scala ./wrap/project/Dependencies.scala | ||||
| cp project/build.properties ./wrap/project/build.properties | cp project/build.properties ./wrap/project/build.properties | ||||
| cp sbt.sh ./wrap | cp sbt.sh ./wrap | ||||
| tar czfv $username.gz wrap | |||||
| (cd ./wrap/; tar czfv $username.tar.gz .) | |||||
| mv ./wrap/$username.tar.gz . | |||||
| rm -rf ./wrap | rm -rf ./wrap | ||||
| echo "Unwrapping and testing your wrapped package" | echo "Unwrapping and testing your wrapped package" | ||||
| mkdir wrapTest | mkdir wrapTest | ||||
| tar -C ./wrapTest -xvf $username.gz | |||||
| ./wrapTest/wrap/sbt.sh test | |||||
| tar -C ./wrapTest -xvf $username.tar.gz | |||||
| ./wrapTest/sbt.sh test | |||||
| rm -rf ./wrapTest | rm -rf ./wrapTest | ||||
| echo "If the test output looked good then you're good to go!" | echo "If the test output looked good then you're good to go!" | ||||
| @@ -22,6 +22,15 @@ | |||||
| Keep in mind that this is just a high level sketch, omitting many details as well | Keep in mind that this is just a high level sketch, omitting many details as well | ||||
| entire features (for instance branch logic) | entire features (for instance branch logic) | ||||
| *Important* | |||||
| When you are done, use the provided ./deliver.sh script to pack up the archive. | |||||
| If you're unable to run bash scripts then please ensure that you deliver a *zip* archive. | |||||
| Not .rar or anything else, just use zip because my grading script knows how to handle that | |||||
| in addition to the one used by deliver.sh | |||||
| named after your username. Nothing more, nothing less, just your username. | |||||
| This archive should be runnable as is, thus you need to include all the necessary files. | |||||
| (I may or may not diff the tests to check if you're screwing with them) | |||||
| #+CAPTION: A very high level processor schematic. Registers, Instruction and data memory are already implemented. | #+CAPTION: A very high level processor schematic. Registers, Instruction and data memory are already implemented. | ||||
| [[./Images/FiveStage.png]] | [[./Images/FiveStage.png]] | ||||
| @@ -26,7 +26,7 @@ object Parser { | |||||
| def branchZ : (Parser[Int], Parser[String]) = (reg <~ sep, label) | def branchZ : (Parser[Int], Parser[String]) = (reg <~ sep, label) | ||||
| def arith : (Parser[Int], Parser[Int], Parser[Int]) = (reg <~ sep, reg <~ sep, reg) | def arith : (Parser[Int], Parser[Int], Parser[Int]) = (reg <~ sep, reg <~ sep, reg) | ||||
| def arithImm : (Parser[Int], Parser[Int], Parser[Int]) = (reg <~ sep, reg <~ sep, hex | int) | |||||
| def arithImm : (Parser[Int], Parser[Int], Parser[Int]) = (reg <~ sep, reg <~ sep, (hex | int)) | |||||
| def stringWs(s: String) : Parser[String] = many(whitespace) ~> string(s) <~ many1(whitespace) | def stringWs(s: String) : Parser[String] = many(whitespace) ~> string(s) <~ many1(whitespace) | ||||
| @@ -144,18 +144,16 @@ object Parser { | |||||
| val multipleInstructions: Parser[List[Op]] = List( | val multipleInstructions: Parser[List[Op]] = List( | ||||
| // stringWs("li") ~> (reg <~ sep, (hex | int).map(_.splitLoHi(20))).mapN{ case(rd, (hi, lo)) => { | |||||
| stringWs("li") ~> (reg <~ sep, (hex | int).map(_.splitHiLo(20))).mapN{ case(rd, (hi, lo)) => { | stringWs("li") ~> (reg <~ sep, (hex | int).map(_.splitHiLo(20))).mapN{ case(rd, (hi, lo)) => { | ||||
| say("hello?") | |||||
| List( | List( | ||||
| ArithImm.add(rd, rd, lo), | ArithImm.add(rd, rd, lo), | ||||
| LUI(rd, hi), | |||||
| LUI(rd, if(lo>0) hi else hi+1), | |||||
| )}}.map(_.widen[Op]), | )}}.map(_.widen[Op]), | ||||
| // NOTE: THESE ARE NOT PSEUDO-OPS IN RISC-V32I! | // NOTE: THESE ARE NOT PSEUDO-OPS IN RISC-V32I! | ||||
| // NOTE: USES A SPECIAL REGISTER | // NOTE: USES A SPECIAL REGISTER | ||||
| // NOTE: PROBABLY BROKEN, NOT EXHAUSTIVELY TESTED!!! | // NOTE: PROBABLY BROKEN, NOT EXHAUSTIVELY TESTED!!! | ||||
| stringWs("lh") ~> (reg <~ sep, int <~ char('('), reg <~ char(')')).mapN{ | |||||
| stringWs("lh") ~> (reg <~ sep, (hex | int) <~ char('('), reg <~ char(')')).mapN{ | |||||
| case (rd, offset, rs1) if (offset % 4 == 3) => { | case (rd, offset, rs1) if (offset % 4 == 3) => { | ||||
| val placeHolder = if(rd == Reg("a0").value) Reg("a1").value else Reg("a0").value | val placeHolder = if(rd == Reg("a0").value) Reg("a1").value else Reg("a0").value | ||||
| List( | List( | ||||
| @@ -49,7 +49,7 @@ object TestRunner { | |||||
| binary.toList.sortBy(_._1.value).map(_._2), | binary.toList.sortBy(_._1.value).map(_._2), | ||||
| program.settings, | program.settings, | ||||
| finalVM.pc, | finalVM.pc, | ||||
| 1500) | |||||
| 15000) | |||||
| } yield { | } yield { | ||||
| val traces = mergeTraces(trace, chiselTrace).map(x => printMergedTraces((x), program)) | val traces = mergeTraces(trace, chiselTrace).map(x => printMergedTraces((x), program)) | ||||
| @@ -0,0 +1,98 @@ | |||||
| * Theory question 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 the | |||||
| soul of wit, and also the key to getting a good score. | |||||
| ** Question 1 | |||||
| 2 points. | |||||
| *** Part 1 | |||||
| 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? | |||||
| + memToReg | |||||
| + 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: | |||||
| + memToReg = 0 | |||||
| + 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. | |||||
| 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) | |||||
| ** Question 3 | |||||
| 4 points. | |||||
| 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) 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) | |||||