perilus

git clone https://git.bradleygannon.com/perilus.git
Log | Files | Refs | Submodules | README

commit e1885a909491dfcaebfbacdf2bc3b1b0095b3431
parent 2a60eae4eae580443792e072aa31c1df80c5d388
Author: Bradley Gannon <bradley@bradleygannon.com>
Date:   Thu,  2 Apr 2026 20:26:23 -0400

Add support for lui and auipc

Diffstat:
Msrc/main/scala/alu.scala | 4++--
Msrc/main/scala/controlUnit.scala | 30++++++++++++++++++++++++++++--
Msrc/main/scala/extendUnit.scala | 5++++-
Msrc/main/scala/main.scala | 3+++
Msrc/test/scala/perilus/main.scala | 46++++++++++++++++++++++++++++++++++++++++++++--
5 files changed, 81 insertions(+), 7 deletions(-)

diff --git a/src/main/scala/alu.scala b/src/main/scala/alu.scala @@ -72,9 +72,9 @@ object AluSrcB extends ChiselEnum { } object AluOp extends ChiselEnum { - val memory, branch, arithmetic = Value + val memory, branch, arithmetic, auipc = Value } object ResultSrc extends ChiselEnum { - val aluOutBuf, readDataBuf, aluResult = Value + val aluOutBuf, readDataBuf, aluResult, immExt = Value } diff --git a/src/main/scala/controlUnit.scala b/src/main/scala/controlUnit.scala @@ -87,6 +87,10 @@ class ControlUnit(withDebug: Boolean = false) extends Module { state := ControlUnitState.jalrLink }.elsewhen(io.op === Opcode.branch) { state := ControlUnitState.branch + }.elsewhen(io.op === Opcode.lui) { + state := ControlUnitState.lui + }.elsewhen(io.op === Opcode.auipc) { + state := ControlUnitState.auipc }.elsewhen(io.op === Opcode.env || io.op === Opcode.fence) { state := ControlUnitState.fetch } @@ -169,13 +173,26 @@ class ControlUnit(withDebug: Boolean = false) extends Module { branch := true.B state := ControlUnitState.fetch } + is(ControlUnitState.lui) { + io.resultSrc := ResultSrc.immExt + io.regWrite := true.B + state := ControlUnitState.fetch + } + is(ControlUnitState.auipc) { + io.resultSrc := ResultSrc.aluResult + io.aluSrcA := AluSrcA.oldPc + io.aluSrcB := AluSrcB.immExt + aluOp := AluOp.auipc + io.regWrite := true.B + state := ControlUnitState.fetch + } } io.pcWrite := ((branch && ((io.funct3 === 0.U && io.zero) || (io.funct3 === 1.U && !io.zero) || ((io.funct3 === 4.U || io.funct3 === 6.U) && io.lessThan) || ((io.funct3 === 5.U || io.funct3 === 7.U) && !io.lessThan))) - || pcUpdate) + || pcUpdate) aluDecoder.io.aluOp := aluOp aluDecoder.io.funct3 := io.funct3 @@ -201,6 +218,9 @@ class AluDecoder extends Module { io.aluControl := AluControl.add switch(io.aluOp) { + is(AluOp.auipc) { + io.aluControl := AluControl.add + } is(AluOp.memory) { io.aluControl := AluControl.add } @@ -277,12 +297,18 @@ class InstructionDecoder extends Module { is(Opcode.jal) { io.immSrc := ImmSrc.jType } + is(Opcode.lui) { + io.immSrc := ImmSrc.uType + } + is(Opcode.auipc) { + io.immSrc := ImmSrc.uType + } } } object ControlUnitState extends ChiselEnum { val fetch, decode, memAdr, memRead, memWb, memWrite, executeR, aluWb, executeI, jal, jalrLink, - jalrJump, branch = + jalrJump, branch, lui, auipc = Value } diff --git a/src/main/scala/extendUnit.scala b/src/main/scala/extendUnit.scala @@ -41,9 +41,12 @@ class ExtendUnit extends Module { 0.U(1.W) ) } + is(ImmSrc.uType) { + io.immExt := Cat(io.input(24, 5), Fill(12, 0.U)) + } } } object ImmSrc extends ChiselEnum { - val iTypeSigned, iTypeUnsigned, sType, bType, jType = Value + val iTypeSigned, iTypeUnsigned, sType, bType, jType, uType = Value } diff --git a/src/main/scala/main.scala b/src/main/scala/main.scala @@ -109,6 +109,9 @@ class Perilus( is(ResultSrc.aluResult) { result := alu.io.aluResult } + is(ResultSrc.immExt) { + result := extendUnit.io.immExt + } } alu.io.aluControl := controlUnit.io.aluControl diff --git a/src/test/scala/perilus/main.scala b/src/test/scala/perilus/main.scala @@ -289,11 +289,53 @@ class PerilusTests extends AnyFunSpec with ChiselSim { } } describe("executes U-type RV32I instructions") { + def testUType( + imm: Int, + rd: Int, + op: Int + ) = { + val immMasked = (imm & 0xfffff000) + val rdShifted = (rd & 0x1f) << 7 + val instr = immMasked | rdShifted | op + + var registerFile = ArrayBuffer.fill(32)(0x00000000) + var memory = ArrayBuffer.fill(64)(0x00000000) + val test_pc = 48 + memory(0) = 0x02000863 // beq x0, x0, 48 + memory(test_pc / 4) = instr + val expected = if (op == 0x17) { immMasked + test_pc } + else { immMasked } + + simulate( + new Perilus( + initRegs = initMemFile(registerFile), + initMem = initMemFile(memory), + withDebug = true + ) + ) { perilus => + { + val perilusDebug = perilus.io.debug.get + perilusDebug.memAddr.poke(test_pc) + perilusDebug.memData.expect(toULong(instr)) + perilus.clock.step(6) + perilusDebug.reg.poke(rd) + perilusDebug.regData.expect(toULong(expected)) + } + } + } it("auipc") { - cancel("Not yet implemented") + testUType( + imm = 0xf5540000, + rd = 29, + op = 0x17 + ) } it("lui") { - cancel("Not yet implemented") + testUType( + imm = 0xc6fed000, + rd = 21, + op = 0x37 + ) } } describe("executes S-type RV32I instructions") {