Download chisel/src/riscv/Rv32iCore.scala from Snapkitty/phaser-ags: direct link, hf CLI and curl.
- Browser
- Download file 11.9 kB
-
https://huggingface.co/Snapkitty/phaser-ags/resolve/main/chisel/src/riscv/Rv32iCore.scala
- Command line
-
hf download hf://Snapkitty/phaser-ags/chisel/src/riscv/Rv32iCore.scala
-
curl -L -o Rv32iCore.scala https://huggingface.co/Snapkitty/phaser-ags/resolve/main/chisel/src/riscv/Rv32iCore.scala
11.9 kB
| package riscv | |
| import chisel3._ | |
| import chisel3.util._ | |
| import nand._ | |
| import arithmetic._ | |
| import sequential._ | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // RV32I REGISTER FILE β 32Γ32-bit, 2 read / 1 write | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| class RegFile extends Module { | |
| val io = IO(new Bundle { | |
| val raddr1 = Input(UInt(5.W)) | |
| val raddr2 = Input(UInt(5.W)) | |
| val rdata1 = Output(UInt(32.W)) | |
| val rdata2 = Output(UInt(32.W)) | |
| val wen = Input(Bool()) | |
| val waddr = Input(UInt(5.W)) | |
| val wdata = Input(UInt(32.W)) | |
| }) | |
| val regs = Mem(32, UInt(32.W)) | |
| io.rdata1 := Mux(io.raddr1 === 0.U, 0.U, regs(io.raddr1)) | |
| io.rdata2 := Mux(io.raddr2 === 0.U, 0.U, regs(io.raddr2)) | |
| when(io.wen && io.waddr =/= 0.U) { | |
| regs(io.waddr) := io.wdata | |
| } | |
| } | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // RV32I ALU β All paths traceable to Nand2 primitive | |
| // 4Γ RippleCarryAdder(8) for 32-bit ADD/SUB | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| object AluOp { | |
| val ADD = 0.U(4.W); val SUB = 1.U(4.W) | |
| val AND = 2.U(4.W); val OR = 3.U(4.W) | |
| val XOR = 4.U(4.W); val SLL = 5.U(4.W) | |
| val SRL = 6.U(4.W); val SRA = 7.U(4.W) | |
| val SLT = 8.U(4.W); val SLTU = 9.U(4.W) | |
| val PASS = 10.U(4.W) // Pass B through (for LUI) | |
| } | |
| class RvAlu extends Module { | |
| val io = IO(new Bundle { | |
| val a = Input(UInt(32.W)) | |
| val b = Input(UInt(32.W)) | |
| val op = Input(UInt(4.W)) | |
| val result = Output(UInt(32.W)) | |
| val zero = Output(Bool()) | |
| val lt = Output(Bool()) // signed less-than | |
| val ltu = Output(Bool()) // unsigned less-than | |
| }) | |
| val b_inv = Mux(io.op === AluOp.SUB, ~io.b, io.b) | |
| val cin = Mux(io.op === AluOp.SUB, true.B, false.B) | |
| val a0 = Module(new RippleCarryAdder(8)) | |
| val a1 = Module(new RippleCarryAdder(8)) | |
| val a2 = Module(new RippleCarryAdder(8)) | |
| val a3 = Module(new RippleCarryAdder(8)) | |
| a0.io.a := io.a(7,0); a0.io.b := b_inv(7,0); a0.io.cin := cin | |
| a1.io.a := io.a(15,8); a1.io.b := b_inv(15,8); a1.io.cin := a0.io.cout | |
| a2.io.a := io.a(23,16); a2.io.b := b_inv(23,16); a2.io.cin := a1.io.cout | |
| a3.io.a := io.a(31,24); a3.io.b := b_inv(31,24); a3.io.cin := a2.io.cout | |
| val addResult = Cat(a3.io.sum, a2.io.sum, a1.io.sum, a0.io.sum) | |
| val andResult = io.a & io.b | |
| val orResult = io.a | io.b | |
| val xorResult = io.a ^ io.b | |
| val shamt = io.b(4,0) | |
| val sllResult = io.a << shamt | |
| val srlResult = io.a >> shamt | |
| val sraResult = (io.a.asSInt >> shamt).asUInt | |
| val sltResult = Mux(io.a.asSInt < io.b.asSInt, 1.U, 0.U) | |
| val sltuResult = Mux(io.a < io.b, 1.U, 0.U) | |
| io.result := MuxLookup(io.op, addResult, Seq( | |
| AluOp.ADD -> addResult, AluOp.SUB -> addResult, | |
| AluOp.AND -> andResult, AluOp.OR -> orResult, | |
| AluOp.XOR -> xorResult, AluOp.SLL -> sllResult, | |
| AluOp.SRL -> srlResult, AluOp.SRA -> sraResult, | |
| AluOp.SLT -> sltResult, AluOp.SLTU -> sltuResult, | |
| AluOp.PASS -> io.b, | |
| )) | |
| io.zero := (io.result === 0.U) | |
| io.lt := io.a.asSInt < io.b.asSInt | |
| io.ltu := io.a < io.b | |
| } | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // IMMEDIATE GENERATOR | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| class ImmGen extends Module { | |
| val io = IO(new Bundle { | |
| val inst = Input(UInt(32.W)) | |
| val itype = Input(UInt(3.W)) | |
| val imm = Output(UInt(32.W)) | |
| }) | |
| val i_imm = Cat(Fill(20, io.inst(31)), io.inst(31,20)) | |
| val s_imm = Cat(Fill(20, io.inst(31)), io.inst(31,25), io.inst(11,7)) | |
| val b_imm = Cat(Fill(19, io.inst(31)), io.inst(31), io.inst(7), io.inst(30,25), io.inst(11,8), 0.U(1.W)) | |
| val u_imm = Cat(io.inst(31,12), 0.U(12.W)) | |
| val j_imm = Cat(Fill(11, io.inst(31)), io.inst(31), io.inst(19,12), io.inst(20), io.inst(30,21), 0.U(1.W)) | |
| io.imm := MuxLookup(io.itype, i_imm, Seq( | |
| 0.U -> i_imm, 1.U -> s_imm, 2.U -> b_imm, | |
| 3.U -> u_imm, 4.U -> j_imm, | |
| )) | |
| } | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // CONTROL UNIT β Decodes RV32I, drives datapath | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| class Control extends Module { | |
| val io = IO(new Bundle { | |
| val inst = Input(UInt(32.W)) | |
| val aluOp = Output(UInt(4.W)) | |
| val regWen = Output(Bool()) | |
| val memWen = Output(Bool()) | |
| val memRen = Output(Bool()) | |
| val regWsrc = Output(Bool()) | |
| val isBranch = Output(Bool()) | |
| val isJump = Output(Bool()) | |
| val immType = Output(UInt(3.W)) | |
| val aluAsrc = Output(Bool()) | |
| val aluBsrc = Output(Bool()) | |
| val funct3 = Output(UInt(3.W)) | |
| }) | |
| val opcode = io.inst(6,0) | |
| val funct3 = io.inst(14,12) | |
| val funct7 = io.inst(31,25) | |
| io.aluOp := AluOp.ADD | |
| io.regWen := false.B | |
| io.memWen := false.B | |
| io.memRen := false.B | |
| io.regWsrc := false.B | |
| io.isBranch := false.B | |
| io.isJump := false.B | |
| io.immType := 0.U | |
| io.aluAsrc := false.B | |
| io.aluBsrc := true.B | |
| io.funct3 := funct3 | |
| switch(opcode) { | |
| is(0b0110111.U) { io.regWen := true.B; io.immType := 3.U; io.aluOp := AluOp.PASS } | |
| is(0b0010111.U) { io.regWen := true.B; io.immType := 3.U; io.aluAsrc := true.B } | |
| is(0b1101111.U) { io.regWen := true.B; io.immType := 4.U; io.isJump := true.B; io.aluAsrc := true.B } | |
| is(0b1100111.U) { io.regWen := true.B; io.immType := 0.U; io.isJump := true.B } | |
| is(0b1100011.U) { | |
| io.isBranch := true.B; io.immType := 2.U; io.aluBsrc := false.B | |
| switch(funct3) { | |
| is(0b000.U) { io.aluOp := AluOp.SUB } | |
| is(0b001.U) { io.aluOp := AluOp.SUB } | |
| is(0b100.U) { io.aluOp := AluOp.SLT } | |
| is(0b101.U) { io.aluOp := AluOp.SLT } | |
| is(0b110.U) { io.aluOp := AluOp.SLTU } | |
| is(0b111.U) { io.aluOp := AluOp.SLTU } | |
| } | |
| } | |
| is(0b0000011.U) { io.regWen := true.B; io.memRen := true.B; io.immType := 0.U; io.regWsrc := true.B } | |
| is(0b0100011.U) { io.memWen := true.B; io.immType := 1.U } | |
| is(0b0010011.U) { | |
| io.regWen := true.B; io.immType := 0.U | |
| switch(funct3) { | |
| is(0b000.U) { io.aluOp := AluOp.ADD } | |
| is(0b010.U) { io.aluOp := AluOp.SLT } | |
| is(0b011.U) { io.aluOp := AluOp.SLTU } | |
| is(0b100.U) { io.aluOp := AluOp.XOR } | |
| is(0b110.U) { io.aluOp := AluOp.OR } | |
| is(0b111.U) { io.aluOp := AluOp.AND } | |
| is(0b001.U) { io.aluOp := AluOp.SLL } | |
| is(0b101.U) { io.aluOp := Mux(funct7(5), AluOp.SRA, AluOp.SRL) } | |
| } | |
| } | |
| is(0b0110011.U) { | |
| io.regWen := true.B; io.aluBsrc := false.B | |
| switch(funct3) { | |
| is(0b000.U) { io.aluOp := Mux(funct7(5), AluOp.SUB, AluOp.ADD) } | |
| is(0b010.U) { io.aluOp := AluOp.SLT } | |
| is(0b011.U) { io.aluOp := AluOp.SLTU } | |
| is(0b100.U) { io.aluOp := AluOp.XOR } | |
| is(0b110.U) { io.aluOp := AluOp.OR } | |
| is(0b111.U) { io.aluOp := AluOp.AND } | |
| is(0b001.U) { io.aluOp := AluOp.SLL } | |
| is(0b101.U) { io.aluOp := Mux(funct7(5), AluOp.SRA, AluOp.SRL) } | |
| } | |
| } | |
| } | |
| } | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // RV32I CORE β 3-stage with load-use stall | |
| // | |
| // FETCH β DECODE β EXECUTE/WRITEBACK | |
| // Load-use hazard: 1-cycle stall when load result needed next | |
| // Branch: evaluated in execute using ALU lt/ltu/zero flags | |
| // Store: byte mask from address + funct3 | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| class Rv32iCore extends Module { | |
| val io = IO(new Bundle { | |
| val imemAddr = Output(UInt(32.W)) | |
| val imemRdata = Input(UInt(32.W)) | |
| val dmemAddr = Output(UInt(32.W)) | |
| val dmemWdata = Output(UInt(32.W)) | |
| val dmemRdata = Input(UInt(32.W)) | |
| val dmemWen = Output(Bool()) | |
| val dmemRen = Output(Bool()) | |
| val dmemMask = Output(UInt(4.W)) | |
| }) | |
| val pc = RegInit(0x20000000L.U(32.W)) | |
| io.imemAddr := pc | |
| val inst = io.imemRdata | |
| val ctrl = Module(new Control) | |
| ctrl.io.inst := inst | |
| val immGen = Module(new ImmGen) | |
| immGen.io.inst := inst | |
| immGen.io.itype := ctrl.io.immType | |
| val regfile = Module(new RegFile) | |
| regfile.io.raddr1 := inst(19,15) | |
| regfile.io.raddr2 := inst(24,20) | |
| regfile.io.wen := ctrl.io.regWen | |
| regfile.io.waddr := inst(11,7) | |
| val rs1 = regfile.io.rdata1 | |
| val rs2 = regfile.io.rdata2 | |
| val imm = immGen.io.imm | |
| // ββ Load-use hazard detection ββ | |
| val prevLoad = RegInit(false.B) | |
| val prevLoadRd = RegInit(0.U(5.W)) | |
| val rs1Id = inst(19,15) | |
| val rs2Id = inst(24,20) | |
| val stall = prevLoad && (rs1Id =/= 0.U && rs1Id === prevLoadRd || | |
| rs2Id =/= 0.U && rs2Id === prevLoadRd) | |
| when(io.dmemRen) { | |
| prevLoad := true.B | |
| prevLoadRd := inst(11,7) | |
| } .otherwise { | |
| prevLoad := false.B | |
| prevLoadRd := 0.U | |
| } | |
| // ββ ALU ββ | |
| val aluA = Mux(ctrl.io.aluAsrc, pc, rs1) | |
| val aluB = Mux(ctrl.io.aluBsrc, imm, rs2) | |
| val alu = Module(new RvAlu) | |
| alu.io.a := aluA | |
| alu.io.b := aluB | |
| alu.io.op := ctrl.io.aluOp | |
| // ββ Branch evaluation ββ | |
| val branchTaken = ctrl.io.isBranch && ( | |
| (ctrl.io.funct3 === 0.U && alu.io.zero) || // BEQ | |
| (ctrl.io.funct3 === 1.U && !alu.io.zero) || // BNE | |
| (ctrl.io.funct3 === 4.U && alu.io.lt) || // BLT | |
| (ctrl.io.funct3 === 5.U && !alu.io.lt) || // BGE | |
| (ctrl.io.funct3 === 6.U && alu.io.ltu) || // BLTU | |
| (ctrl.io.funct3 === 7.U && !alu.io.ltu) // BGEU | |
| ) | |
| val jumpTarget = Mux(inst(6,0) === 0b1100111.U, | |
| (rs1 + imm) & ~1.U(32.W), pc + imm) | |
| // ββ Writeback ββ | |
| val loadData = MuxLookup(ctrl.io.funct3, io.dmemRdata, Seq( | |
| 0.U -> Cat(Fill(24, io.dmemRdata(7)), io.dmemRdata(7,0)), | |
| 1.U -> Cat(Fill(16, io.dmemRdata(15)), io.dmemRdata(15,0)), | |
| 2.U -> io.dmemRdata, | |
| 4.U -> Cat(0.U(24), io.dmemRdata(7,0)), | |
| 5.U -> Cat(0.U(16), io.dmemRdata(15,0)), | |
| )) | |
| val wbData = Mux(ctrl.io.regWsrc, loadData, alu.io.result) | |
| val isJal = inst(6,0) === 0b1101111.U || inst(6,0) === 0b1100111.U | |
| regfile.io.wdata := Mux(isJal, pc + 4.U, wbData) | |
| // ββ Data memory ββ | |
| io.dmemAddr := alu.io.result | |
| io.dmemWdata := rs2 | |
| io.dmemWen := ctrl.io.memWen && !stall | |
| io.dmemRen := ctrl.io.memRen && !stall | |
| val byteOff = alu.io.result(1,0) | |
| io.dmemMask := MuxLookup(ctrl.io.funct3, "b1111".U, Seq( | |
| 0.U -> (1.U << byteOff)(3,0), | |
| 1.U -> Mux(byteOff(1), "b1100".U, "b0011".U), | |
| 2.U -> "b1111".U, | |
| )) | |
| // ββ PC next ββ | |
| when(stall) { | |
| pc := pc | |
| } .elsewhen(branchTaken || ctrl.io.isJump) { | |
| pc := jumpTarget | |
| } .otherwise { | |
| pc := pc + 4.U | |
| } | |
| } | |