diff --git a/.gitignore b/.gitignore index b7b08fc..19a2805 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ -!src \ No newline at end of file +/* +!src/ +!build.sbt +!.gitignore \ No newline at end of file diff --git a/build.sbt b/build.sbt new file mode 100644 index 0000000..6929c43 --- /dev/null +++ b/build.sbt @@ -0,0 +1,6 @@ +// build.sbt +scalaVersion := "2.13.8" +addCompilerPlugin("edu.berkeley.cs" % "chisel3-plugin" % "3.5.0" cross CrossVersion.full) +libraryDependencies += "edu.berkeley.cs" %% "chisel3" % "3.5.0" +// We also recommend using chiseltest for writing unit tests +libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "0.5.0" % "test" diff --git a/src/main/scala/Build.scala b/src/main/scala/Build.scala new file mode 100644 index 0000000..436b38f --- /dev/null +++ b/src/main/scala/Build.scala @@ -0,0 +1,11 @@ +import pipeline._ +import chisel3._ +import chisel3.stage._ +import funcunit._ + +object Build extends App { + // println(getVerilogString(new InstFetch)) + println("Generating Verilog Code") + (new ChiselStage).emitVerilog(new Alu) + println("Done") +} diff --git a/src/main/scala/FIR.scala b/src/main/scala/FIR.scala new file mode 100644 index 0000000..dae0544 --- /dev/null +++ b/src/main/scala/FIR.scala @@ -0,0 +1,22 @@ +import chisel3._ + +object FIR extends App { +// println("[{(Generating Verilog file)}]") +// (new ChiselStage).emitVerilog(new FIR(0, 0, 0, 0)) +} + +class FIR(b0: Int, b1: Int, b2: Int, b3: Int) extends Module { + val io = IO(new Bundle() { + val in = Input(UInt(8.W)) + val out = Output(UInt(8.W)) + }) + + val shift_0 = RegNext(io.in, 0.U) + val shift_1 = RegNext(shift_0, 0.U) + val shift_2 = RegNext(shift_1, 0.U) + + io.out := io.in * b0.U(8.W) + + shift_0 * b1.U(8.W) + + shift_1 * b2.U(8.W) + + shift_2 * b3.U(8.W) +} diff --git a/src/main/scala/HelloWorld.scala b/src/main/scala/HelloWorld.scala new file mode 100644 index 0000000..2cb28cc --- /dev/null +++ b/src/main/scala/HelloWorld.scala @@ -0,0 +1,23 @@ +import chisel3._ +import chisel3.stage._ + +object HelloWorld extends App { + println("[{(Generating Verilog file)}]") + (new ChiselStage).emitVerilog(new Alu) +// println(getVerilogString(new Alu)) +} + +class Alu extends Module { + val io = IO(new Bundle{ + val src_a = Input(UInt(32.W)) + val src_b = Input(UInt(32.W)) + val op_code = Input(UInt(12.W)) + val res = Output(UInt(32.W)) + }) + + when(io.op_code(0)) { + io.res := io.src_a + io.src_b + }.otherwise { + io.res := io.src_a - io.src_b + } +} diff --git a/src/main/scala/Top.scala b/src/main/scala/Top.scala new file mode 100644 index 0000000..ab53a58 --- /dev/null +++ b/src/main/scala/Top.scala @@ -0,0 +1,16 @@ +import pipeline._ +import chisel3._ + +class Top extends Module { + val sram_req = IO(new SramReq) + val sram_res = IO(new SramRes) + + val pfs = Module(new PreInstFetch) + val fs = Module(new InstFetch) + + pfs.sram_req <> sram_req + pfs.pfs2fs_bus <> fs.pfs2fs_bus + fs.sram_res <> sram_res + + fs.fs2ds_bus.ds_allowin := true.B +} diff --git a/src/main/scala/funcunit/Alu.scala b/src/main/scala/funcunit/Alu.scala new file mode 100644 index 0000000..bf99838 --- /dev/null +++ b/src/main/scala/funcunit/Alu.scala @@ -0,0 +1,26 @@ +package funcunit + +import chisel3._ +import chisel3.util._ +import pipeline._ + +class Alu extends Module { + val io = IO(Flipped(new DsToAluBus)) + + val res = Wire(Vec(12, UInt(32.W))) + + res(0) := io.src1 + io.src2 + res(1) := io.src1 - io.src2 + res(2) := io.src1 & io.src2 + res(3) := io.src1 | io.src2 + res(4) := io.src1 ^ io.src2 + res(5) := ~(io.src1 | io.src2) + res(6) := io.src1 + io.src2 + res(7) := io.src1 + io.src2 + res(8) := io.src1 + io.src2 + res(9) := io.src1 + io.src2 + res(10) := io.src1 + io.src2 + res(11) := io.src1 + io.src2 + + io.res := Mux1H(io.aluop, res) +} diff --git a/src/main/scala/funcunit/RegFile.scala b/src/main/scala/funcunit/RegFile.scala new file mode 100644 index 0000000..7741493 --- /dev/null +++ b/src/main/scala/funcunit/RegFile.scala @@ -0,0 +1,31 @@ +package funcunit + +import chisel3._ + +class RegFile(NRReg: Int, XLen: Int) extends Module { + def log2(x: Double): Int = (Math.log(x) / Math.log(2)).toInt + val addr_len = log2(NRReg) + + val io = IO(new Bundle() { + val raddr = Input(Vec(2, UInt(addr_len.W))) + val rdata = Output(Vec(2, UInt(XLen.W))) + + val wen = Input(Bool()) + val waddr = Input(UInt(addr_len.W)) + val wdata = Input(UInt(XLen.W)) + }) + + val regs = Mem(NRReg, UInt(XLen.W)) + + when (io.wen) { + regs(io.waddr) := io.wdata + } + + for (i <- 0 to 1) { + when (io.raddr(i) === "h0".U(5.W)) { + io.rdata(i) := "h0".U(32.W) + } otherwise { + io.rdata(i) := regs(io.raddr(i)) + } + } +} diff --git a/src/main/scala/pipeline/Decode.scala b/src/main/scala/pipeline/Decode.scala new file mode 100644 index 0000000..e61b3cf --- /dev/null +++ b/src/main/scala/pipeline/Decode.scala @@ -0,0 +1,52 @@ +package pipeline + +import chisel3._ + +class Decode extends Module { + // Interface + val fs2ds_bus = IO(Flipped(new FsToDsBus)) + val ds2es_bus = IO(new DsToEsBus) + val ds2alu_bus = IO(new DsToAluBus) + + // Stage Control + val valid = RegInit(false.B) + val ds_ready_go = Wire(Bool()) + + // Stage Register + val data = Reg(new FsToDsData) + + // Functional Part + val inst_add_w = Wire(Bool()) + + fs2ds_bus.ds_allowin := ~valid | ds_ready_go & ds2es_bus.es_allowin + + ds2es_bus.ds_valid := valid & ds_ready_go + ds2es_bus.data.pc := data.pc + ds2es_bus.data.dest := "h0".U(5.W) + + ds2alu_bus.src1 := "h0".U(32.W) + ds2alu_bus.src2 := "h0".U(32.W) + ds2alu_bus.aluop(0) := inst_add_w + ds2alu_bus.aluop(1) := inst_add_w + ds2alu_bus.aluop(2) := inst_add_w + ds2alu_bus.aluop(3) := inst_add_w + ds2alu_bus.aluop(4) := inst_add_w + ds2alu_bus.aluop(5) := inst_add_w + ds2alu_bus.aluop(6) := inst_add_w + ds2alu_bus.aluop(7) := inst_add_w + ds2alu_bus.aluop(8) := inst_add_w + ds2alu_bus.aluop(9) := inst_add_w + ds2alu_bus.aluop(10) := inst_add_w + ds2alu_bus.aluop(11) := inst_add_w + + ds_ready_go := true.B + when (fs2ds_bus.ds_allowin) { + valid := fs2ds_bus.fs_valid + } + + when (fs2ds_bus.fs_valid && fs2ds_bus.ds_allowin) { + data := fs2ds_bus.data + } + + inst_add_w := fs2ds_bus.data.inst(1, 0) === 2.U +} diff --git a/src/main/scala/pipeline/InstFetch.scala b/src/main/scala/pipeline/InstFetch.scala new file mode 100644 index 0000000..a6bda03 --- /dev/null +++ b/src/main/scala/pipeline/InstFetch.scala @@ -0,0 +1,33 @@ +package pipeline + +import chisel3._ +import chisel3.stage +import chisel3.stage.ChiselStage + +class InstFetch extends Module { + // Interface + val pfs2fs_bus = IO(Flipped(new PfsToFsBus)) + val fs2ds_bus = IO(new FsToDsBus) + val sram_res = IO(new SramRes) + + // Stage Control + val valid = RegInit(false.B) + val fs_ready_go = Wire(Bool()) + + // Stage Register + val data = Reg(new PfsToFsData) + + pfs2fs_bus.fs_allowin := ~valid | fs_ready_go & fs2ds_bus.ds_allowin + fs2ds_bus.fs_valid := valid & fs_ready_go + fs2ds_bus.data.inst := sram_res.rdata + fs2ds_bus.data.pc := data.pc + + fs_ready_go := true.B + when (pfs2fs_bus.fs_allowin) { + valid := pfs2fs_bus.pfs_valid + } + + when (pfs2fs_bus.pfs_valid && pfs2fs_bus.fs_allowin) { + data := pfs2fs_bus.data + } +} diff --git a/src/main/scala/pipeline/Interface.scala b/src/main/scala/pipeline/Interface.scala new file mode 100644 index 0000000..7a27382 --- /dev/null +++ b/src/main/scala/pipeline/Interface.scala @@ -0,0 +1,58 @@ +package pipeline + +import chisel3._ + +// sram insterface +class SramReq extends Bundle { + val en = Output(Bool()) + val wen = Output(UInt(4.W)) + val addr = Output(UInt(32.W)) + val wdata = Output(UInt(32.W)) +} + +class SramRes extends Bundle { + val rdata = Input(UInt(32.W)) +} + +// pre-inst-fetch and inst-fetch +class PfsToFsData extends Bundle { + val pc = Output(UInt(32.W)) +} + +class PfsToFsBus extends Bundle { + val fs_allowin = Input(Bool()) + val pfs_valid = Output(Bool()) + val data = new PfsToFsData +} + +// inst-fetch and decode +class FsToDsData extends Bundle { + val pc = Output(UInt(32.W)) + val inst = Output(UInt(32.W)) +} + +class FsToDsBus extends Bundle { + val ds_allowin = Input(Bool()) + val fs_valid = Output(Bool()) + val data = new FsToDsData +} + +// decode and execute +class DsToEsData extends Bundle { + val pc = Output(UInt(32.W)) + val dest = Output(UInt(5.W)) +} + +class DsToAluBus extends Bundle { + val src1 = Output(UInt(32.W)) + val src2 = Output(UInt(32.W)) +// val aluop = Output(Vec(12, Bool())) + val aluop = Output(UInt(12.W)) + val res = Input(UInt(32.W)) +} + +class DsToEsBus extends Bundle { + val es_allowin = Input(Bool()) + val ds_valid = Output(Bool()) + val data = new DsToEsData +} diff --git a/src/main/scala/pipeline/Modules.scala b/src/main/scala/pipeline/Modules.scala new file mode 100644 index 0000000..b9fb139 --- /dev/null +++ b/src/main/scala/pipeline/Modules.scala @@ -0,0 +1,3 @@ +package pipeline + +import chisel3._ diff --git a/src/main/scala/pipeline/PreInstFetch.scala b/src/main/scala/pipeline/PreInstFetch.scala new file mode 100644 index 0000000..4a3750a --- /dev/null +++ b/src/main/scala/pipeline/PreInstFetch.scala @@ -0,0 +1,36 @@ +package pipeline + +import chisel3._ + +class PreInstFetch extends Module { + // Interface + val pfs2fs_bus = IO(new PfsToFsBus) + val sram_req = IO(new SramReq) + + // Stage Control + val to_pfs_valid = Wire(Bool()) + val pfs_allowin = Wire(Bool()) + val valid = RegInit(false.B) + val pfs_ready_go = Wire(Bool()) + + // Stage Register + val data = RegInit("h1bff_fffc".U(32.W)) + + pfs2fs_bus.pfs_valid := valid & pfs_ready_go + pfs2fs_bus.data.pc := data + sram_req.en := to_pfs_valid & pfs_allowin + sram_req.wen := "h0".U(4.W) + sram_req.addr := data + sram_req.wdata := "h0000_0000".U(32.W) + + to_pfs_valid := true.B + pfs_allowin := ~valid | pfs_ready_go & pfs2fs_bus.fs_allowin + pfs_ready_go := true.B + when (pfs_allowin) { + valid := to_pfs_valid + } + + when (to_pfs_valid && pfs_allowin) { + data := data + "h4".U(32.W) + } +} diff --git a/src/test/scala/FIRtest.scala b/src/test/scala/FIRtest.scala new file mode 100644 index 0000000..f0a202f --- /dev/null +++ b/src/test/scala/FIRtest.scala @@ -0,0 +1,25 @@ +import chisel3._ +import chiseltest._ +import org.scalatest.flatspec.AnyFlatSpec + +class FIRtest extends AnyFlatSpec with ChiselScalatestTester { + behavior of "FIR" + // test class body here + it should "test all zero" in { + // test case body here + test(new FIR(0, 0, 0, 0)) { c => + c.io.in.poke(0.U) + c.io.out.expect(0.U) + c.clock.step(1) + c.io.in.poke(4.U) + c.io.out.expect(0.U) + c.clock.step(1) + c.io.in.poke(5.U) + c.io.out.expect(0.U) + c.clock.step(1) + c.io.in.poke(2.U) + c.io.out.expect(0.U) + } + } + println("Success") +}