# Assignment3: single-cycle RISC-V CPU
Contributed by [P76121089](https://github.com/00853029/ca2023-lab3)
## Environment and Setup
> Follow [Lab3: Construct a single-cycle RISC-V CPU with Chisel](https://hackmd.io/@sysprog/r1mlr3I7p)
Virtual Box: **ubuntu22.04.3**
Install **sdkman**
Install **Eclipse Temurin JDK 11**
## Single-cycle RISC-V CPU
#### Get the repository:
```shell
$ git clone https://github.com/sysprog21/ca2023-lab3
```

### Finish MyCPU
#### 1. InstructionFetch
The original code forgot to control the PC (Program Counter).
Therefore, I added a condition to determine whether to jump, deciding whether the PC value should go to the `jump_address` or `pc + 4`(move to next instruction).
> Source: `./ca2023-lab3/src/main/scala/riscv/core/InstructionFetch.scala`
#### 2. InstructionDecode
The original code didn't determine the control signals for `memory_read_enable`(*MemRead*) and `memory_write_enable`(*MemWrite*).
Therefore, I added conditions to control these two memory control signals.(by opcode value)

> Source: `src/main/scala/riscv/core/InstructionDecode.scala`
#### 3. Execute
The original code didn't pass signal lines into the ALU for computation.
Therefore, I included the `op1`, `op2` resources, and `func` control signal into the ALU module. Then, the `alu.io.result` will be connected to the output in the following code.
> Source: `src/main/scala/riscv/core/Execute.scala`
#### 4. CPU
I added connections between the id module and exe module that were previously unconnected in the original code.
> Source: `src/main/scala/riscv/core/CPU.scala`
### Run Test program using MyCPU
#### Preparatory Work
- Modify the previous assembly code to allow storing the answer to a specified memory address, enabling verification of the answer at the same address in the testbench code.
```c
# Clear the memory intended to store the answer
li t0, 0
sw zero, 0(t0)
sw zero, 4(t0)
sw zero, 8(t0)
sw zero, 12(t0)
sw zero, 16(t0)
...
Print:
slli s0,t6,2
add s1,sp,s0
lw a0,0(s1)
#*store answer to the specified memory address*
slli t5, t6, 2
sw a0, 0(t5)
#------------------------
li a7,2
ecall
addi t6,t6,1
la a0,_EOL
li a7,4
ecall
beq t6,s11,End
jal Print
```
#### 1. Compile pervious assembly code to `asmbin` file
- Put the previous assembly code into the directory(`ca2023-lab3/csrc`)
- Modify Makefile
```shell
BINS = \
shellSort.asmbin \
...
```
- Use `make update` operation to compile all file in the directory.
#### 2. Modify CPUTest
- Setting the memory address where the final answer will be stored
- Specifying the expected outcome.
> `src/test/scala/riscv/singlecycle/CPUTest.scala`
```scala
class shellSort extends AnyFlatSpec with ChiselScalatestTester {
behavior.of("Single Cycle CPU")
it should "shellSort function" in {
test(new TestTopModule("shellSort.asmbin")).withAnnotations(TestAnnotations.annos) { c =>
for (i <- 1 to 10000) {
c.clock.step(1000)
c.io.mem_debug_read_address.poke((i * 4).U) // Avoid timeout
}
//check answer begin
//***memory***
c.io.mem_debug_read_address.poke(0.U)
c.clock.step()
c.io.mem_debug_read_data.expect(0xbfc00000L.U)
c.io.mem_debug_read_address.poke(4.U)
c.clock.step()
c.io.mem_debug_read_data.expect(0xbfa60000L.U)
c.io.mem_debug_read_address.poke(8.U)
c.clock.step()
c.io.mem_debug_read_data.expect(0xbf8c0000L.U)
c.io.mem_debug_read_address.poke(12.U)
c.clock.step()
c.io.mem_debug_read_data.expect(0x3f990000L.U)
c.io.mem_debug_read_address.poke(16.U)
c.clock.step()
c.io.mem_debug_read_data.expect(0x3fb30000L.U)
//end---
}
}
}
```
#### 3. Run Test program using MyCPU
**First:** move current directory to ca2023-lab3
```shell
cd ca2023-lab3
```
**Second:** use `make test > test.log` operation to run all test programs and store the information into test.log.
> test.log
```shell
$ sbt test
[info] welcome to sbt 1.9.7 (Ubuntu Java 11.0.21)
[info] loading settings for project ca2023-lab3-build from plugins.sbt ...
[info] loading project definition from /home/vboxuser/ca2023-lab3/project
[info] loading settings for project root from build.sbt ...
[info] set current project to mycpu (in build file:/home/vboxuser/ca2023-lab3/)
[info] InstructionDecoderTest:
[info] InstructionDecoder of Single Cycle CPU
[info] - should produce correct control signal
[info] RegisterFileTest:
[info] Register File of Single Cycle CPU
[info] - should read the written content
[info] - should x0 always be zero
[info] - should read the writing content
[info] InstructionFetchTest:
[info] InstructionFetch of Single Cycle CPU
[info] - should fetch instruction
[info] ExecuteTest:
[info] Execution of Single Cycle CPU
[info] - should execute correctly
[info] shellSort:
[info] Single Cycle CPU
[info] - should shellSort function
[info] Run completed in 2 minutes, 59 seconds.
[info] Total number of tests run: 7
[info] Suites: completed 5, aborted 0
[info] Tests: succeeded 7, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[success] Total time: 181 s (03:01), completed Dec 1, 2023, 8:37:39 PM
```
## Verify the answer waveform using GTKWave.
run `WRITE_VCD=1 sbt test` to create waveform.
#### 1. Store the answer in the specified memory address.
#### 2. write_enable signal = 1
#### 3. write_enable signal = 4'b1111 -> store word
- address : 0x00000000
- write_data(answer): 0xBFC00000

- address : 0x00000004
- write_data(answer): 0xBFA60000

- address : 0x00000008
- write_data(answer): 0xBF8C0000

- address : 0x0000000C
- write_data(answer): 0x3F990000

- address : 0x00000010
- write_data(answer): 0x3FB30000
