# Assignment3: MyCPU
contributed by <[RayYang421](https://github.com/RayYang421/ca2025-mycpu)>
## 1-single-cycle

### Test Result
```
[info] Run completed in 45 seconds, 824 milliseconds.
[info] Total number of tests run: 9
[info] Suites: completed 7, aborted 0
[info] Tests: succeeded 9, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[success] Total time: 56 s, completed Nov 27, 2025 9:00:26 AM
```
Pass : 41 instructions

### Phase 1: Instruction Decode
**B-type**
| Immediate Bits | Instruction Bits | Description |
| -------------- | ---------------- | --------------------------- |
| imm[12] | inst[31] | Sign bit |
| imm[11] | inst[7] | Middle bit of branch offset |
| imm[10:5] | inst[30:25] | Upper bits of branch offset |
| imm[4:1] | inst[11:8] | Lower bits of branch offset |
| imm[0] | 0 | Always 0 (alignment) |
**S-type**
| Immediate Bits | Instruction Bits | Description |
| -------------- | ---------------- | ------------ |
| imm[11:5] | inst[31:25] | Upper 7 bits |
| imm[4:0] | inst[11:7] | Lower 5 bits |
**J-type**
| Immediate Bits | Instruction Bits | Description |
| -------------- | ---------------- | -------------------------- |
| imm[20] | inst[31] | Sign bit |
| imm[19:12] | inst[19:12] | Middle 8 bits |
| imm[11] | inst[20] | Isolated bit in the offset |
| imm[10:1] | inst[30:21] | Upper-middle bits |
| imm[0] | 0 | Always 0 (alignment) |
ref:

---
### Control Signal
**WriteBack data source selection**
| Category | Write-back Source | Operation |
| ------------------------ | ---------------------------------- | -------------------------------------------------- |
| **R-type** | **ALUResult** | Write the ALU computation result to `rd` |
| **I-type (arith/shift)** | **ALUResult** | Write ALU result (rs1 + imm, logic, shift) to `rd` |
| **Load** | **Memory** | Write loaded data (from memory) to `rd` |
| **LUI** | **ALUResult** (bypassed immediate) | Write upper immediate value to `rd` |
| **AUIPC** | **ALUResult** | Write `PC + imm` to `rd` |
| **JAL** | **NextInstructionAddress** | Write `PC + 4` to `rd` (return address) |
| **JALR** | **NextInstructionAddress** | Write `PC + 4` to `rd` (return address) |
| **Store** | **(no write-back)** | Store instructions do **not** write to a register |
| **Branch** | **(no write-back)** | Branch instructions do **not** write to a register |
```=
// TODO: Determine when to write back from Memory
when(isLoad) {
wbSource := RegWriteSource.Memory
}
// TODO: Determine when to write back PC+4
.elsewhen(isJal || isJalr) {
wbSource := RegWriteSource.NextInstructionAddress
}
```
**ALU operand 1 selection**
The following is talk about
| Category | Operation |
| ------------------------ | ------------------------------------------------------- |
| **R-type** | `op1 = rs1`, performs arithmetic/logic/shift with `rs2` |
| **I-type (arith/shift)** | `op1 = rs1`, performs arithmetic/logic/shift with `imm` |
| **Load** | `op1 = rs1`, computes address: `rs1 + imm` |
| **Store** | `op1 = rs1`, computes address: `rs1 + imm` |
| **Branch (comparison)** | `op1 = rs1`, compares with `rs2` (==, !=, <, >=) |
| **JALR** | `op1 = rs1`, computes jump target: `rs1 + imm` |
And we need
| Category | op1 Source |
| ------------------------------- | ------------ |
| **Branch (target calculation)** | op1 = PC |
| **JAL** | op1 = PC |
| **AUIPC** | op1 = PC |
| **LUI** | ALU not used |
```=
when(isBranch || isAuipc || isJal) {
aluOp1Sel := ALUOp1Source.InstructionAddress
}
```
**ALU operand 2 selection**
| Category | Operation |
| ------------------------- | ------------------------------------------------------- |
| **I-type (arith/shift)** | `op2 = imm`, used with `rs1` for arithmetic/logic/shift |
| **Load** | `op2 = imm`, address = `rs1 + imm` |
| **Store** | `op2 = imm`, address = `rs1 + imm` |
| **Branch (target calc.)** | `op2 = imm`, branch target = `PC + imm` |
| **JAL** | `op2 = imm`, jump target = `PC + imm` |
| **JALR** | `op2 = imm`, jump target = `rs1 + imm` |
| **AUIPC** | `op2 = imm`, result = `PC + imm` |
```=
// TODO: Determine when to use immediate as second operand
// Hint: Most instruction types except R-type use immediate
when(needsImmediate) {
aluOp2Sel := ALUOp2Source.Immediate
}
```
### Phase 2: ALU Control (Exercise 3)
| ALU Functions | Operation |
| ------------- | ------------------ |
| Arithmetic | add, sub, slt,sltu |
| Logic | and, or, xor |
| Shift | sll, sra, srl |
### Phase 3: Execution Stage (Exercises 4–5)
### Branch Comparison Logic
**Unsigned Comparison**
```
InstructionsTypeB.beq -> (io.reg1_data === io.reg2_data)
InstructionsTypeB.bne -> (io.reg1_data =/= io.reg2_data)
// Unsigned comparison
InstructionsTypeB.bltu -> (io.reg1_data < io.reg2_data)
InstructionsTypeB.bgeu -> (io.reg1_data >= io.reg2_data)
```
**Signed Comparison**
```
InstructionsTypeB.blt -> (io.reg1_data.asSINT < io.reg2_data.asSINT)
InstructionsTypeB.bge -> (io.reg1_data.asSINT >= io.reg2_data.asSINT)
```
* `.asSInt` converts a UInt to an SInt by reinterpreting the same bit pattern
### Jump Target Address Calculation
* Branch = PC + immediate (PC-relative)
* JAL = PC + immediate (PC-relative)
* JALR = (rs1 + immediate) & ~1
* ~1 is bitwise not
### Phase 4: Memory Access (Exercises 6–7)
### Load Data Extension - Sign and Zero Extension
* Sign extension: Replicate the sign bit (MSB) to fill upper bits
* Example: LB loads 0xFF → sign-extended to 0xFFFFFFFF
* Zero extension: Fill upper bits with zeros
* Example: LBU loads 0xFF → zero-extended to 0x000000FF
| Instruction | Size Loaded / Stored | Signed? | Extension (for Load) | Description |
| ----------- | -------------------- | -------- | ---------------------- | ------------------------------- |
| **LB** | 8 bits | Signed | Sign-extend to 32 bits | Load a byte and sign-extend |
| **LBU** | 8 bits | Unsigned | Zero-extend to 32 bits | Load a byte and zero-extend |
| **LH** | 16 bits | Signed | Sign-extend to 32 bits | Load a halfword and sign-extend |
| **LHU** | 16 bits | Unsigned | Zero-extend to 32 bits | Load a halfword and zero-extend |
| **LW** | 32 bits | N/A | No extension needed | Load a full word |
### Store Data Alignment - Byte Strobes & Shifting
* Byte strobes: Control which bytes in a 32-bit word are written
* Data shifting: Align data to correct byte position in 32-bit word
| Instruction | Size Stored | Description |
| ----------- | ----------- | ----------------------------------------- |
| **SB** | 8 bits | Store lowest 8 bits (byte) to memory |
| **SH** | 16 bits | Store lowest 16 bits (halfword) to memory |
| **SW** | 32 bits | Store full 32-bit word to memory |
The index is not a fixed value; it is determined by the lower two bits of the memory address and changes for each store instruction depending on the address.
## 2-mmio-trap
### Test
```
[info] Run completed in 43 seconds, 112 milliseconds.
[info] Total number of tests run: 9
[info] Suites: completed 8, aborted 0
[info] Tests: succeeded 9, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[success] Total time: 47 s, completed Nov 28, 2025 7:12:03 AM
```
**make demo**

## 3-pipeline
### Test
```
[info] Run completed in 2 minutes, 26 seconds.
[info] Total number of tests run: 29
[info] Suites: completed 3, aborted 0
[info] Tests: succeeded 27, failed 2, canceled 0, ignored 0, pending 0
[info] *** 2 TESTS FAILED ***
[error] Failed tests:
[error] riscv.PipelineProgramTest
[error] (Test / test) sbt.TestsFailedException: Tests unsuccessful
[error] Total time: 151 s (02:31), completed Nov 28, 2025 9:54:01 AM
make: *** [Makefile:8: test] Error 1
```