---
# System prepended metadata

title: 'Assignment3: Your Own RISC-V CPU'

---

# Assignment3: Your Own RISC-V CPU (Still Working)
contributed by < [`eastwillow`](https://github.com/eastWillow) >

You can find the source code [here](https://github.com/eastWillow/ca2025-mycpu/tree/Add-Code-From-ca2025-quizzes). Feel free to fork and modify it.

**Acknowledgment of AI Usage**: 
Until Now I Dont Use the AI th Finsih this Homework

## Modify the handwritten RISC-V assembly code in Homework2

https://hackmd.io/@eastWillow/arch2025-homework2

### Problem A from Quiz 2 (Tower of Hanoi)

https://github.com/eastWillow/ca2025-mycpu/commit/18570ac26172c8e8aca842ade72796dbd3b4e1df

I use the `sb` to save the result in memory. So I can compare the memory result in Scala and Ripes or RV32EMU

```bash
# la      a0, str1      # address of string
# li      a1, str1_size  # length of string
# call    printstr

addi    a0, s1, 1
sb      a0, 0(s5)       # Save the Disk number to mem(7,0)
# call    print_dec

# la      a0, str2      # address of string
# li      a1, str2_size  # length of string
# call    printstr

addi    a0, t3, 0
sb      a0, 1(s5)       # Save the From. Column ASCII to mem(15,8)
# call    print_char

# la      a0, str3      # address of string
# li      a1, str3_size  # length of string
# call    printstr

addi    a0, t4, 0
sb      a0, 2(s5)       # Save the Dest. Column ASCII to mem(23,16)
# call    print_char
```

```scala
c.io.mem_debug_read_address.poke(0.U)
c.clock.step()
c.io.mem_debug_read_data.expect(0x00434101.U) // Move Disk 1 from A to C
c.io.mem_debug_read_address.poke(4.U)
c.clock.step()
c.io.mem_debug_read_data.expect(0x00424102.U) // Move Disk 2 from A to B
c.io.mem_debug_read_address.poke(8.U)
c.clock.step()
c.io.mem_debug_read_data.expect(0x00424301.U) // Move Disk 1 from C to B
c.io.mem_debug_read_address.poke(12.U)
c.clock.step()
c.io.mem_debug_read_data.expect(0x00434103.U) // Move Disk 3 from A to C
c.io.mem_debug_read_address.poke(16.U)
c.clock.step()
c.io.mem_debug_read_data.expect(0x00414201.U) // Move Disk 1 from B to A
c.io.mem_debug_read_address.poke(20.U)
c.clock.step()
c.io.mem_debug_read_data.expect(0x00434202.U) // Move Disk 2 from B to C
c.io.mem_debug_read_address.poke(24.U)
c.clock.step()
c.io.mem_debug_read_data.expect(0x00434101.U) // Move Disk 1 from A to C
```

## Express what you have learned from Chisel Bootcmap. (TODO)

{%preview https://hackmd.io/@eastWillow/arch2025-lab3 %}

## [CA25: Exercise 21] Ans: (TODO)

{%preview https://hackmd.io/@sysprog/2025-arch-homework3 %}

You should focus on how to improve MyCPU step by step, especially on how to overcome encountered issues, perform unit testing, ensure instruction set compatibility, and make sure that the software you develop can fully leverage the features of MyCPU.

```scala
  // ============================================================
  // [CA25: Exercise 21] Hazard Detection Summary and Analysis
  // ============================================================
  // Conceptual Exercise: Answer the following questions based on the hazard
  // detection logic implemented above
  //
  // Q1: Why do we need to stall for load-use hazards?
  // A: [Student answer here]
  // Hint: Consider data dependency and forwarding limitations
  //
  // Q2: What is the difference between "stall" and "flush" operations?
  // A: [Student answer here]
  // Hint: Compare their effects on pipeline registers and PC
  //
  // Q3: Why does jump instruction with register dependency need stall?
  // A: [Student answer here]
  // Hint: When is jump target address available?
  //
  // Q4: In this design, why is branch penalty only 1 cycle instead of 2?
  // A: [Student answer here]
  // Hint: Compare ID-stage vs EX-stage branch resolution
  //
  // Q5: What would happen if we removed the hazard detection logic entirely?
  // A: [Student answer here]
  // Hint: Consider data hazards and control flow correctness
  //
  // Q6: Complete the stall condition summary:
  // Stall is needed when:
  // 1. ? (EX stage condition)
  // 2. ? (MEM stage condition)
  //
  // Flush is needed when:
  // 1. ? (Branch/Jump condition)
  //
```

* For "CA25: Exercise 21" in 3-pipeline, you must perform Hazard Detection Summary and Analysis with Chisel and waveforms:
    * Why do we need to stall for load-use hazards? (Hint: Consider data dependency and forwarding limitations)
    * What is the difference between "stall" and "flush" operations? (Hint: Compare their effects on pipeline registers and PC)
    * Why does jump instruction with register dependency need stall? (Hint: When is jump target address available?)
    * In this design, why is branch penalty only 1 cycle instead of 2? (Hint: Compare ID-stage vs EX-stage branch resolution)
    * What would happen if we removed the hazard detection logic entirely? (Hint: Consider data hazards and control flow correctness)

For signals involved in filling in the blanks, use the testing framework to output waveform diagrams and describe the changes in key signals of corresponding components when executing different instructions.

# Next Step

{%preview https://hackmd.io/tw90sa8oQfKD8iNOtNecLw %}