diff --git a/repo/.gitignore b/.gitignore similarity index 100% rename from repo/.gitignore rename to .gitignore diff --git a/Lab_4.md b/Lab_4.md deleted file mode 100644 index 78e9dd8..0000000 --- a/Lab_4.md +++ /dev/null @@ -1,170 +0,0 @@ -
- -## EIE2 Instruction Set Architecture & Compiler (IAC) - ---- -## Lab 4 - A Reduced RISC-V CPU - -**_Peter Cheung, V1.2 - 25 Oct 2024_** - ---- - -
- -## Objectives -By the end of this experiment, you should be able to: -* Form a team of four members and get to know each other -* As a team, create a team Github repo with its initial structure -* Pull and push from the repo -* Understand the tasks required for Lab 4 as a Team -* Allocate responsibility for each member according to the task partitioning given to you in this instruction -* Complete the design of the Reduced RISC-V to execute the program provided - -
- -___ - -## Know your team members -___ - -Working as a team with people you don't know is a challenge. It is often much easier to work on your own. You are required to work as a team because: - -1. The coursework for this module is too large for one person to complete. -2. You learn much more from each other provided that the "stronger" student is prepare to teach the "weaker" student - both will benefit provided that those need help are willing to admit and ask. -3. Github was created mainly to provide a collaboration tool. You will be forced to learn how to use Git and Github, which is part of the educational goals of this module. -4. It may improve your social skills. - ->Introduce yourself to each other by doing a 5 minutes each one-on-one chat. This will take only 15 minutes, but it is important to do this at this stage. - -
- -___ - -## Set up Github Repository for the Team - -___ - - ->Choose among the Team a Repo Master, who is reponsible to create the repo and make sure that all other team member learn how to do it themselves if needed. All members should also learn how to branch, pull, push and commit to the repo. Discuss among yourself an initial structure of the repo and a set of common practices that your Team should follow. - -You can find a very helpful guide on how to set up your repo in Github [here](https://docs.github.com/en/get-started/quickstart/create-a-repo "How to create a repo"). - -The Repo Master should now create a repo for the team with a name that **ends** in the team number, which is provided by me in the Teams List (e.g. `Team21` or `RISC-V-Team5`) - -The Repo Master must then give permission to all team members AND ME (also the TAs if you want), so that every member can access the repo, and I can see what your team is doing. I will be checking on the progress of all teams by the end of next week on Lab 4. - -A starting repo is available in the [`repo`](repo) folder. You may copy the files over, or start -from scratch. If you decide to start from scratch, your repo must be able to run our integration -tests from a single script, like the [`doit.sh`](repo/tb/doit.sh) script. - -___ - -

FINAL TEAM PROJECT ASSESSMENT WILL INCLUDE A CHECK ON HOW OFTEN

-

YOU COMMIT TO THE REPO AS EVIDENCE OF AN INDIVIDUAL'S CONTRIBUTION.

- -
- -___ - -## The Reduced RISC-V Specification - -___ - -Your team task for Lab 4 is to design a *__SINGLE CYCLE__* CPU that executes two (or three) RISC-V instructions. To verify that your design works, the CPU should execute the simple assembly language program below (see [`program.S`](repo/tb/asm/program.S)):

- -


- -This program performs the same function as the simple 8-bit binary counter you designed in Lab 1 (i.e. counter.sv). Note that this uses ONLY two instructions: "addi" and "bne". It demonstrates how "reduced" the RISC-V ISA is! However, this also makes the assembly program hard to read and understand. One can translate these instructions to pseudoinstructions, which makes the program much easier to read. (I used the online assembler [here](https://riscvasm.lucasteske.dev/) to do this). The equivalent asssembly code with pseudoinstructions is: - -


- -> Each student should take one addi and one bne instruction, and check you fully understand why the instruction is mapped to this machine code. (See Lecture 6 slide 7.) - -
- -___ - -## The Microarchitecture of the Reduced RISC-V CPU - -___ - -To help you progress quickly, here is the top-level block diagram for this CPU. Note the following: -1. This is a *__single cycle__* design meaning that on each rising edge of the clock, one instruction is executed. -2. The program memory must be asynchronous - meaning that as soon as the Program Counter (PC) changes, the instruction will appear at the program memory output. You should modify Lab 2 memory block (you may use RAM or ROM here) so that it is asynchronous. You can preload the memory with the machine code program from a file. -3. Only two components here are clocked: the PC Register that maintains the program counter and the Register File. The two READ ports of the register file should also be asychronous and the WRITE port of the Register File must be synchronous. -4. The thick verticle blue bar shows how the 32-bit instructions is split into fields to drive the different modules. It is NOT a component. -5. The entire CPU only has three I/O ports shown in RED: clock signal _clk_, _rst_ and the contents of the a0 register (directly from the Register File). This allows us to bring this register content to the outside directly. -6. The Sign-extension Unit takes the relevant fields from the instruction and composes the immediate operand depending on the instruction. -7. The Control Unit is not clocked and decodes the instruction to provide control signals to various modules. -

- -


- ->Discuss among yourselves why the WRITE port of the Register File must be synchronous to the clock signal. - -___ - -## Divide the task into individual components - -___ - -In a team project, there is always a danger that a team member is too keen and able, and wanting so much the team to succeed that they "hog" the project and do everything. Or a team member is trying to do as little as possible and just be a passenger. Therefore, the task in this Lab is divided into four separate components as shaded blocks, one for each team member as followings: -1. Program Counter and related adders. -2. The Register File, ALU and the related [MUX](repo/rtl/mux.sv). -3. The Control Unit, the Sign-extension Unit and the instruction memory. -4. The testbench and verification of the whole design working via gtkWave and Vbuddy (where appropriate). - -If you are doing verification, please read this guide: -[`verification.md`](verification.md) - ->Discuss and agree among yourselves who does what. ->Complete the Lab 4 Team's Survey [here](https://forms.office.com/r/n2zeXxxvaJ "Survey"). Only ONE survey per team. - -
- -___ - -## Define interfaces for all modules - -___ - ->Each member should define the interface signals of the modules for which they are responsible. The test person should create a test plan. -
- -The block diagram shown above has no style convention. You may wish to follow -the diagram exactly, or use a style convention. I recommend the one [here]( -https://www.systemverilog.io/verification/styleguide/). Please keep the names -of the signals the same (e.g. `RegWrite` could be `reg_write`). -This allows TAs and myself to help you debug your design easier without having to discover your naming convention. - -
- -___ - -## Stretched Goal - -___ - ->If your team have time, you can modify your design to include the "lw" instruction. You will need to change the microarchitecture to add a block of data memory (separate from program memory), into which you store a single cycle of sine coefficents. Replace line 7 of the program with: - -```brainfuck - lw a0, 0(a1) -``` - -This is the implementation of the Lab 2 sinewave generator using RISC-V instructions! - -

- -___ - -## Deliverables - -___ - -Note that Lab 4 is designed to be a formative assessment exercise. The deliverables here are designed to help you learn and to self-assess how you and your team are doing. I and the TAs will also provide informal feedback to you during Lab Sessions. **This will NOT contribute towards the final coursework marks**. - ->On the repo for your team, you should have: ->1. A README.md that show evidences of the CPU working properly with the program. ->2. A short narrative to state the challenges you encountered as a team. ->3. Comments about any design decisions you made that are not obvious. ->4. A reflection on what you might do differently if you were to start again. \ No newline at end of file diff --git a/README.md b/README.md index 14516fb..9b80c60 120000 --- a/README.md +++ b/README.md @@ -1 +1 @@ -Lab_4.md \ No newline at end of file +Easy A* diff --git a/images/code1.jpg b/images/code1.jpg deleted file mode 100644 index e19b5d2..0000000 Binary files a/images/code1.jpg and /dev/null differ diff --git a/images/machine_code.jpg b/images/machine_code.jpg deleted file mode 100644 index f10345c..0000000 Binary files a/images/machine_code.jpg and /dev/null differ diff --git a/images/microarchitecture.jpg b/images/microarchitecture.jpg deleted file mode 100644 index 0a83d47..0000000 Binary files a/images/microarchitecture.jpg and /dev/null differ diff --git a/images/pseudo.jpg b/images/pseudo.jpg deleted file mode 100644 index 13e83bb..0000000 Binary files a/images/pseudo.jpg and /dev/null differ diff --git a/images/pseudo.pdf b/images/pseudo.pdf deleted file mode 100644 index 96bdfae..0000000 Binary files a/images/pseudo.pdf and /dev/null differ diff --git a/repo/rtl/top.sv b/repo/rtl/top.sv deleted file mode 100644 index b25a766..0000000 --- a/repo/rtl/top.sv +++ /dev/null @@ -1,9 +0,0 @@ -module top #( - DATA_WIDTH = 32 -) ( - input logic clk, - input logic rst, - output logic [DATA_WIDTH-1:0] a0 -); - assign a0 = 32'd5; -endmodule diff --git a/rtl/control_unit.sv b/rtl/control_unit.sv new file mode 100644 index 0000000..56c2268 --- /dev/null +++ b/rtl/control_unit.sv @@ -0,0 +1,46 @@ +module control_unit #( + WIDTH = 32 +) ( + input logic [WIDTH-1:0] ins, + input logic EQ, //? + output logic pc_src, // pc branches or not + output logic [2:0] alu_ctrl, // ALU operation: add, sub, OR + output logic alu_src, // whether 2nd ALU input is a register data or immediate + output logic [1:0] imm_src, // type of ins: R, I, S, B + output logic reg_write // register write enable +); + +logic [6:0] opcode; +logic [2:0] funct3; + +assign opcode = ins[6:0]; +assign funct3 = ins[14:12]; + +//-------- DECODER --------// +// Only implementing two basic instructions addi and bne so logic can be very specific and not generalised. +always_comb +case (opcode) + + 7'd19: case (funct3) + 0: begin // addi ins + reg_write <= 1; // storing the resut in register + imm_src <= 0; + alu_src <= 1 // ALU uses immediate and not rs2 + alu_ctrl <= 0 // addition of rs1 + imm + pc_src <= 0; + end + endcase + + 7'd99: case (funct3) + 1: begin // bne ins + reg_write <= 0; + imm_src <= 2; // type B ins + alu_src <= 0; // the immediate will be fed into the PC and not used in the ALU + alu_ctrl <= 1; // we are doing a sub to find the difference between instruction addresses + pc_src <= 1; // pc increments to branch address + end + endcase + +endcase + +endmodule diff --git a/rtl/instr.mem b/rtl/instr.mem new file mode 100644 index 0000000..8c3947f --- /dev/null +++ b/rtl/instr.mem @@ -0,0 +1,7 @@ +0f f0 03 13 +00 00 05 13 +00 00 05 93 +00 05 85 13 +00 15 85 93 +fe 65 9c e3 +fe 03 18 e3 \ No newline at end of file diff --git a/rtl/instr_mem.sv b/rtl/instr_mem.sv new file mode 100644 index 0000000..50827b7 --- /dev/null +++ b/rtl/instr_mem.sv @@ -0,0 +1,20 @@ +module instr_mem #( + parameter ADDRESS_WIDTH = 16, + DATA_WIDTH = 32 +)( + input logic [ADDRESS_WIDTH-1:0] addr, + output logic [DATA_WIDTH-1:0] dout +); + +logic [DATA_WIDTH-1:0] mem_array [2**ADDRESS_WIDTH-1:0]; + +initial begin + $display("Loading Instruction Memory."); + $readmemh("instr.mem", mem_array); +end; + +always_ff @(posedge addr) + + dout <= mem_array [addr]; + +endmodule diff --git a/rtl/pc/pc_branch.sv b/rtl/pc/pc_branch.sv new file mode 100644 index 0000000..fd87de1 --- /dev/null +++ b/rtl/pc/pc_branch.sv @@ -0,0 +1,11 @@ +module pc_branch #( + parameter WIDTH = 32 +) ( + input logic [WIDTH-1:0] pc, + input logic [WIDTH-1:0] imm, + output logic [WIDTH-1:0] branch_pc +); + +assign branch_pc = pc + imm; + +endmodule diff --git a/rtl/pc/pc_inc.sv b/rtl/pc/pc_inc.sv new file mode 100644 index 0000000..2f8f1aa --- /dev/null +++ b/rtl/pc/pc_inc.sv @@ -0,0 +1,10 @@ +module pc_inc #( + parameter WIDTH = 32 +) ( + input logic [WIDTH-1:0] pc, + output logic [WIDTH-1:0] inc_pc +); + +assign inc_pc = pc + 32'b100; + +endmodule diff --git a/rtl/pc/pc_reg.sv b/rtl/pc/pc_reg.sv new file mode 100644 index 0000000..670f27a --- /dev/null +++ b/rtl/pc/pc_reg.sv @@ -0,0 +1,17 @@ +module pc_reg #( + parameter WIDTH = 32 +) ( + input logic clk, + input logic rst, + input logic [WIDTH-1:0] pc_in, + output logic [WIDTH-1:0] pc_out +); + +always_ff @(posedge clk or posedge rst) begin + if (rst) + pc_out <= 'b0; + else + pc_out <= pc_in; +end + +endmodule diff --git a/rtl/pc/pc_unit.sv b/rtl/pc/pc_unit.sv new file mode 100644 index 0000000..57c5e6d --- /dev/null +++ b/rtl/pc/pc_unit.sv @@ -0,0 +1,46 @@ +module pc_unit #( + parameter WIDTH = 32 +) ( + input logic clk, + input logic rst, + input logic pc_src, + input logic [WIDTH-1:0] pc_in, + input logic [WIDTH-1:0] immop, + output logic [WIDTH-1:0] pc_out +); + + +logic [WIDTH-1:0] inc_pc; +logic [WIDTH-1:0] branch_pc; +logic [WIDTH-1:0] next_pc; + +// Increment PC (pc + 4) +pc_inc #(.WIDTH(WIDTH)) u_inc ( + .pc(pc_in), + .inc_pc(inc_pc) +); + +// Branch PC (pc + imm) +pc_branch #(.WIDTH(WIDTH)) u_branch ( + .pc(pc_in), + .imm(immop), + .branch_pc(branch_pc) +); + +// Next PC multiplexer +mux_2 #(.DATA_WIDTH(WIDTH)) u_mux_next_pc ( + .in0(inc_pc), + .in1(branch_pc), + .sel(pc_src), + .out(next_pc) +); + +// PC register +pc_reg #(.WIDTH(WIDTH)) u_pc_reg ( + .clk(clk), + .rst(rst), + .pc_in(next_pc), + .pc_out(pc_out) +); + +endmodule diff --git a/rtl/reg_file/alu.sv b/rtl/reg_file/alu.sv new file mode 100644 index 0000000..c8a90b0 --- /dev/null +++ b/rtl/reg_file/alu.sv @@ -0,0 +1,28 @@ +module alu #( + parameter DATA_WIDTH 8 +) ( + input logic [DATA_WIDTH-1:0] aluop1, + input logic [DATA_WIDTH-1:0] aluop2, + input logic [2:0] aluctrl, + output logic [DATA_WIDTH-1:0] aluout, + output logic eq +) + +always_comb begin + case (aluctrl) + 0: begin + aluout <= aluop1 + aluop2; + eq <= 1b'0; + end + 1: begin + aluout <= aluop1 - aluop2; + eq <= aluout == 1b'0; + end + default: begin + aluout <= 1b'0; + eq <= 1b'0; + end + endcase +end + +endmodule diff --git a/repo/rtl/mux.sv b/rtl/reg_file/mux_2.sv similarity index 84% rename from repo/rtl/mux.sv rename to rtl/reg_file/mux_2.sv index 11ef1e1..8504179 100644 --- a/repo/rtl/mux.sv +++ b/rtl/reg_file/mux_2.sv @@ -1,6 +1,6 @@ -module mux #( - DATA_WIDTH = 32 -) ( +module mux_2 #( + DATA_WIDTH = 8 +)( input logic [DATA_WIDTH-1:0] in0, input logic [DATA_WIDTH-1:0] in1, input logic sel, diff --git a/rtl/reg_file/ram2.sv b/rtl/reg_file/ram2.sv new file mode 100644 index 0000000..4a9ff99 --- /dev/null +++ b/rtl/reg_file/ram2.sv @@ -0,0 +1,25 @@ +module ram2 #( + parameter ADDRESS_WIDTH = 5, + DATA_WIDTH = 8 +)( + input logic clk, + input logic wr_en, + input logic [ADDRESS_WIDTH-1:0] wr_addr, + input logic [ADDRESS_WIDTH-1:0] rd1_addr, + input logic [ADDRESS_WIDTH-1:0] rd2_addr, + input logic [DATA_WIDTH-1:0] din, + output logic [DATA_WIDTH-1:0] dout1, + output logic [DATA_WIDTH-1:0] dout2, + output logic a0 +); + +logic [DATA_WIDTH-1:0] ram_array [2**ADDRESS_WIDTH-1:0]; + +always_ff @(posedge clk) begin + dout1 <= ram_array[rd1_addr]; + dout2 <= ram_array[rd2_addr]; + if (wr_en == 1'b1) + ram_array[wr_addr] <= din; + a0 <= ram_array[wr_addr]; +end +endmodule diff --git a/rtl/reg_file/reg_file.sv b/rtl/reg_file/reg_file.sv new file mode 100644 index 0000000..252e286 --- /dev/null +++ b/rtl/reg_file/reg_file.sv @@ -0,0 +1,47 @@ +module reg_file #( + parameter D_WIDTH = 8, + parameter A_WIDTH = 5 +) ( + input logic [ADDRESS_WIDTH-1:0] ad1, + input logic [ADDRESS_WIDTH-1:0] ad2, + input logic [ADDRESS_WIDTH-1:0] ad3, + input logic we3, + input logic [DATA_WIDTH-1:0] imm_op, + input logic alusrc, + input logic [3:0] aluctrl, + input logic clk, + output logic [DATA_WIDTH-1:0] a0, + output logic eq +); + +logic [DATA_WIDTH-1:0] aluout; +logic [DATA_WIDTH-1:0] aluop1; +logic [DATA_WIDTH-1:0] aluop2; +logic [DATA_WIDTH-1:0] regop2; + +ram2 registers ( + .clk(clk), + .wr_en(we3), + .wr_addr(ad3), + .rd1_addr(ad1), + .rd2_addr(ad2), + .din(wd3), + .dout1(aluop1), + .dout2(regop2) +) + +mux_2 imm_mux ( + .in0(regop2), + .in1(imm_op), + .sel(alusrc), + .out(aluop2) +) + +alu ALU ( + .aluop1(aluop1), + .aluop2(aluop2), + .aluctrl(aluctrl), + .aluout(aluout), + .eq(eq) +) +endmodule diff --git a/rtl/sign_extend.sv b/rtl/sign_extend.sv new file mode 100644 index 0000000..243cd44 --- /dev/null +++ b/rtl/sign_extend.sv @@ -0,0 +1,30 @@ +module sign_extend #( + WIDTH = 32 +)( + input logic [1:0] imm_src, // type of instruction + input logic [WIDTH-1:0] ins, // entire instruction word + output logic [WIDTH-1:0] imm_op // output sign extended imm +); + +always_comb +case (imm_src) // 2: R type -> do no care as this instruction doesn't use immediates + 0: if (ins[31]) // I type + imm_op <= {{WIDTH-12{1'b1}}, ins[31:20]} + else + imm_op <= {{WIDTH-12{1'b0}}, ins[31:20]} + 1: if (ins[31]) // S type + imm_op <= {{WIDTH-12{1'b1}}, ins[31:25], ins[11:7]} + else + imm_op <= {{WIDTH-12{1'b0}}, ins[31:20]} + 2: if (ins[31]) // B type + imm_op <= {{WIDTH-13{1'b1}}, ins[31], ins[7], ins[30:25], ins[11:8], 0} + else + imm_op <= {{WIDTH-13{0'b1}}, ins[31], ins[7], ins[30:25], ins[11:8], 0} + + default: if (ins[31]) + imm_op <= {{WIDTH-12{1'b1}}, ins[31:20]} + else + imm_op <= {{WIDTH-12{1'b0}}, ins[31:20]} +endcase + +endmodule diff --git a/rtl/top.sv b/rtl/top.sv new file mode 100644 index 0000000..74e4b57 --- /dev/null +++ b/rtl/top.sv @@ -0,0 +1,40 @@ +module top #( + parameter WIDTH = 32, +) ( + input logic clk, + input logic rst, + output logic [WIDTH-1:0] a0 +); + + logic [WIDTH-1:0] pc_out; + logic PCsrc; + logic [WIDTH-1:0] immop; + + pc_unit #(.WIDTH(WIDTH)) pc ( + .clk (clk), + .rst (rst), + .pc_src (PCsrc), + .pc_in (pc_out), + .immop (immop), + .pc_out (pc_out) + ); + + instr_mem imem ( + .addr (pc_out), + .dout (instr) + ); + + + assign alu_in2 = ALUSrc ? immop : RD2; + + alu_unit alu ( + .opA (RD1), + .opB (alu_in2), + .ALUctrl (ALUctrl), + .sum (alu_out), + .eq (EQ) + ); + + assign a0 = alu_out; + +endmodule diff --git a/repo/tb/asm/program.S b/tb/asm/program.S similarity index 100% rename from repo/tb/asm/program.S rename to tb/asm/program.S diff --git a/repo/tb/c/return_5.c b/tb/c/return_5.c similarity index 100% rename from repo/tb/c/return_5.c rename to tb/c/return_5.c diff --git a/repo/tb/compile.sh b/tb/compile.sh similarity index 100% rename from repo/tb/compile.sh rename to tb/compile.sh diff --git a/repo/tb/doit.sh b/tb/doit.sh similarity index 100% rename from repo/tb/doit.sh rename to tb/doit.sh diff --git a/repo/tb/tests/base_testbench.h b/tb/tests/base_testbench.h similarity index 100% rename from repo/tb/tests/base_testbench.h rename to tb/tests/base_testbench.h diff --git a/repo/tb/tests/mux_tb.cpp b/tb/tests/mux_tb.cpp similarity index 100% rename from repo/tb/tests/mux_tb.cpp rename to tb/tests/mux_tb.cpp diff --git a/repo/tb/tests/testbench.h b/tb/tests/testbench.h similarity index 100% rename from repo/tb/tests/testbench.h rename to tb/tests/testbench.h diff --git a/repo/tb/tests/verify.cpp b/tb/tests/verify.cpp similarity index 100% rename from repo/tb/tests/verify.cpp rename to tb/tests/verify.cpp diff --git a/verification.md b/verification.md deleted file mode 100644 index 8bc2e37..0000000 --- a/verification.md +++ /dev/null @@ -1,94 +0,0 @@ -
- -## EIE2 Instruction Set Architecture & Compiler (IAC) - ---- -## Verification - a guide - -**_@saturn691, V1.2 - 25 Oct 2024_** - ---- -
- -## Introduction - -Congratulations for taking the role of lead verification engineer! This guide -has been written by one of Peter's TAs and will follow from Lab 3. - -## Aims - -Your goal is to ensure that the CPU is **_functionally correct_**. - -## What should I do? - -There are two main things in the testing world: - -- Testing every single component. This is similar to what was done in Lab 3, and -is known in the industry as **_unit testing_**. -- Testing the CPU as a whole, known in the industry as **_integration testing_**. - -Your CPU is going to be integration tested. Whether you choose to unit test -every component is your choice, and it depends on how much you love writing -tests. - -## How do I start? - -In the attached model repository there are examples of unit tests, and examples -of verification tests. - -See [`mux_tb.cpp`](repo/tb/tests/mux_tb.cpp) for an example of a unit test. - -See [`verify.cpp`](repo/tb/tests/verify.cpp) for how your CPU implementation -will be tested. - -Your first goal, as a team, is to get `verify.cpp` to pass. You can invoke the -tests by running the [`doit.sh`](repo/tb/doit.sh) script. - -```cpp -TEST_F(CpuTestbench, BaseProgramTest) -{ - system("./compile.sh asm/program.S"); - - for (int i = 0; i < 1000; i++) - { - runSimulation(1); - if (top->a0 == 254) - { - SUCCEED(); - } - } - FAIL() << "Counter did not reach 254"; -} -``` - -If you are using the attached repository, it will -- generate a .hex file in the `rtl` folder. -- generate a .dis file in the `tb` folder. This is short for "disassembly". It -will be useful later (ignore this for now). -- generate a .vcd (waveform) file in the `tb` folder. - -## How should I think? - -This section will cover unit testbenches, as the test programs will be provided -on the spec release. - -Whilst it may seem like duplicated work to write unit testbenches (if you are -writing a golden C++ model), oftentimes this gives a lot more freedom to the -RTL writers to implement their model, without worrying about causing bugs later -down the line. - -I have not been very involved in the hardware verification space after this -coursework last year. Therefore I do not know every single best practice, but -these are some good guidelines: -- keep tests simple -- test the **_behaviour_**, not the implementation -- include some tests for simple cases (e.g. on reset) - -There is a whole space on hardware verification, and there are loads of other -guides that go into a lot more depth. However, this should be enough -information for this coursework. - -## Yeah, so what do I do? - -The choice is yours, refer to the [aims](#aims) to guide you, and then use your -creativity! \ No newline at end of file