mirror of
https://github.com/handsomezhuzhu/2025-yatcpu.git
synced 2026-02-20 20:10:14 +00:00
Lab3 pipelined CPU renewed
- added tutorial - fix ID reg addr invalid in certain types of instructions - renamed some variables for better understanding
This commit is contained in:
@@ -23,17 +23,19 @@ class Top extends Module {
|
||||
val io = IO(new CPUBundle)
|
||||
|
||||
val cpu = Module(new CPU(implementation = ImplementationType.ThreeStage))
|
||||
|
||||
io.device_select := 0.U
|
||||
cpu.io.debug_read_address := io.debug_read_address
|
||||
io.debug_read_data := cpu.io.debug_read_data
|
||||
|
||||
// intercept UART signals
|
||||
io.device_select := cpu.io.device_select
|
||||
|
||||
// CPU instruction input is controlled by external codes
|
||||
io.memory_bundle <> cpu.io.memory_bundle
|
||||
io.instruction_address := cpu.io.instruction_address
|
||||
cpu.io.instruction := io.instruction
|
||||
cpu.io.instruction_valid := io.instruction_valid
|
||||
|
||||
cpu.io.interrupt_flag := io.interrupt_flag
|
||||
cpu.io.instruction_valid := io.instruction_valid
|
||||
}
|
||||
|
||||
object VerilogGenerator extends App {
|
||||
|
||||
@@ -82,6 +82,11 @@ class Top(binaryFilename: String = "say_goodbye.asmbin") extends Module {
|
||||
cpu.io.memory_bundle <> mem.io.bundle
|
||||
}
|
||||
}
|
||||
|
||||
when (uart.io.bundle.write_enable) {
|
||||
val the_char = cpu.io.memory_bundle.write_data(7, 0)
|
||||
printf(cf"${the_char.asUInt}%c")
|
||||
}
|
||||
}
|
||||
|
||||
// LED, blinks every second
|
||||
|
||||
@@ -81,6 +81,11 @@ class Top(binaryFilename: String = "say_goodbye.asmbin") extends Module {
|
||||
cpu.io.memory_bundle <> mem.io.bundle
|
||||
}
|
||||
}
|
||||
|
||||
when (uart.io.bundle.write_enable) {
|
||||
val the_char = cpu.io.memory_bundle.write_data(7, 0)
|
||||
printf(cf"${the_char.asUInt}%c")
|
||||
}
|
||||
}
|
||||
|
||||
// LED, blinks every second
|
||||
|
||||
@@ -61,8 +61,8 @@ class CPU extends Module {
|
||||
inst_fetch.io.rom_instruction := io.instruction
|
||||
inst_fetch.io.instruction_valid := io.instruction_valid
|
||||
|
||||
if2id.io.stall := ctrl.io.if_stall
|
||||
if2id.io.flush := ctrl.io.if_flush
|
||||
if2id.io.stall := ctrl.io.if2id_stall
|
||||
if2id.io.flush := ctrl.io.if2id_flush
|
||||
if2id.io.instruction := inst_fetch.io.id_instruction
|
||||
if2id.io.instruction_address := inst_fetch.io.instruction_address
|
||||
if2id.io.interrupt_flag := io.interrupt_flag
|
||||
@@ -78,7 +78,7 @@ class CPU extends Module {
|
||||
id.io.interrupt_assert := clint.io.id_interrupt_assert
|
||||
id.io.interrupt_handler_address := clint.io.id_interrupt_handler_address
|
||||
|
||||
id2ex.io.flush := ctrl.io.id_flush
|
||||
id2ex.io.flush := ctrl.io.id2ex_flush
|
||||
id2ex.io.instruction := if2id.io.output_instruction
|
||||
id2ex.io.instruction_address := if2id.io.output_instruction_address
|
||||
id2ex.io.reg1_data := regs.io.read_data1
|
||||
|
||||
@@ -28,16 +28,16 @@ class Control extends Module {
|
||||
val memory_read_enable_mem = Input(Bool())
|
||||
val rd_mem = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
|
||||
val if_flush = Output(Bool())
|
||||
val id_flush = Output(Bool())
|
||||
val if2id_flush = Output(Bool())
|
||||
val id2ex_flush = Output(Bool())
|
||||
val pc_stall = Output(Bool())
|
||||
val if_stall = Output(Bool())
|
||||
val if2id_stall = Output(Bool())
|
||||
})
|
||||
|
||||
// Lab3(Final)
|
||||
io.if_flush := false.B
|
||||
io.id_flush := false.B
|
||||
io.if2id_flush := false.B
|
||||
io.id2ex_flush := false.B
|
||||
io.pc_stall := false.B
|
||||
io.if_stall := false.B
|
||||
io.if2id_stall := false.B
|
||||
// Lab3(Final) End
|
||||
}
|
||||
|
||||
@@ -170,8 +170,10 @@ class InstructionDecode extends Module {
|
||||
val rs1 = io.instruction(19, 15)
|
||||
val rs2 = io.instruction(24, 20)
|
||||
|
||||
io.regs_reg1_read_address := Mux(opcode === Instructions.lui, 0.U(Parameters.PhysicalRegisterAddrWidth), rs1)
|
||||
// Lab3(Final) ID rs
|
||||
io.regs_reg1_read_address := rs1
|
||||
io.regs_reg2_read_address := rs2
|
||||
// Lab3(Final) ID rs End
|
||||
io.ex_immediate := MuxLookup(
|
||||
opcode,
|
||||
Cat(Fill(20, io.instruction(31)), io.instruction(31, 20)),
|
||||
@@ -208,10 +210,10 @@ class InstructionDecode extends Module {
|
||||
Instructions.jalr -> RegWriteSource.NextInstructionAddress
|
||||
)
|
||||
)
|
||||
io.ex_reg_write_enable := (opcode === InstructionTypes.RM) || (opcode === InstructionTypes.I) ||
|
||||
(opcode === InstructionTypes.L) || (opcode === Instructions.auipc) || (opcode === Instructions.lui) ||
|
||||
(opcode === Instructions.jal) || (opcode === Instructions.jalr) || (opcode === Instructions.csr)
|
||||
io.ex_reg_write_address := io.instruction(11, 7)
|
||||
// Lab3(Final) ID rd
|
||||
io.ex_reg_write_enable := false.B
|
||||
io.ex_reg_write_address := rd
|
||||
// Lab3(Final) ID rd End
|
||||
io.ex_csr_address := io.instruction(31, 20)
|
||||
io.ex_csr_write_enable := (opcode === Instructions.csr) && (
|
||||
funct3 === InstructionsTypeCSR.csrrw || funct3 === InstructionsTypeCSR.csrrwi ||
|
||||
|
||||
@@ -58,15 +58,15 @@ class CPU extends Module {
|
||||
inst_fetch.io.rom_instruction := io.instruction
|
||||
inst_fetch.io.instruction_valid := io.instruction_valid
|
||||
|
||||
if2id.io.stall := ctrl.io.if_stall
|
||||
if2id.io.flush := ctrl.io.if_flush
|
||||
if2id.io.stall := ctrl.io.if2id_stall
|
||||
if2id.io.flush := ctrl.io.if2id_flush
|
||||
if2id.io.instruction := inst_fetch.io.id_instruction
|
||||
if2id.io.instruction_address := inst_fetch.io.instruction_address
|
||||
if2id.io.interrupt_flag := io.interrupt_flag
|
||||
|
||||
id.io.instruction := if2id.io.output_instruction
|
||||
|
||||
id2ex.io.flush := ctrl.io.id_flush
|
||||
id2ex.io.flush := ctrl.io.id2ex_flush
|
||||
id2ex.io.instruction := if2id.io.output_instruction
|
||||
id2ex.io.instruction_address := if2id.io.output_instruction_address
|
||||
id2ex.io.reg1_data := regs.io.read_data1
|
||||
|
||||
@@ -25,16 +25,16 @@ class Control extends Module {
|
||||
val memory_read_enable_ex = Input(Bool())
|
||||
val rd_ex = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
|
||||
val if_flush = Output(Bool())
|
||||
val id_flush = Output(Bool())
|
||||
val if2id_flush = Output(Bool())
|
||||
val id2ex_flush = Output(Bool())
|
||||
val pc_stall = Output(Bool())
|
||||
val if_stall = Output(Bool())
|
||||
val if2id_stall = Output(Bool())
|
||||
})
|
||||
|
||||
// Lab3(Forward)
|
||||
io.if_flush := false.B
|
||||
io.id_flush := false.B
|
||||
io.if2id_flush := false.B
|
||||
io.id2ex_flush := false.B
|
||||
io.pc_stall := false.B
|
||||
io.if_stall := false.B
|
||||
io.if2id_stall := false.B
|
||||
// Lab3(Forward) End
|
||||
}
|
||||
|
||||
@@ -156,8 +156,10 @@ class InstructionDecode extends Module {
|
||||
val rs1 = io.instruction(19, 15)
|
||||
val rs2 = io.instruction(24, 20)
|
||||
|
||||
io.regs_reg1_read_address := Mux(opcode === Instructions.lui, 0.U(Parameters.PhysicalRegisterAddrWidth), rs1)
|
||||
// Lab3(Forwarding) ID rs
|
||||
io.regs_reg1_read_address := rs1
|
||||
io.regs_reg2_read_address := rs2
|
||||
// Lab3(Forwarding) ID rs End
|
||||
io.ex_immediate := MuxLookup(
|
||||
opcode,
|
||||
Cat(Fill(20, io.instruction(31)), io.instruction(31, 20)),
|
||||
@@ -194,10 +196,10 @@ class InstructionDecode extends Module {
|
||||
Instructions.jalr -> RegWriteSource.NextInstructionAddress
|
||||
)
|
||||
)
|
||||
io.ex_reg_write_enable := (opcode === InstructionTypes.RM) || (opcode === InstructionTypes.I) ||
|
||||
(opcode === InstructionTypes.L) || (opcode === Instructions.auipc) || (opcode === Instructions.lui) ||
|
||||
(opcode === Instructions.jal) || (opcode === Instructions.jalr) || (opcode === Instructions.csr)
|
||||
io.ex_reg_write_address := io.instruction(11, 7)
|
||||
// Lab3(Forwarding) ID rd
|
||||
io.ex_reg_write_enable := false.B
|
||||
io.ex_reg_write_address := rd
|
||||
// Lab3(Forwarding) ID rd End
|
||||
io.ex_csr_address := io.instruction(31, 20)
|
||||
io.ex_csr_write_enable := (opcode === Instructions.csr) && (
|
||||
funct3 === InstructionsTypeCSR.csrrw || funct3 === InstructionsTypeCSR.csrrwi ||
|
||||
|
||||
@@ -59,15 +59,15 @@ class CPU extends Module {
|
||||
inst_fetch.io.rom_instruction := io.instruction
|
||||
inst_fetch.io.instruction_valid := io.instruction_valid
|
||||
|
||||
if2id.io.stall := ctrl.io.if_stall
|
||||
if2id.io.flush := ctrl.io.if_flush
|
||||
if2id.io.stall := ctrl.io.if2id_stall
|
||||
if2id.io.flush := ctrl.io.if2id_flush
|
||||
if2id.io.instruction := inst_fetch.io.id_instruction
|
||||
if2id.io.instruction_address := inst_fetch.io.instruction_address
|
||||
if2id.io.interrupt_flag := io.interrupt_flag
|
||||
|
||||
id.io.instruction := if2id.io.output_instruction
|
||||
|
||||
id2ex.io.flush := ctrl.io.id_flush
|
||||
id2ex.io.flush := ctrl.io.id2ex_flush
|
||||
id2ex.io.instruction := if2id.io.output_instruction
|
||||
id2ex.io.instruction_address := if2id.io.output_instruction_address
|
||||
id2ex.io.reg1_data := regs.io.read_data1
|
||||
|
||||
@@ -27,17 +27,17 @@ class Control extends Module {
|
||||
val rd_mem = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val reg_write_enable_mem = Input(Bool())
|
||||
|
||||
val if_flush = Output(Bool())
|
||||
val id_flush = Output(Bool())
|
||||
val if2id_flush = Output(Bool())
|
||||
val id2ex_flush = Output(Bool())
|
||||
val pc_stall = Output(Bool())
|
||||
val if_stall = Output(Bool())
|
||||
val if2id_stall = Output(Bool())
|
||||
})
|
||||
|
||||
// Lab3(Stall)
|
||||
io.if_flush := false.B
|
||||
io.id_flush := false.B
|
||||
io.if2id_flush := false.B
|
||||
io.id2ex_flush := false.B
|
||||
|
||||
io.pc_stall := false.B
|
||||
io.if_stall := false.B
|
||||
io.if2id_stall := false.B
|
||||
// Lab3(Stall) End
|
||||
}
|
||||
|
||||
@@ -156,8 +156,10 @@ class InstructionDecode extends Module {
|
||||
val rs1 = io.instruction(19, 15)
|
||||
val rs2 = io.instruction(24, 20)
|
||||
|
||||
io.regs_reg1_read_address := Mux(opcode === Instructions.lui, 0.U(Parameters.PhysicalRegisterAddrWidth), rs1)
|
||||
// Lab3(Stall) ID rs
|
||||
io.regs_reg1_read_address := rs1
|
||||
io.regs_reg2_read_address := rs2
|
||||
// Lab3(Stall) ID rs End
|
||||
io.ex_immediate := MuxLookup(
|
||||
opcode,
|
||||
Cat(Fill(20, io.instruction(31)), io.instruction(31, 20)),
|
||||
@@ -194,10 +196,10 @@ class InstructionDecode extends Module {
|
||||
Instructions.jalr -> RegWriteSource.NextInstructionAddress
|
||||
)
|
||||
)
|
||||
io.ex_reg_write_enable := (opcode === InstructionTypes.RM) || (opcode === InstructionTypes.I) ||
|
||||
(opcode === InstructionTypes.L) || (opcode === Instructions.auipc) || (opcode === Instructions.lui) ||
|
||||
(opcode === Instructions.jal) || (opcode === Instructions.jalr) || (opcode === Instructions.csr)
|
||||
io.ex_reg_write_address := io.instruction(11, 7)
|
||||
// Lab3(Stall) ID rd
|
||||
io.ex_reg_write_enable := false.B
|
||||
io.ex_reg_write_address := rd
|
||||
// Lab3(Stall) ID rd End
|
||||
io.ex_csr_address := io.instruction(31, 20)
|
||||
io.ex_csr_write_enable := (opcode === Instructions.csr) && (
|
||||
funct3 === InstructionsTypeCSR.csrrw || funct3 === InstructionsTypeCSR.csrrwi ||
|
||||
|
||||
@@ -71,3 +71,4 @@ class FiveStageCPUForwardTest extends AnyFlatSpec with ChiselScalatestTester {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ package riscv
|
||||
import chisel3._
|
||||
import chiseltest._
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import scala.util.Random
|
||||
import riscv.core.fivestage_stall._
|
||||
|
||||
|
||||
class FiveStageCPUStallTest extends AnyFlatSpec with ChiselScalatestTester {
|
||||
@@ -71,3 +73,86 @@ class FiveStageCPUStallTest extends AnyFlatSpec with ChiselScalatestTester {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class DecoderStallTest extends AnyFlatSpec with ChiselScalatestTester {
|
||||
behavior of "ID of Five-stage Pipelined CPU with Stalling"
|
||||
|
||||
def concatBits(values: (Int, Int)*): Int = {
|
||||
values.foldLeft(0) { case (result, (value, bits)) =>
|
||||
val mask = (1 << bits) - 1 // Create mask for the specified bit width
|
||||
val maskedValue = value & mask // Ensure value fits in specified bits
|
||||
(result << bits) | maskedValue
|
||||
}
|
||||
}
|
||||
|
||||
it should "generate correct reg addr" in {
|
||||
test(new InstructionDecode).withAnnotations(TestAnnotations.annos) { c =>
|
||||
|
||||
for (i <- 0 to 100) {
|
||||
val rs1 = Random.nextInt(32)
|
||||
val rs2 = Random.nextInt(32)
|
||||
val rd = Random.nextInt(32)
|
||||
|
||||
// for R-type instructions, rs2, rs1 and rd should be valid
|
||||
// val instR = 0.U(7.W) ## rs2 ## rs1 ## 1.U(3.W) ## rd ## InstructionTypes.RM
|
||||
val instR = concatBits(
|
||||
(0, 7), (rs2, 5), (rs1, 5), (1, 3), (rd, 5), (InstructionTypes.RM.litValue.toInt, 7)
|
||||
)
|
||||
c.io.instruction.poke(instR)
|
||||
c.io.regs_reg1_read_address.expect(rs1)
|
||||
c.io.regs_reg2_read_address.expect(rs2)
|
||||
c.io.ex_reg_write_address.expect(rd)
|
||||
c.io.ex_reg_write_enable.expect(true.B)
|
||||
c.clock.step()
|
||||
|
||||
// for I-type instructions, rs1 and rd should be valid
|
||||
val instI = concatBits((0, 12), (rs1, 5), (1, 3), (rd, 5), (InstructionTypes.I.litValue.toInt, 7))
|
||||
c.io.instruction.poke(instI)
|
||||
c.io.regs_reg1_read_address.expect(rs1)
|
||||
c.io.regs_reg2_read_address.expect(0.U)
|
||||
c.io.ex_reg_write_address.expect(rd)
|
||||
c.io.ex_reg_write_enable.expect(true.B)
|
||||
c.clock.step()
|
||||
|
||||
// for S-type instructions, rs2 and rs1 should be valid
|
||||
val instS = concatBits((0, 7), (rs2, 5), (rs1, 5), (1, 3), (2, 5), (InstructionTypes.S.litValue.toInt, 7))
|
||||
c.io.instruction.poke(instS)
|
||||
c.io.regs_reg1_read_address.expect(rs1)
|
||||
c.io.regs_reg2_read_address.expect(rs2)
|
||||
c.io.ex_reg_write_address.expect(0.U)
|
||||
c.io.ex_reg_write_enable.expect(false.B)
|
||||
c.clock.step()
|
||||
|
||||
// for B-type instructions, rs2 and rs1 should be valid
|
||||
val instB = concatBits((0, 7), (rs2, 5), (rs1, 5), (1, 3), (2, 5), (InstructionTypes.B.litValue.toInt, 7))
|
||||
c.io.instruction.poke(instB)
|
||||
c.io.regs_reg1_read_address.expect(rs1)
|
||||
c.io.regs_reg2_read_address.expect(rs2)
|
||||
c.io.ex_reg_write_address.expect(0.U)
|
||||
c.io.ex_reg_write_enable.expect(false.B)
|
||||
c.clock.step()
|
||||
|
||||
// for U-type instructions, rd should be valid
|
||||
val instU = concatBits((0, 20), (rd, 5), (Instructions.lui.litValue.toInt, 7))
|
||||
c.io.instruction.poke(instU)
|
||||
c.io.regs_reg1_read_address.expect(0.U)
|
||||
c.io.regs_reg2_read_address.expect(0.U)
|
||||
c.io.ex_reg_write_address.expect(rd)
|
||||
c.io.ex_reg_write_enable.expect(true.B)
|
||||
c.clock.step()
|
||||
|
||||
// for J-type instructions, rd should be valid
|
||||
val instJ = concatBits((0, 20), (rd, 5), (Instructions.jal.litValue.toInt, 7))
|
||||
c.io.instruction.poke(instJ)
|
||||
c.io.regs_reg1_read_address.expect(0.U)
|
||||
c.io.regs_reg2_read_address.expect(0.U)
|
||||
c.io.ex_reg_write_address.expect(rd)
|
||||
c.io.ex_reg_write_enable.expect(true.B)
|
||||
c.clock.step()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user