commit 5924ed9e5dfac5942dc3ffc05ca4b45acc3faa65
parent f736439ba08a3a78179e0c41c99482d4edc2b579
Author: Bradley Gannon <bradley@bradleygannon.com>
Date: Tue, 30 Dec 2025 20:47:56 -0500
Add ControlUnitFsmTests
Diffstat:
2 files changed, 143 insertions(+), 1 deletion(-)
diff --git a/src/main/scala/controlUnit.scala b/src/main/scala/controlUnit.scala
@@ -6,7 +6,7 @@ import chisel3.util._
import com.rinthyAi.perilus.alu._
import com.rinthyAi.perilus.extendUnit._
-class ControlUnit extends Module {
+class ControlUnit(withDebug: Boolean = false) extends Module {
// Figure 7.28 (page 423)
val io = IO(new Bundle {
val op = Input(Opcode())
@@ -19,10 +19,18 @@ class ControlUnit extends Module {
val resultSrc = Output(ResultSrc())
val immSrc = Output(ImmSrc())
val aluControl = Output(AluControl())
+ val debug = if (withDebug) Some(Output(new Bundle {
+ val state = ControlUnitState()
+ }))
+ else None
})
val state = RegInit(ControlUnitState.fetch)
+ io.debug.foreach(d => {
+ d.state := state
+ })
+
val aluOp = WireDefault(AluOp.memory)
val branch, pcUpdate = WireDefault(false.B)
diff --git a/src/test/scala/perilus/controlUnit.scala b/src/test/scala/perilus/controlUnit.scala
@@ -0,0 +1,134 @@
+import chisel3._
+import chisel3.simulator.scalatest.ChiselSim
+import org.scalatest.funspec.AnyFunSpec
+
+import com.rinthyAi.perilus.controlUnit._
+
+class ControlUnitFsmTests extends AnyFunSpec with ChiselSim {
+ def checkFsmStates(dut: ControlUnit, states: List[ControlUnitState.Type]) = {
+ val debug = dut.io.debug.get
+ debug.state.expect(states.head)
+ states.tail.foreach(state => {
+ dut.clock.step(1)
+ debug.state.expect(state)
+ })
+ dut.clock.step(1)
+ debug.state.expect(states.head)
+ }
+ describe("ControlUnit") {
+ it("controls the beq instruction") {
+ simulate(new ControlUnit(withDebug = true)) { controlUnit =>
+ {
+ controlUnit.io.op.poke(Opcode.branch)
+ controlUnit.io.funct3.poke(0.U)
+ controlUnit.io.funct7_5.poke(false.B)
+ controlUnit.io.zero.poke(false.B)
+
+ val states = List(
+ ControlUnitState.fetch,
+ ControlUnitState.decode,
+ ControlUnitState.beq
+ )
+
+ checkFsmStates(controlUnit, states)
+ }
+ }
+ }
+ it("controls the jal instruction") {
+ simulate(new ControlUnit(withDebug = true)) { controlUnit =>
+ {
+ controlUnit.io.op.poke(Opcode.jal)
+ controlUnit.io.funct3.poke(0.U)
+ controlUnit.io.funct7_5.poke(false.B)
+ controlUnit.io.zero.poke(false.B)
+
+ val states = List(
+ ControlUnitState.fetch,
+ ControlUnitState.decode,
+ ControlUnitState.jal,
+ ControlUnitState.aluWb
+ )
+
+ checkFsmStates(controlUnit, states)
+ }
+ }
+ }
+ it("controls the lw instruction") {
+ simulate(new ControlUnit(withDebug = true)) { controlUnit =>
+ {
+ controlUnit.io.op.poke(Opcode.load)
+ controlUnit.io.funct3.poke(2.U)
+ controlUnit.io.funct7_5.poke(false.B)
+ controlUnit.io.zero.poke(false.B)
+
+ val states = List(
+ ControlUnitState.fetch,
+ ControlUnitState.decode,
+ ControlUnitState.memAdr,
+ ControlUnitState.memRead,
+ ControlUnitState.memWb
+ )
+
+ checkFsmStates(controlUnit, states)
+ }
+ }
+ }
+ it("controls the or instruction") {
+ simulate(new ControlUnit(withDebug = true)) { controlUnit =>
+ {
+ controlUnit.io.op.poke(Opcode.rType)
+ controlUnit.io.funct3.poke(6.U)
+ controlUnit.io.funct7_5.poke(false.B)
+ controlUnit.io.zero.poke(false.B)
+
+ val states = List(
+ ControlUnitState.fetch,
+ ControlUnitState.decode,
+ ControlUnitState.executeR,
+ ControlUnitState.aluWb
+ )
+
+ checkFsmStates(controlUnit, states)
+ }
+ }
+ }
+ it("controls the slti instruction") {
+ simulate(new ControlUnit(withDebug = true)) { controlUnit =>
+ {
+ controlUnit.io.op.poke(Opcode.immediate)
+ controlUnit.io.funct3.poke(2.U)
+ controlUnit.io.funct7_5.poke(false.B)
+ controlUnit.io.zero.poke(false.B)
+
+ val states = List(
+ ControlUnitState.fetch,
+ ControlUnitState.decode,
+ ControlUnitState.executeI,
+ ControlUnitState.aluWb
+ )
+
+ checkFsmStates(controlUnit, states)
+ }
+ }
+ }
+ it("controls the sw instruction") {
+ simulate(new ControlUnit(withDebug = true)) { controlUnit =>
+ {
+ controlUnit.io.op.poke(Opcode.store)
+ controlUnit.io.funct3.poke(2.U)
+ controlUnit.io.funct7_5.poke(false.B)
+ controlUnit.io.zero.poke(false.B)
+
+ val states = List(
+ ControlUnitState.fetch,
+ ControlUnitState.decode,
+ ControlUnitState.memAdr,
+ ControlUnitState.memWrite
+ )
+
+ checkFsmStates(controlUnit, states)
+ }
+ }
+ }
+ }
+}