commit 9b22240b1911a643a2e893fde4be9f4bb85302c9
parent 5924ed9e5dfac5942dc3ffc05ca4b45acc3faa65
Author: Bradley Gannon <bradley@bradleygannon.com>
Date: Tue, 30 Dec 2025 21:34:02 -0500
Factor out AluDecoder and InstructionDecoder and add tests for both
Diffstat:
2 files changed, 87 insertions(+), 6 deletions(-)
diff --git a/src/main/scala/controlUnit.scala b/src/main/scala/controlUnit.scala
@@ -25,6 +25,9 @@ class ControlUnit(withDebug: Boolean = false) extends Module {
else None
})
+ val aluDecoder = Module(new AluDecoder())
+ val instrDecoder = Module(new InstructionDecoder())
+
val state = RegInit(ControlUnitState.fetch)
io.debug.foreach(d => {
@@ -35,10 +38,8 @@ class ControlUnit(withDebug: Boolean = false) extends Module {
val branch, pcUpdate = WireDefault(false.B)
io.adrSrc := DontCare
- io.aluControl := DontCare
io.aluSrcA := DontCare
io.aluSrcB := DontCare
- io.immSrc := DontCare
io.irWrite := DontCare
io.memWrite := DontCare
io.regWrite := DontCare
@@ -138,8 +139,29 @@ class ControlUnit(withDebug: Boolean = false) extends Module {
io.pcWrite := (io.zero && branch) || pcUpdate
- // ALU Decoder (Table 7.3, page 409)
- switch(aluOp) {
+ aluDecoder.io.aluOp := aluOp
+ aluDecoder.io.funct3 := io.funct3
+ aluDecoder.io.funct7_5 := io.funct7_5
+ aluDecoder.io.op := io.op
+ io.aluControl := aluDecoder.io.aluControl
+
+ instrDecoder.io.op := io.op
+ io.immSrc := instrDecoder.io.immSrc
+}
+
+// ALU Decoder (Table 7.3, page 409)
+class AluDecoder extends Module {
+ val io = IO(new Bundle {
+ val aluOp = Input(AluOp())
+ val funct3 = Input(UInt(3.W))
+ val funct7_5 = Input(Bool())
+ val op = Input(Opcode())
+ val aluControl = Output(AluControl())
+ })
+
+ io.aluControl := DontCare
+
+ switch(io.aluOp) {
is(AluOp.memory) {
io.aluControl := AluControl.add
}
@@ -164,8 +186,17 @@ class ControlUnit(withDebug: Boolean = false) extends Module {
}
}
}
+}
+
+// Instruction Decoder (Table 7.6, page 413)
+class InstructionDecoder extends Module {
+ val io = IO(new Bundle {
+ val op = Input(Opcode())
+ val immSrc = Output(ImmSrc())
+ })
+
+ io.immSrc := DontCare
- // Instruction Decoder (Table 7.6, page 413)
switch(io.op) {
is(Opcode.load) {
io.immSrc := ImmSrc.iType
diff --git a/src/test/scala/perilus/controlUnit.scala b/src/test/scala/perilus/controlUnit.scala
@@ -2,9 +2,11 @@ import chisel3._
import chisel3.simulator.scalatest.ChiselSim
import org.scalatest.funspec.AnyFunSpec
+import com.rinthyAi.perilus.alu._
import com.rinthyAi.perilus.controlUnit._
+import com.rinthyAi.perilus.extendUnit._
-class ControlUnitFsmTests extends AnyFunSpec with ChiselSim {
+class ControlUnitTests extends AnyFunSpec with ChiselSim {
def checkFsmStates(dut: ControlUnit, states: List[ControlUnitState.Type]) = {
val debug = dut.io.debug.get
debug.state.expect(states.head)
@@ -15,6 +17,36 @@ class ControlUnitFsmTests extends AnyFunSpec with ChiselSim {
dut.clock.step(1)
debug.state.expect(states.head)
}
+ describe("AluDecoder") {
+ it("decodes correctly") {
+ simulate(new AluDecoder) { aluDecoder =>
+ {
+ aluDecoder.io.funct3.poke(0.U)
+ aluDecoder.io.funct7_5.poke(false.B)
+ aluDecoder.io.op.poke(Opcode.rType)
+
+ aluDecoder.io.aluOp.poke(AluOp.memory)
+ aluDecoder.io.aluControl.expect(AluControl.add)
+
+ aluDecoder.io.aluOp.poke(AluOp.branch)
+ aluDecoder.io.aluControl.expect(AluControl.sub)
+
+ aluDecoder.io.aluOp.poke(AluOp.arithmetic)
+ aluDecoder.io.op.poke(Opcode.immediate)
+ aluDecoder.io.aluControl.expect(AluControl.add)
+ aluDecoder.io.op.poke(Opcode.rType)
+ aluDecoder.io.funct7_5.poke(true.B)
+ aluDecoder.io.aluControl.expect(AluControl.sub)
+ aluDecoder.io.funct3.poke("b010".U)
+ aluDecoder.io.aluControl.expect(AluControl.slt)
+ aluDecoder.io.funct3.poke("b110".U)
+ aluDecoder.io.aluControl.expect(AluControl.or)
+ aluDecoder.io.funct3.poke("b111".U)
+ aluDecoder.io.aluControl.expect(AluControl.and)
+ }
+ }
+ }
+ }
describe("ControlUnit") {
it("controls the beq instruction") {
simulate(new ControlUnit(withDebug = true)) { controlUnit =>
@@ -131,4 +163,22 @@ class ControlUnitFsmTests extends AnyFunSpec with ChiselSim {
}
}
}
+ describe("InstructionDecoder") {
+ it("decodes correctly") {
+ simulate(new InstructionDecoder) { instrDecoder =>
+ {
+ instrDecoder.io.op.poke(Opcode.load)
+ instrDecoder.io.immSrc.expect(ImmSrc.iType)
+ instrDecoder.io.op.poke(Opcode.store)
+ instrDecoder.io.immSrc.expect(ImmSrc.sType)
+ instrDecoder.io.op.poke(Opcode.branch)
+ instrDecoder.io.immSrc.expect(ImmSrc.bType)
+ instrDecoder.io.op.poke(Opcode.immediate)
+ instrDecoder.io.immSrc.expect(ImmSrc.iType)
+ instrDecoder.io.op.poke(Opcode.jal)
+ instrDecoder.io.immSrc.expect(ImmSrc.jType)
+ }
+ }
+ }
+ }
}