# Assignment3: MyCPU contributed by <[RayYang421](https://github.com/RayYang421/ca2025-mycpu)> ## 1-single-cycle ![image](https://hackmd.io/_uploads/B1WCDljebl.png) ### 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 ![image](https://hackmd.io/_uploads/rkWL13CZbe.png) ### 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: ![image](https://hackmd.io/_uploads/SJtHF5YgZe.png) --- ### 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** ![image](https://hackmd.io/_uploads/BJFsmoCZWx.png) ## 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 ```