From 3b635be2dc5ba57dbd87ae872818f2c1004a6bd6 Mon Sep 17 00:00:00 2001 From: peteraaser Date: Mon, 1 Jun 2020 14:16:08 +0200 Subject: [PATCH] Github render test --- README.org | 2 - exercise.org | 193 +++----------------------- instructions.org | 2 +- src/main/scala/Decoder.scala | 8 +- src/test/scala/RISCV/testRunner.scala | 20 +-- 5 files changed, 31 insertions(+), 194 deletions(-) diff --git a/README.org b/README.org index ddcaf45..ea9f78f 100644 --- a/README.org +++ b/README.org @@ -4,8 +4,6 @@ This is the coursework for the graded part of the TDT4255 course at NTNU. * Instructions - #+ATTR_HTML: title="Join the chat at https://gitter.im/RISCV-FiveStage/community" - [[https://gitter.im/RISCV-FiveStage/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge][file:https://badges.gitter.im/RISCV-FiveStage/community.svg]] To get started with designing your 5-stage RISC-V pipeline you should follow the [[./exercise.org][Exercise instructions]] diff --git a/exercise.org b/exercise.org index cd9ebe5..e246586 100644 --- a/exercise.org +++ b/exercise.org @@ -1,185 +1,24 @@ -* Exercise description - The task in this exercise is to implement a 5-stage pipelined processor for - the [[./instructions.org][RISCV32I instruction set]]. +* Getting started + In order to make a correct design in a somewhat expedient fashion you need to be + *methodical!* - For exercise 1 you will build a 5-stage processor which handles one instruction - at a time, whereas in exercise 2 your design will handle multiple instructions - at a time. - This is done by inserting 4 NOP instructions inbetween each source instruction, - enabling us to use the same tests and harness for both exercise 1 and 2. + This means you should have a good idea of how your processor should work *before* + you start writing code. While chisel is more pleasent to work with than other HDLs + the [[https://i.imgur.com/6IpVNA7.jpg][bricoleur]] approach is not recommended. - Once you are done with exercise 1, you can up the difficulty by setting nopPad - to false and start reading the [[exercise2.org][ex2 guide]]. - - In the project skeleton files ([[./src/main/scala/][Found here]]) you can see that a lot of code has - 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. + My recommended approach is therefore to create an RTL sketch of your processor design. + Start with an overall sketch showing all the components, then drill down. + In your sketch you will eventually add a box for registers, IMEM and DMEM, which + should make it clear how the already finished modules fit into the grander design, + making the skeleton-code less mysterious. - In order to orient yourself you first need a map, thus a high level overview of the - 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) - - *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. - [[./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]] - This is the top level module for the system as a whole. This is where the test - harness accessses your design, providing the necessary IO. - *You should not modify this module for other purposes than debugging.* - - + [[./src/main/scala/CPU.scala]] - This is the top level module for your processor. - In this module the various stages and barriers that make up your processor - should be declared and wired together. - Some of these modules have already been declared in order to wire up the - 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.* - 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]] - This is the instruction fetch stage. - In this stage instruction fetching should happen, meaning you will have to - add logic for handling branches, jumps, and for exercise 2, stalls. - The reason this module is already included is that it contains the instruction - memory, described next which is heavily coupled to the testing harness. - *This module is intended to be further fleshed out by you.* - - + [[./src/main/scala/IMem.scala]] - This module contains the instruction memory for your processor. - Upon testing the test harness loads your program into the instruction memory, - freeing you from the hassle. - *You should not modify this module for other purposes than maaaaybe debugging.* - - + [[./src/main/scala/ID.scala]] - The instruction decode stage. - The reason this module is included is that the registers reside here, thus - for the test harness to work it must be wired up to the register unit to - record its state updates. - *This module is intended to be further fleshed out by you.* - - + [[./src/main/scala/Registers.scala]] - Contains the registers for your processor. Note that the zero register is alredy - disabled, you do not need to do this yourself. - The test harness ensures that all register updates are recorded. - *You should not modify this module for other purposes than maaaaybe debugging.* - - + [[./src/main/scala/MEM.scala]] - Like ID and IF, the MEM skeleton module is included so that the test harness - can set up and monitor the data memory - *This module is intended to be further fleshed out by you.* - - + [[./src/main/scala/DMem.scala]] - Like the registers and Imem, the DMem is already implemented. - *You should not modify this module for other purposes than maaaaybe debugging.* - - + [[./src/main/scala/Const.scala]] - Contains helpful constants for decoding, used by the decoder which is provided. - *This module may be fleshed out further by you if you so choose.* - - + [[./src/main/scala/Decoder.scala]] - The decoder shows how to conveniently demux the instruction. - In the provided ID.scala file a decoder module has already been instantiated. - You should flesh it out further. - You may find it useful to alter this module, especially in exercise 2. - *This module should be further fleshed out by you.* - - + [[./src/main/scala/ToplevelSignals.scala]] - Contains helpful constants. - You should add your own constants here when you find the need for them. - You are not required to use it at all, but it is very helpful. - *This module can be further fleshed out by you.* - - + [[./src/main/scala/SetupSignals.scala]] - You should obviously not modify this file. - You may choose to create a similar file for debug signals, modeled on how - the test harness is built. - *You should not modify this module at all.* - - -** Tests - In addition to the skeleton files it's useful to take a look at how the tests work. - You will not need to alter anything here other than the [[./src/test/scala/Manifest.scala][test manifest]], but some - of these settings can be quite useful to alter. - The main attraction is the test options. By altering the verbosity settings you - may change what is output. - The settings are: - - + printIfSuccessful - Enables logging on tests that succeed. - You typically want this turned off, at least for the full test runner. - - + printErrors - Enables logging of errors. You obviously want this one on, at least on the single - test. - - + printParsedProgram - Prints the desugared program. Useful when the test asm contains instructions that - needs to be expanded or altered. - Unsure what "bnez" means? Turn this setting on and see! - - + printVMtrace - Enables printing of the VM trace, showing how the ideal machine executes a test - - + printVMfinal - Enables printing of the final VM state, showing how the registers look after - completion. Useful if you want to see what a program returns. - - + printMergedTrace - Enables printing of a merged trace. With this option enabled you get to see how - the VM and your processor executed the program side by side. - This setting is extremely helpful to track down where your program goes wrong! - This option attempts to synchronize the execution traces as best as it can, however - once your processor design derails this becomes impossible, leading to rather - nonsensical output. - Instructions that were only executed by either VM or Your design is colored red or - blue. - - *IF YOU ARE COLOR BLIND YOU SHOULD ALTER THE DISPLAY COLORS!* - - + nopPadded - Set this to false when you're ready to enter the big-boy league - - + breakPoints - Not implemented. It's there as a teaser, urging you to implement it so I don't have to. - - -** Getting started - In order to make a correct design in a somewhat expedient fashion you need to be - *methodical!* - - This means you should have a good idea of how your processor should work *before* - you start writing code. While chisel is more pleasent to work with than other HDLs - the [[https://i.imgur.com/6IpVNA7.jpg][bricoleur]] approach is not recommended. - - My recommended approach is therefore to create an RTL sketch of your processor design. - Start with an overall sketch showing all the components, then drill down. - In your sketch you will eventually add a box for registers, IMEM and DMEM, which - should make it clear how the already finished modules fit into the grander design, - 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. + 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. + #+attr_html: :width 1000px + #+attr_latex: :width 1000px [[./Images/IDstage.png]] - I would generally advice to do these on paper, but don't half-ass them. + I would generally advice to do these on paper, but don't half-ass them. ** Adding numbers diff --git a/instructions.org b/instructions.org index c4c9ea0..07be128 100644 --- a/instructions.org +++ b/instructions.org @@ -2,7 +2,7 @@ 4.2. Register-Register Arithmetic Instructions -------------------------------------------------------------------------- -These do not render well on github, try using your text editor. +If these do not render well on github, try using your text editor. * ADD diff --git a/src/main/scala/Decoder.scala b/src/main/scala/Decoder.scala index 98516f5..758c250 100644 --- a/src/main/scala/Decoder.scala +++ b/src/main/scala/Decoder.scala @@ -8,7 +8,7 @@ import chisel3.util.ListLookup * This module is mostly done, but you will have to fill in the blanks in opcodeMap. * You may want to add more signals to be decoded in this module depending on your * design if you so desire. - * + * * In the "classic" 5 stage decoder signals such as op1select and immType * are not included, however I have added them to my design, and similarily you might * find it useful to add more @@ -36,12 +36,12 @@ class Decoder() extends Module { val Y = 1.asUInt(1.W) /** - * In scala we sometimes (ab)use the `->` operator to create tuples. + * In scala we sometimes (ab)use the `->` operator to create tuples. * The reason for this is that it serves as convenient sugar to make maps. - * + * * This doesn't matter to you, just fill in the blanks in the style currently * used, I just want to demystify some of the scala magic. - * + * * `a -> b` == `(a, b)` == `Tuple2(a, b)` */ val opcodeMap: Array[(BitPat, List[UInt])] = Array( diff --git a/src/test/scala/RISCV/testRunner.scala b/src/test/scala/RISCV/testRunner.scala index 3d9d60c..9c5f977 100644 --- a/src/test/scala/RISCV/testRunner.scala +++ b/src/test/scala/RISCV/testRunner.scala @@ -136,18 +136,18 @@ object TestRunner { events match { // Scala syntax for matching a list with a head element of some type and a tail - // `case h :: t =>` - // means we want to match a list with at least a head and a tail (tail can be Nil, so we - // essentially want to match a list with at least one element) - // h is the first element of the list, t is the remainder (which can be Nil, aka empty) + // `case h :: t =>` + // means we want to match a list with at least a head and a tail (tail can be Nil, so we + // essentially want to match a list with at least one element) + // h is the first element of the list, t is the remainder (which can be Nil, aka empty) - // `case Constructor(arg1, arg2) :: t => ` - // means we want to match a list whose first element is of type Constructor, giving us access to its internal - // values. + // `case Constructor(arg1, arg2) :: t => ` + // means we want to match a list whose first element is of type Constructor, giving us access to its internal + // values. - // `case Constructor(arg1, arg2) :: t => if(p(arg1, arg2))` - // means we want to match a list whose first element is of type Constructor while satisfying some predicate p, - // called an if guard. + // `case Constructor(arg1, arg2) :: t => if(p(arg1, arg2))` + // means we want to match a list whose first element is of type Constructor while satisfying some predicate p, + // called an if guard. case Taken(from, to) :: t if( predictionTable(from)) => helper(t, predictionTable) case Taken(from, to) :: t if(!predictionTable(from)) => 1 + helper(t, predictionTable.updated(from, true)) case NotTaken(addr) :: t if( predictionTable(addr)) => 1 + helper(t, predictionTable.updated(addr, false))