diff --git a/flake.nix b/flake.nix index c824872..b2e8142 100644 --- a/flake.nix +++ b/flake.nix @@ -111,17 +111,12 @@ nixpkgs-circt162.legacyPackages.${system}.circt yosys cli11 - flex - bison - verilator ]; buildInputs = [ + verilator nvboard openssl - libllvm - libxml2 - readline ] ++ self.checks.${system}.pre-commit-check.enabledPackages; cmakeFlags = [ diff --git a/npc/CMakeLists.txt b/npc/CMakeLists.txt index bcd356b..78dbfe5 100644 --- a/npc/CMakeLists.txt +++ b/npc/CMakeLists.txt @@ -34,10 +34,6 @@ if(BUILD_SIM_NVBOARD_TARGET) find_package(SDL2_image REQUIRED) endif() find_package(CLI11 CONFIG REQUIRED) -# TODO: Not required -find_package(LLVM CONFIG REQUIRED) - -option(ENABLE_SDB "Enable simple debugger" ON) find_library(NVBOARD_LIBRARY NAMES nvboard) find_path(NVBOARD_INCLUDE_DIR NAMES nvboard.h) @@ -63,7 +59,6 @@ endif() # -- Build Verilator executable and add to test include_directories(include) -add_subdirectory(utils) add_subdirectory(csrc) diff --git a/npc/cmake/FindReadline.cmake b/npc/cmake/FindReadline.cmake deleted file mode 100644 index dc2dd41..0000000 --- a/npc/cmake/FindReadline.cmake +++ /dev/null @@ -1,49 +0,0 @@ -# Code copied from sethhall@github -# -# - Try to find readline include dirs and libraries -# -# Usage of this module as follows: -# -# find_package(Readline) -# -# Variables used by this module, they can change the default behaviour and need -# to be set before calling find_package: -# -# Readline_ROOT_DIR Set this variable to the root installation of -# readline if the module has problems finding the -# proper installation path. -# -# Variables defined by this module: -# -# READLINE_FOUND System has readline, include and lib dirs found -# Readline_INCLUDE_DIR The readline include directories. -# Readline_LIBRARY The readline library. - -find_path(Readline_ROOT_DIR - NAMES include/readline/readline.h -) - -find_path(Readline_INCLUDE_DIR - NAMES readline/readline.h - HINTS ${Readline_ROOT_DIR}/include -) - -find_library(Readline_LIBRARY - NAMES readline - HINTS ${Readline_ROOT_DIR}/lib -) - -if(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY) - set(READLINE_FOUND TRUE) -else(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY) - find_library(Readline_LIBRARY NAMES readline) - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(Readline DEFAULT_MSG Readline_INCLUDE_DIR Readline_LIBRARY ) - mark_as_advanced(Readline_INCLUDE_DIR Readline_LIBRARY) -endif(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY) - -mark_as_advanced( - Readline_ROOT_DIR - Readline_INCLUDE_DIR - Readline_LIBRARY -) \ No newline at end of file diff --git a/npc/core/src/main/resources/RamDpi.v b/npc/core/src/main/resources/RamDpi.v index c9f8b7c..d6e3c98 100644 --- a/npc/core/src/main/resources/RamDpi.v +++ b/npc/core/src/main/resources/RamDpi.v @@ -8,9 +8,7 @@ module RamDpi ( input [31:0] writeData, input [3:0] writeMask, input reg [31:0] readAddr, - output reg [31:0] readData, - input reg [31:0] pc, - output reg [31:0] inst + output reg [31:0] readData ); always @(*) begin if (valid) begin // 有读写请求时 @@ -22,6 +20,5 @@ module RamDpi ( else begin readData = 0; end - inst = pmem_read(pc); end endmodule \ No newline at end of file diff --git a/npc/core/src/main/scala/components/ALU.scala b/npc/core/src/main/scala/components/ALU.scala index 0c22b15..9a0b0f9 100644 --- a/npc/core/src/main/scala/components/ALU.scala +++ b/npc/core/src/main/scala/components/ALU.scala @@ -6,50 +6,41 @@ import shapeless.{HNil, ::} class ALUControlInterface extends Bundle { object OpSelect extends ChiselEnum { - val aOpAdd, aOpSub, aOpNot, aOpAnd, aOpOr, aOpXor, aOpSlt, aOpSll, aOpSrl, aOpSra = Value + val aOpAdd, aOpSub, aOpNot, aOpAnd, aOpOr, aOpXor, aOpSlt, aOpEq, aOpNop = Value } - object SrcASelect extends ChiselEnum { - val aSrcARs1, aSrcAPc, aSrcAZero = Value - } - object SrcBSelect extends ChiselEnum { - val aSrcBRs2, aSrcBImmI, aSrcBImmJ, aSrcBImmB, aSrcBImmS = Value + object SrcSelect extends ChiselEnum { + val aSrcRs2, aSrcImm = Value } val op = Input(OpSelect()) - val srcASelect = Input(SrcASelect()) - val srcBSelect = Input(SrcBSelect()) - val signExt = Input(Bool()) + val src = Input(SrcSelect()) - def ctrlBindPorts = { - op :: srcASelect :: srcBSelect :: signExt :: HNil + type CtrlTypes = OpSelect.Type :: SrcSelect.Type :: HNil + def ctrlBindPorts: CtrlTypes = { + op :: src :: HNil } } class ALU[T <: UInt](tpe: T) extends Module { val control = IO(new ALUControlInterface) val in = IO(new Bundle { - val a = Input(Vec(control.SrcASelect.all.length, tpe)) - val b = Input(Vec(control.SrcBSelect.all.length, tpe)) + val a = Input(Vec(control.SrcSelect.all.length, tpe)) + val b = Input(tpe) }) val out = IO(new Bundle { - val eq = Output(Bool()) val result = Output(tpe) }) - val a = in.a(control.srcASelect.asUInt) - val b = in.b(control.srcBSelect.asUInt) + val a = in.a(control.src.asUInt) // val adder_b = (Fill(tpe.getWidth, io.op(0)) ^ io.b) + io.op(0) // take (-b) if sub - val add = a + b - val sub = a - b - val and = a & b + val add = a + in.b + val sub = a - in.b + val and = a & in.b val not = ~a - val or = a | b - val xor = a ^ b - val slt = a < b - val sll = a << b(log2Ceil(tpe.getWidth), 0) - val srl = a >> b(log2Ceil(tpe.getWidth), 0) - val sra = a.asSInt >> b(log2Ceil(tpe.getWidth), 0) - out.eq := a === b + val or = a | in.b + val xor = a ^ in.b + val slt = a < in.b + val eq = a === in.b import control.OpSelect._ @@ -61,9 +52,7 @@ class ALU[T <: UInt](tpe: T) extends Module { aOpOr -> or, aOpXor -> xor, aOpSlt -> slt, - aOpSll -> sll, - aOpSrl -> srl, - aOpSra -> sra.asUInt + aOpEq -> eq )) } diff --git a/npc/core/src/main/scala/components/Mem.scala b/npc/core/src/main/scala/components/Mem.scala index 7562730..6634edb 100644 --- a/npc/core/src/main/scala/components/Mem.scala +++ b/npc/core/src/main/scala/components/Mem.scala @@ -6,32 +6,19 @@ import chisel3.util.HasBlackBoxResource import chisel3.util.log2Ceil import chisel3.experimental.noPrefix import scala.collection.SeqMap -import flow.components -import shapeless.{HNil, ::} +import javax.swing.plaf.synth.SynthRadioButtonMenuItemUI -class RamControlInterface(addrWidth: Int) extends Bundle { +class RamInterface[T <: Data](tpe: T, addrWidth: Int) extends Bundle { val valid = Input(Bool()) - val writeMask = Input(UInt((addrWidth / 8).W)) val writeEnable = Input(Bool()) - def ctrlBindPorts = { - valid :: writeMask :: writeEnable :: HNil - } - -} - -/* FIXME: Extends here might not be the best solution. - * We need a way to merge two bundles together - */ -class RamInterface[T <: Data](tpe: T, addrWidth: Int) extends RamControlInterface(addrWidth) { val writeAddr = Input(UInt(addrWidth.W)) val writeData = Input(tpe) + val writeMask = Input(UInt((addrWidth / 8).W)) val readAddr = Input(UInt(addrWidth.W)) val readData = Output(tpe) - val pc = Input(UInt(addrWidth.W)) - val inst = Output(tpe) } class RamDpi extends BlackBox with HasBlackBoxResource { - val io = IO((new RamInterface(UInt(32.W), 32))) + val io = IO(new RamInterface(UInt(32.W), 32)) addResource("/RamDpi.v") } diff --git a/npc/core/src/main/scala/components/ProgramCounter.scala b/npc/core/src/main/scala/components/ProgramCounter.scala index 01ac115..bfb3e1b 100644 --- a/npc/core/src/main/scala/components/ProgramCounter.scala +++ b/npc/core/src/main/scala/components/ProgramCounter.scala @@ -6,42 +6,33 @@ import shapeless.{HNil, ::} class PcControlInterface extends Bundle { object SrcSelect extends ChiselEnum { - val pStaticNpc, pExeOut = Value + val pStaticNpc, pBranchResult = Value } - val useImmB = Input(Bool()) val srcSelect = Input(SrcSelect()) - def ctrlBindPorts = { - useImmB :: srcSelect :: HNil + type CtrlTypes = SrcSelect.Type :: HNil + def ctrlBindPorts: CtrlTypes = { + srcSelect :: HNil } } -class ProgramCounter[T <: UInt](tpe: T) extends Module { +class ProgramCounter[T <: Data](tpe: T) extends Module { val control = IO(new PcControlInterface) val in = IO(new Bundle { - val immB = Input(tpe) - val exeOut = Input(tpe) + val pcSrcs = Input(Vec(control.SrcSelect.all.length, tpe)) }) val out = IO(Output(tpe)) - private val pc_reg = RegInit(0x80000000L.U) + private val pc = RegInit(0x80000000L.U) -// pc := in.pcSrcs(control.srcSelect.asUInt) - import control.SrcSelect._ - when( control.useImmB === true.B ) { - pc_reg := pc_reg + in.immB - }. elsewhen( control.srcSelect === pStaticNpc) { - pc_reg := pc_reg + 4.U - }. elsewhen( control.srcSelect === pExeOut) { - pc_reg := in.exeOut - } - out := pc_reg + pc := in.pcSrcs(control.srcSelect.asUInt) + out := pc } object ProgramCounter { - def apply[T <: UInt](tpe: T): ProgramCounter[T] = { + def apply[T <: Data](tpe: T): ProgramCounter[T] = { val pc = Module(new ProgramCounter(tpe)) pc } diff --git a/npc/core/src/main/scala/components/RegisterFile.scala b/npc/core/src/main/scala/components/RegisterFile.scala index b5d1b63..9b50375 100644 --- a/npc/core/src/main/scala/components/RegisterFile.scala +++ b/npc/core/src/main/scala/components/RegisterFile.scala @@ -5,17 +5,18 @@ import chisel3.util.log2Ceil import chisel3.util.UIntToOH import chisel3.util.MuxLookup import chisel3.experimental.Trace._ -import shapeless.{ HList, HNil, :: } +import shapeless.{ HNil, :: } class RegControl extends Bundle { object WriteSelect extends ChiselEnum { - val rAluOut, rMemOut, rNpc = Value + val rAluOut, rMemOut = Value } val writeEnable = Input(Bool()) val writeSelect = Input(WriteSelect()) - def ctrlBindPorts = { + type CtrlTypes = Bool :: WriteSelect.Type :: HNil + def ctrlBindPorts: CtrlTypes = { writeEnable :: writeSelect :: HNil } traceName(writeEnable) @@ -39,8 +40,7 @@ class RegisterFile[T <: Data](tpe: T, regCount: Int, numReadPorts: Int) extends val writeAddrOH = UIntToOH(in.writeAddr) for ((reg, i) <- regFile.zipWithIndex.tail) { - reg := Mux( - writeAddrOH(i.U(log2Ceil(regCount).W)) && control.writeEnable, in.writeData(control.writeSelect.asUInt), reg) + reg := Mux(writeAddrOH(i.U(log2Ceil(regCount).W)) && control.writeEnable, in.writeData(control.writeSelect.asUInt), reg) } regFile(0) := 0.U diff --git a/npc/core/src/main/scala/top/FlowMain.scala b/npc/core/src/main/scala/top/FlowMain.scala index 899783c..73df9ed 100644 --- a/npc/core/src/main/scala/top/FlowMain.scala +++ b/npc/core/src/main/scala/top/FlowMain.scala @@ -2,8 +2,12 @@ package flow import scala.reflect.runtime.universe._ import chisel3._ +import chisel3.util.{MuxLookup, Fill, Decoupled, Counter, Queue, Reverse} +import chisel3.util.{SRAM} import chisel3.util.experimental.decode.{decoder, TruthTable} -import chisel3.util._ +import chisel3.util.log2Ceil +import chisel3.util.BitPat +import chisel3.util.Enum import chisel3.experimental.Trace._ import shapeless.{HNil, ::} import shapeless.HList @@ -11,322 +15,68 @@ import shapeless.ops.coproduct.Prepend import chisel3.util.{ BinaryMemoryFile, HexMemoryFile } import chisel3.experimental.Trace -import scala.collection.IndexedSeqView -import shapeless.Poly1 -import flow.components.RamControlInterface object RV32Inst { private val bp = BitPat + val addi = this.bp("b???????_?????_?????_000_?????_00100_11") + val inv = this.bp("b???????_?????_?????_???_?????_?????_??") +} - val lui = this.bp("b???????_?????_?????_???_?????_01101_11") - val auipc = this.bp("b???????_?????_?????_???_?????_00101_11") - - val jal = this.bp("b???????_?????_?????_???_?????_11011_11") - val jalr = this.bp("b???????_?????_?????_???_?????_11001_11") - val beq = this.bp("b???????_?????_?????_000_?????_11000_11") - val bne = this.bp("b???????_?????_?????_001_?????_11000_11") - val blt = this.bp("b???????_?????_?????_100_?????_11000_11") - val bge = this.bp("b???????_?????_?????_101_?????_11000_11") - val bltu = this.bp("b???????_?????_?????_110_?????_11000_11") - val bgeu = this.bp("b???????_?????_?????_111_?????_11000_11") - - val lb = this.bp("b???????_?????_?????_000_?????_00000_11") - val lh = this.bp("b???????_?????_?????_001_?????_00000_11") - val lw = this.bp("b???????_?????_?????_010_?????_00000_11") - val lbu = this.bp("b???????_?????_?????_100_?????_00000_11") - val lhu = this.bp("b???????_?????_?????_101_?????_00000_11") - val sb = this.bp("b???????_?????_?????_000_?????_01000_11") - val sh = this.bp("b???????_?????_?????_001_?????_01000_11") - val sw = this.bp("b???????_?????_?????_010_?????_01000_11") - - val addi = this.bp("b???????_?????_?????_000_?????_00100_11") - val slti = this.bp("b???????_?????_?????_010_?????_00100_11") - val sltiu = this.bp("b???????_?????_?????_011_?????_00100_11") - val xori = this.bp("b???????_?????_?????_100_?????_00100_11") - val ori = this.bp("b???????_?????_?????_110_?????_00100_11") - val andi = this.bp("b???????_?????_?????_111_?????_00100_11") - val slli = this.bp("b0000000_?????_?????_001_?????_00100_11") - val srli = this.bp("b0000000_?????_?????_101_?????_00100_11") - val srai = this.bp("b0100000_?????_?????_101_?????_00100_11") - val add = this.bp("b0000000_?????_?????_000_?????_01100_11") - val sub = this.bp("b0100000_?????_?????_000_?????_01100_11") - val sll = this.bp("b0000000_?????_?????_001_?????_01100_11") - val slt = this.bp("b0000000_?????_?????_010_?????_01100_11") - val sltu = this.bp("b0000000_?????_?????_011_?????_01100_11") - val xor = this.bp("b0000000_?????_?????_100_?????_01100_11") - val srl = this.bp("b0000000_?????_?????_101_?????_01100_11") - val sra = this.bp("b0100000_?????_?????_101_?????_01100_11") - val or = this.bp("b0000000_?????_?????_110_?????_01100_11") - val and = this.bp("b0000000_?????_?????_111_?????_01100_11") - - val ebreak = this.bp("b0000000_00001_00000_000_00000_11100_11") - - - val mul = this.bp("b0000001_?????_?????_000_?????_01100_11") - val mulh = this.bp("b0000001_?????_?????_001_?????_01100_11") - val mulhsu = this.bp("b0000001_?????_?????_010_?????_01100_11") - val mulhu = this.bp("b0000001_?????_?????_011_?????_01100_11") - val div = this.bp("b0000001_?????_?????_100_?????_01100_11") - val divu = this.bp("b0000001_?????_?????_101_?????_01100_11") - val rem = this.bp("b0000001_?????_?????_110_?????_01100_11") - val remu = this.bp("b0000001_?????_?????_111_?????_01100_11") - - val inv = this.bp("b???????_?????_?????_???_?????_?????_??") +class PcControl(width: Int) extends Bundle { + object SrcSelect extends ChiselEnum { + val pPC, pExeResult = Value + } + val srcSelect = Output(SrcSelect()) } import flow.components.{RegControl, PcControlInterface, ALUControlInterface} -class Control(width: Int) extends RawModule { - // Helpers - class WrapList[T](vl: T) { type Type = T; val v = vl} - object wrap extends Poly1 { - implicit def default[A] = at[A](Right(_).withLeft[Int]) - } - def lit(x: Element) = { x.litValue.toInt } - def toBits(t: dst.Type): BitPat = { - val list = t.toList - list.map(e => e match { - case Right(x) => BitPat(lit(x).U(x.getWidth.W)) - case Left(x) => BitPat.dontCare(x) - }).reduceLeft(_ ## _) - } - val r = Right - def l[T <: Any](x: T) = x match { - case x: ChiselEnum => Left(log2Ceil(x.all.length)) - case x: Data => Left(x.getWidth) - case _ => throw new IllegalArgumentException - } - +class Control(width: Int) extends Module { val inst = IO(Input(UInt(width.W))) val reg = IO(Flipped(new RegControl)) val pc = IO(Flipped(new PcControlInterface)) val alu = IO(Flipped(new ALUControlInterface)) - val ram = IO(Flipped(new RamControlInterface(32))) - val dst = new WrapList(( - reg.ctrlBindPorts ++ - pc.ctrlBindPorts ++ - alu.ctrlBindPorts ++ - ram.ctrlBindPorts).map(wrap)) + // TODO: Add .ctrlTypes together instead of writing them by hand. + type T = + Bool :: reg.WriteSelect.Type :: pc.SrcSelect.Type :: alu.OpSelect.Type :: alu.SrcSelect.Type :: HNil + val dst: T = reg.ctrlBindPorts ++ pc.ctrlBindPorts ++ alu.ctrlBindPorts - val dstList = dst.v.toList - val controlWidth = dstList.map(_.toOption.get.getWidth).reduce(_ + _) - val reversePrefixSum = dstList.scanLeft(0)(_ + _.toOption.get.getWidth) - val sliceIndex = reversePrefixSum.map(controlWidth - _) - val slices = sliceIndex.map(_ - 1).zip(sliceIndex.tail) + val dstList = dst.toList + val reversePrefixSum = dstList.scanLeft(0)(_ + _.getWidth).reverse + val slices = reversePrefixSum.zip(reversePrefixSum.tail) import reg.WriteSelect._ - import reg._ import pc.SrcSelect._ - import pc._ import alu.OpSelect._ - import alu.SrcASelect._ - import alu.SrcBSelect._ - import pc._ + import alu.SrcSelect._ import RV32Inst._ - val ControlMapping: Array[(BitPat, dst.Type)] = Array( - // Regs | writeEnable :: writeSelect :: HNil - // PC | useImmB :: srcSelect :: HNil - // Exe | op :: srcASelect :: srcBSelect :: signExt :: HNil - // Mem | valid :: writeMask :: writeEnable :: HNil - - // ---- Control Transfer Instructions ---- - (jal , (r(true.B) :: r(rNpc) :: - r(false.B) :: r(pExeOut) :: - r(aOpAdd) :: r(aSrcAPc) :: r(aSrcBImmJ) :: r(false.B) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), - - (jalr , (r(true.B) :: r(rNpc) :: - r(false.B) :: r(pExeOut) :: - r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmJ) :: r(false.B) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), - - (beq , (r(false.B) :: l(WriteSelect) :: - r(true.B) :: r(pExeOut) :: - r(aOpSlt) :: r(aSrcAPc) :: r(aSrcBImmB) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), - - (bne , (r(false.B) :: l(WriteSelect) :: - r(true.B) :: r(pExeOut) :: - r(aOpSlt) :: r(aSrcAPc) :: r(aSrcBImmB) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), - - (blt , (r(false.B) :: l(WriteSelect) :: - r(true.B) :: r(pExeOut) :: - r(aOpSlt) :: r(aSrcAPc) :: r(aSrcBImmB) :: r(true.B) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), - - (bge , (r(false.B) :: l(WriteSelect) :: - r(true.B) :: r(pExeOut) :: - r(aOpSlt) :: r(aSrcAPc) :: r(aSrcBImmB) :: r(true.B) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), - - (bltu , (r(false.B) :: l(WriteSelect):: - r(true.B) :: r(pExeOut) :: - r(aOpSlt) :: r(aSrcAPc) :: r(aSrcBImmB) :: r(false.B) :: - r(false.B) :: l(UInt(4.W)) :: r(false.B) :: HNil)), - - (bgeu , (r(false.B) :: l(WriteSelect):: - r(true.B) :: r(pExeOut) :: - r(aOpSlt) :: r(aSrcAPc) :: r(aSrcBImmB) :: r(false.B) :: - r(false.B) :: l(UInt(4.W)) :: r(false.B) :: HNil)), - - // ---- Memory Access Instructions ---- - - (lb , (r(true.B) :: r(rMemOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(true.B) :: l(UInt(4.W)) :: r(false.B) :: HNil)), - - (lh , (r(true.B) :: r(rMemOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(true.B) :: l(UInt(4.W)) :: r(false.B) :: HNil)), - - (lw , (r(true.B) :: r(rMemOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(true.B) :: l(UInt(4.W)) :: r(false.B) :: HNil)), - - (sb , (r(false.B) :: l(WriteSelect):: - r(false.B) :: r(pStaticNpc) :: - r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(true.B) :: r(1.U(4.W)) :: r(false.B) :: HNil)), - - (sh , (r(false.B) :: l(WriteSelect):: - r(false.B) :: r(pStaticNpc) :: - r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(true.B) :: r(3.U(4.W)) :: r(false.B) :: HNil)), - - (sw , (r(false.B) :: l(WriteSelect):: - r(false.B) :: r(pStaticNpc) :: - r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(true.B) :: r(15.U(4.W)) :: r(false.B) :: HNil)), - - // ---- Integer Computational Instructions --- - - (addi , (r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), - - (slti , (r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpSlt) :: r(aSrcARs1) :: r(aSrcBImmI) :: r(true.B) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), - - (sltiu , (r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpSlt) :: r(aSrcARs1) :: r(aSrcBImmI) :: r(false.B) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), - - (xori , (r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpOr) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), - - (ori , (r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpXor) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), - - (andi , (r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpAnd) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), - - (slli , (r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpSll) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), - - (srli , (r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpSrl) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), - - (srai , (r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpSra) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), - - (add , (r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), - - (sub , (r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpSub) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), - - (sll , (r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpSll) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), - - (slt , (r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpSlt) :: r(aSrcARs1) :: r(aSrcBRs2) :: r(true.B) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), - - (sltu , (r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpSlt) :: r(aSrcARs1) :: r(aSrcBRs2) :: r(false.B) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), - - (xor , (r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpXor) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), - - (srl , (r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpSrl) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), - - (sra , (r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpSra) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), - - (or , (r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpOr) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), - - (and , (r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpAnd) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil)), + val ControlMapping: Array[(BitPat, T)] = Array( + // Regs :: PC :: Exe + // writeEnable :: writeSelect :: srcSelect :: + (addi, true.B :: rAluOut :: pStaticNpc :: aOpAdd :: aSrcImm :: HNil), ) + val default = BitPat.dontCare(dstList.map(_.getWidth).reduce(_ + _)) - val default = BitPat(0.U(controlWidth.W)) - -// println(s"ControlMapping = ${ControlMapping.map(it => (it._1 -> toBits(it._2))).foreach(x => println(x._2))}\n") + def toBits(t: T): BitPat = { + val list: List[Data] = t.toList + list.map(x => BitPat(x.litValue.toInt.U(x.getWidth.W))).reduceLeft(_ ## _) + } val out = decoder( inst, TruthTable(ControlMapping.map(it => (it._1 -> toBits(it._2))), default)) - val srcList = slices.map(s => out(s._1, s._2)) + val srcList = slices.map(s => out(s._1 - 1, s._2)) - assert(out != default) - println(s"out = $out, default = $default\n") - println(s"dstList = ${dstList}\n") - println(s"srcList = ${srcList}\n") srcList - .zip(dstList) + .zip(dstList.reverse) .foreach({ case (src, dst) => - dst.toOption.get := src.asTypeOf(dst.toOption.get) + dst := src.asTypeOf(dst) }) - - pc.useImmB := DontCare } import flow.components.{RegisterFile, ProgramCounter, ALU, RamDpi} import chisel3.util.experimental.loadMemoryFromFileInline class Flow extends Module { - def lit(x: Data) = { x.litValue.toInt } - val dataType = UInt(32.W) val ram = Module(new RamDpi) val control = Module(new Control(32)) @@ -334,61 +84,42 @@ class Flow extends Module { val pc = Module(new ProgramCounter(dataType)) val alu = Module(new ALU(dataType)) - // TODO: Switch to Decoupled and Arbiter later - ram.io.pc := pc.out - val inst = ram.io.inst + ram.io.readAddr := pc.out + val inst = ram.io.readData dontTouch(reg.control.writeEnable) import control.pc.SrcSelect._ - val npc = Wire(dataType) - npc := pc.out + 4.U - pc.in.exeOut := alu.out.result - pc.in.immB := Cat(Fill(20, inst(31)), inst(7), inst(30, 25), inst(11, 8), inst(0)) + pc.in.pcSrcs(pStaticNpc.litValue.toInt) := pc.out + 4.U + pc.in.pcSrcs(pBranchResult.litValue.toInt) := alu.out.result control.inst := inst reg.control <> control.reg - // FIXME: Probably optimizable with bulk connection pc.control <> control.pc alu.control <> control.alu - val branchUseSlt = Wire(Bool()) - val branchInvertResult = Wire(Bool()) - branchUseSlt := inst(14) - branchInvertResult := inst(12) - val _branchResult = Mux(branchUseSlt, alu.out.result(0), alu.out.eq) - val branchResult = Mux(branchInvertResult, _branchResult, !_branchResult) - pc.control.useImmB := control.pc.useImmB && _branchResult import control.reg.WriteSelect._ - reg.in.writeData(lit(rAluOut)) := alu.out.result + reg.in.writeData(rAluOut.litValue.toInt) := alu.out.result + // TODO: Read address in load command goes here - reg.in.writeData(lit(rMemOut)) := ram.io.readData - reg.in.writeData(lit(rNpc)) := npc + reg.in.writeData(rMemOut.litValue.toInt) := DontCare reg.in.writeAddr := inst(11, 7) reg.in.rs(0) := inst(19, 15) // rs1 reg.in.rs(1) := inst(24, 20) // rs2 // TODO: Memory write goes here - ram.io.writeAddr := alu.out.result - ram.io.writeData := reg.out.src(1) - ram.io.writeMask := control.ram.writeMask - ram.io.writeEnable := control.ram.writeEnable + ram.io.writeAddr := DontCare + ram.io.writeData := DontCare + ram.io.writeMask := DontCare + ram.io.writeEnable := false.B ram.io.valid := true.B - ram.io.readAddr := alu.out.result - import control.alu.SrcASelect._ - import control.alu.SrcBSelect._ - alu.in.a(lit(aSrcARs1)) := reg.out.src(0) - alu.in.a(lit(aSrcAPc)) := pc.out - alu.in.a(lit(aSrcAZero)) := 0.U - - alu.in.b(lit(aSrcBRs2)) := reg.out.src(1) - alu.in.b(lit(aSrcBImmI)) := inst(31, 20).pad(aSrcBImmI.getWidth) - alu.in.b(lit(aSrcBImmJ)) := Cat(Fill(12, inst(31)), inst(19, 12), inst(20), inst(30, 25), inst(24, 21), 0.U(1.W)) - alu.in.b(lit(aSrcBImmB)) := Cat(Fill(20, inst(31)), inst(7), inst(30, 25), inst(11, 8), inst(0)) - alu.in.b(lit(aSrcBImmS)) := Cat(inst(31), inst(19, 12), inst(20), inst(30, 25), inst(24, 21), 0.U(1.W)).pad(aSrcBImmS.getWidth) + import control.alu.SrcSelect._ + alu.in.a(aSrcRs2.litValue.toInt) := reg.out.src(1) + alu.in.a(aSrcImm.litValue.toInt) := inst(31, 20) + alu.in.b := reg.out.src(0) Trace.traceName(pc.out); dontTouch(control.out) diff --git a/npc/core/src/main/scala/top/Main.scala b/npc/core/src/main/scala/top/Main.scala index 6de6893..3c02ff3 100644 --- a/npc/core/src/main/scala/top/Main.scala +++ b/npc/core/src/main/scala/top/Main.scala @@ -34,7 +34,7 @@ object VerilogMain extends App { } val annos = (new ChiselStage).execute( - Array("--target-dir", opt.targetDir.toString, "--target", "systemverilog", "--split-verilog", "--full-stacktrace"), + Array("--target-dir", opt.targetDir.toString, "--target", "systemverilog", "--split-verilog"), Seq( ) ++ (if(config.traceConfig.enable) Seq(ChiselGeneratorAnnotation(() => new Flow)) else Seq()) @@ -56,9 +56,9 @@ object VerilogMain extends App { .foreach( ct => println(s"""TOP.${ct.circuit}.${ct.path.map { case (Instance(i), _) => i }.mkString(".")}.${ct.tokens.collectFirst { case Ref(r) => r - }.get}""") + }.get}""") ) - + val verilatorConfigWriter = new PrintWriter(new File(opt.targetDir, opt.verilatorConfigFileOut.toString())) verilatorConfigWriter.write("`verilator_config\n") try { diff --git a/npc/csrc/Flow/CMakeLists.txt b/npc/csrc/Flow/CMakeLists.txt index ad8d2e9..606fd73 100644 --- a/npc/csrc/Flow/CMakeLists.txt +++ b/npc/csrc/Flow/CMakeLists.txt @@ -1,6 +1,5 @@ include(ChiselBuild) add_executable(V${TOPMODULE} config.cpp main.cpp) -target_link_libraries(V${TOPMODULE} PRIVATE disasm sdb) verilate(V${TOPMODULE} TRACE COVERAGE THREADS TOP_MODULE ${TOPMODULE} @@ -9,7 +8,6 @@ verilate(V${TOPMODULE} TRACE COVERAGE THREADS INCLUDE_DIRS ${CHISEL_OUTPUT_DIR} VERILATOR_ARGS "--vpi" # Enable VPI - "-Wno-UNOPTFLAT" ) add_test( diff --git a/npc/include/components.hpp b/npc/csrc/Flow/components.hpp similarity index 66% rename from npc/include/components.hpp rename to npc/csrc/Flow/components.hpp index fced1af..a84309a 100644 --- a/npc/include/components.hpp +++ b/npc/csrc/Flow/components.hpp @@ -1,23 +1,13 @@ #ifndef _NPC_COMPONENTS_H_ #define _NPC_COMPONENTS_H_ +#include "vpi_user.h" #include #include -#include #include #include #include -#include -#include -#include - -const std::map riscv32_regs_by_name{ - {"$0", 0}, {"ra", 1}, {"sp", 2}, {"gp", 3}, {"tp", 4}, {"t0", 5}, - {"t1", 6}, {"t2", 7}, {"s0", 8}, {"s1", 9}, {"a0", 10}, {"a1", 11}, - {"a2", 12}, {"a3", 13}, {"a4", 14}, {"a5", 15}, {"a6", 16}, {"a7", 17}, - {"s2", 18}, {"s3", 19}, {"s4", 20}, {"s5", 21}, {"s6", 22}, {"s7", 23}, - {"s8", 24}, {"s9", 25}, {"s10", 26}, {"s11", 27}, {"t3", 28}, {"t4", 29}, - {"t5", 30}, {"t6", 31}}; +#include template class _RegistersBase { std::array regs; @@ -35,6 +25,36 @@ public: } }; +template +class _RegistersVPI : public _RegistersBase { + std::array reg_handles; + vpiHandle pc_handle; + T vpi_get(vpiHandle vh) { + s_vpi_value v; + v.format = vpiIntVal; + vpi_get_value(vh, &v); + return v.value.integer; + } + T fetch_pc(void) { return vpi_get(pc_handle); } + T fetch_reg(std::size_t id) { return vpi_get(reg_handles[id]); } + +public: + _RegistersVPI(const std::string regs_prefix, + const std::string pcname) { + for (int i = 0; i < nr; i++) { + std::string regname = regs_prefix + std::to_string(i); + vpiHandle vh = vpi_handle_by_name((PLI_BYTE8 *)regname.c_str(), nullptr); + if (vh == nullptr) { + std::cerr << "vpiHandle " << regname.c_str() << " not found" + << std::endl; + exit(EXIT_FAILURE); + } + reg_handles[i] = vh; + } + pc_handle = vpi_handle_by_name((PLI_BYTE8 *)pcname.c_str(), nullptr); + } +}; + template class Memory { std::size_t addr_to_index(std::size_t addr) { if (addr < 0x80000000) { @@ -54,8 +74,7 @@ template class Memory { public: std::array mem; Memory(std::filesystem::path filepath, bool is_binary = true) { - if (!std::filesystem::exists(filepath)) - throw std::runtime_error("Memory file not found"); + assert(std::filesystem::exists(filepath)); if (is_binary) { std::ifstream file(filepath, std::ios::binary); char *pmem = reinterpret_cast(mem.data()); diff --git a/npc/csrc/Flow/main.cpp b/npc/csrc/Flow/main.cpp index b1c37c9..50eeeeb 100644 --- a/npc/csrc/Flow/main.cpp +++ b/npc/csrc/Flow/main.cpp @@ -1,15 +1,10 @@ -#include "VFlow___024root.h" +#include "components.hpp" #include "config.hpp" -#include "disasm.hpp" #include "vl_wrapper.hpp" #include "vpi_user.h" -#include "vpi_wrapper.hpp" #include #include -#include #include -#include -#include using VlModule = VlModuleInterfaceCommon; using Registers = _RegistersVPI; @@ -36,10 +31,9 @@ void pmem_write(int waddr, int wdata, char wmask) { } } -Disassembler d{"riscv32-pc-linux-gnu"}; - VlModule *top; Registers *regs; +using CPUState = CPUStateBase; vpiHandle pc = nullptr; void difftest_memcpy(paddr_t, void *, size_t, bool){}; @@ -64,8 +58,6 @@ void difftest_exec(uint64_t n) { } } } -// std::cout << d.disassemble(top->rootp->Flow__DOT__pc__DOT__pc_reg, (uint8_t *)&top->rootp->Flow__DOT___ram_inst, 4) << std::endl; - void difftest_init(int port) { // top = std::make_unique(config.do_trace, config.wavefile); top = new VlModule{config.do_trace, config.wavefile}; @@ -73,34 +65,20 @@ void difftest_init(int port) { top->reset_eval(10); } -DifftestInterface dut_interface = DifftestInterface{ - &difftest_memcpy, &difftest_regcpy, &difftest_exec, &difftest_init}; - -SDB::SDB sdb_dut; -extern "C" { -word_t reg_str2val(const char *name, bool *success) { - return sdb_dut.reg_str2val(name, success); -} -} - int main(int argc, char **argv, char **env) { config.cli_parse(argc, argv); /* -- Difftest -- */ std::filesystem::path ref{config.lib_ref}; + DifftestInterface dut_interface = DifftestInterface{ + &difftest_memcpy, &difftest_regcpy, &difftest_exec, &difftest_init}; DifftestInterface ref_interface = DifftestInterface{ref}; Difftest> diff{dut_interface, ref_interface, pmem_get(), 128}; int t = 8; - sdb_dut.main_loop(); while (t--) { - if (!diff.step(1)) { - uint32_t pc = regs->get_pc(); - uint32_t inst = pmem_read(pc); - std::cout << diff << d.disassemble(pc, (uint8_t *)&inst, 4) << std::endl; - return EXIT_FAILURE; - } + diff.step(1); } return 0; diff --git a/npc/csrc/Flow/vpi_wrapper.hpp b/npc/csrc/Flow/vpi_wrapper.hpp deleted file mode 100644 index a1dd089..0000000 --- a/npc/csrc/Flow/vpi_wrapper.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef _NPC_VPI_WRAPPER_H_ -#define _NPC_VPI_WRAPPER_H_ -#include -#include - -template -class _RegistersVPI : public _RegistersBase { - std::array reg_handles; - vpiHandle pc_handle; - T vpi_get(vpiHandle vh) { - s_vpi_value v; - v.format = vpiIntVal; - vpi_get_value(vh, &v); - return v.value.integer; - } - T fetch_pc(void) { return vpi_get(pc_handle); } - T fetch_reg(std::size_t id) { return vpi_get(reg_handles[id]); } - -public: - _RegistersVPI(const std::string regs_prefix, - const std::string pcname) { - for (int i = 0; i < nr; i++) { - std::string regname = regs_prefix + std::to_string(i); - vpiHandle vh = vpi_handle_by_name((PLI_BYTE8 *)regname.c_str(), nullptr); - if (vh == nullptr) { - std::cerr << "vpiHandle " << regname.c_str() << " not found" - << std::endl; - exit(EXIT_FAILURE); - } - reg_handles[i] = vh; - } - pc_handle = vpi_handle_by_name((PLI_BYTE8 *)pcname.c_str(), nullptr); - } -}; - -#endif diff --git a/npc/include/config.hpp b/npc/include/config.hpp deleted file mode 100644 index 9f5873c..0000000 --- a/npc/include/config.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _NPC_CONFIG_H_ -#define _NPC_CONFIG_H_ -#include -#include -#include -#include - -struct Config { - std::filesystem::path memory_file; - uint64_t max_sim_time = 1000; - bool memory_file_binary = {true}; - bool do_trace{false}; - std::filesystem::path wavefile; - std::filesystem::path lib_ref; - void cli_parse(int argc, char **argv); -}; - -extern Config config; - -#endif \ No newline at end of file diff --git a/npc/include/difftest.hpp b/npc/include/difftest.hpp index 7349004..dd690b9 100644 --- a/npc/include/difftest.hpp +++ b/npc/include/difftest.hpp @@ -1,14 +1,12 @@ #ifndef _DIFFTEST_DIFFTEST_H_ #define _DIFFTEST_DIFFTEST_H_ #include -#include #include #include #include #include #include #include -#include #include using paddr_t = uint32_t; @@ -71,11 +69,14 @@ public: dut.regcpy(dut_state.get(), DIFFTEST_FROM_REF); } - bool step(uint64_t n) { + void step(uint64_t n) { ref.exec(n); dut.exec(n); fetch_state(); - return *ref_state == *dut_state; + if (*ref_state != *dut_state) { + std::cout << *this; + exit(EXIT_FAILURE); + } } friend std::ostream &operator<<(std::ostream &os, const Difftest &d) { @@ -89,8 +90,6 @@ public: template struct CPUStateBase { R reg[nr_reg] = {0}; paddr_t pc = 0x80000000; - static const std::map inline regs_by_name = - riscv32_regs_by_name; CPUStateBase() { for (int i = 0; i < nr_reg; i++) reg[i] = 0; @@ -107,9 +106,6 @@ template struct CPUStateBase { bool operator!=(const CPUStateBase &other) const { return !(*this == other); // Reuse the == operator for != implementation } - - /* This does not update the register!!! */ - R at(std::string name) { return reg[regs_by_name.at(name)]; } }; template diff --git a/npc/include/types.h b/npc/include/types.h deleted file mode 100644 index f6a8d87..0000000 --- a/npc/include/types.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _NPC_TYPES_H__ -#define _NPC_TYPES_H__ -#include - -typedef uint32_t word_t; -typedef int32_t sword_t; -static const word_t WORD_T_MAX = UINT32_MAX; -static const sword_t SWORD_T_MAX = INT32_MAX; -static const sword_t SWORD_T_MIN = INT32_MIN; -#define WORD_BYTES 4 - -#define FMT_WORD "0x%08x" -typedef uint32_t vaddr_t; -typedef uint32_t paddr_t; -#define FMT_ADDR "0x%08x" -typedef uint16_t ioaddr_t; - -#ifdef __cplusplus -#include -using CPUState = CPUStateBase; -#endif - -#endif \ No newline at end of file diff --git a/npc/include/vl_wrapper.hpp b/npc/include/vl_wrapper.hpp deleted file mode 100644 index 4d42b55..0000000 --- a/npc/include/vl_wrapper.hpp +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef _NPC_TRACER_H_ -#define _NPC_TRACER_H_ -#include -#include - -template class Tracer { - std::shared_ptr top; - std::unique_ptr m_trace; - uint64_t cycle = 0; - -public: - Tracer(T *top, std::filesystem::path wavefile) { - top = top; - Verilated::traceEverOn(true); - m_trace = std::make_unique(); - top->trace(m_trace.get(), 5); - m_trace->open(wavefile.c_str()); - } - ~Tracer() { m_trace->close(); } - - /** - * Dump signals to waveform file. Must be called once after every top->eval() - * call. - */ - void update() { m_trace->dump(cycle++); } -}; - -template class VlModuleInterfaceCommon : public T { - uint64_t sim_time = 0; - uint64_t posedge_cnt = 0; - std::unique_ptr> tracer; - -public: - VlModuleInterfaceCommon(bool do_trace, - std::filesystem::path wavefile = "waveform.vcd") { - if (do_trace) - tracer = std::make_unique>(this, wavefile); - } - void eval() { - if (this->is_posedge()) { - posedge_cnt++; - } - T::clock = !T::clock; - sim_time++; - T::eval(); - if (tracer) - tracer->update(); - } - void eval(int n) { - for (int i = 0; i < n; i++) { - this->eval(); - } - } - void reset_eval(int n) { - this->reset = 1; - this->eval(n); - this->reset = 0; - } - bool is_posedge() { - // Will be posedge when eval is called - return T::clock == 0; - } -}; - -#endif diff --git a/npc/utils/CMakeLists.txt b/npc/utils/CMakeLists.txt deleted file mode 100644 index 017313c..0000000 --- a/npc/utils/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -add_subdirectory(disasm) -if (ENABLE_SDB) - add_subdirectory(sdb) -endif() diff --git a/npc/utils/disasm/CMakeLists.txt b/npc/utils/disasm/CMakeLists.txt deleted file mode 100644 index e019bf7..0000000 --- a/npc/utils/disasm/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -add_library(disasm disasm.cpp) -target_include_directories(disasm PUBLIC include) -llvm_map_components_to_libnames(LLVM_LIBS ${LLVM_TARGETS_TO_BUILD}) -target_link_libraries(disasm PUBLIC ${LLVM_LIBS}) diff --git a/npc/utils/disasm/disasm.cpp b/npc/utils/disasm/disasm.cpp deleted file mode 100644 index 0e817ba..0000000 --- a/npc/utils/disasm/disasm.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include -#include -#include -#include -#include -#include -#if LLVM_VERSION_MAJOR >= 14 -#include -#if LLVM_VERSION_MAJOR >= 15 -#include -#endif -#else -#include -#endif -#include -#include -#include - -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic pop -#endif - -#if LLVM_VERSION_MAJOR < 11 -#error Please use LLVM with major version >= 11 -#endif - -Disassembler::Disassembler(std::string triple) : triple(triple) { - llvm::InitializeAllTargetInfos(); - llvm::InitializeAllTargetMCs(); - llvm::InitializeAllAsmParsers(); - llvm::InitializeAllDisassemblers(); - - std::string errstr; - - llvm::MCInstrInfo *gMII = nullptr; - llvm::MCRegisterInfo *gMRI = nullptr; - auto target = llvm::TargetRegistry::lookupTarget(triple, errstr); - if (!target) { - llvm::errs() << "Can't find target for " << triple << ": " << errstr - << "\n"; - assert(0); - } - - llvm::MCTargetOptions MCOptions; - gSTI = target->createMCSubtargetInfo(triple, "", ""); - std::string isa = target->getName(); - if (isa == "riscv32" || isa == "riscv64") { - gSTI->ApplyFeatureFlag("+m"); - gSTI->ApplyFeatureFlag("+a"); - gSTI->ApplyFeatureFlag("+c"); - gSTI->ApplyFeatureFlag("+f"); - gSTI->ApplyFeatureFlag("+d"); - } - gMII = target->createMCInstrInfo(); - gMRI = target->createMCRegInfo(triple); - auto AsmInfo = target->createMCAsmInfo(*gMRI, triple, MCOptions); -#if LLVM_VERSION_MAJOR >= 13 - auto llvmTripleTwine = llvm::Twine(triple); - auto llvmtriple = llvm::Triple(llvmTripleTwine); - auto Ctx = new llvm::MCContext(llvmtriple, AsmInfo, gMRI, nullptr); -#else - auto Ctx = new llvm::MCContext(AsmInfo, gMRI, nullptr); -#endif - gDisassembler = target->createMCDisassembler(*gSTI, *Ctx); - gIP = target->createMCInstPrinter(llvm::Triple(triple), - AsmInfo->getAssemblerDialect(), *AsmInfo, - *gMII, *gMRI); - gIP->setPrintImmHex(true); - gIP->setPrintBranchImmAsAddress(true); - if (isa == "riscv32" || isa == "riscv64") - gIP->applyTargetSpecificCLOption("no-aliases"); -} - -std::string Disassembler::disassemble(uint64_t pc, uint8_t *code, int nbyte) { - llvm::MCInst inst; - llvm::ArrayRef arr(code, nbyte); - uint64_t dummy_size = 0; - gDisassembler->getInstruction(inst, dummy_size, arr, pc, llvm::nulls()); - - std::stringstream ss; - ss << "0x" << std::hex << pc << ": "; - std::string s = ss.str(); - llvm::raw_string_ostream os{s}; - gIP->printInst(&inst, pc, "", *gSTI, os); - - return s; -} diff --git a/npc/utils/disasm/include/disasm.hpp b/npc/utils/disasm/include/disasm.hpp deleted file mode 100644 index a14ebb3..0000000 --- a/npc/utils/disasm/include/disasm.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _NPC_UTILS_DISASM_ -#define _NPC_UTILS_DISASM_ -#include "llvm/MC/MCDisassembler/MCDisassembler.h" -#include "llvm/MC/MCInstPrinter.h" - -class Disassembler { - llvm::MCDisassembler *gDisassembler = nullptr; - llvm::MCSubtargetInfo *gSTI = nullptr; - llvm::MCInstPrinter *gIP = nullptr; - std::string triple; - -public: - Disassembler(std::string); - std::string disassemble(uint64_t pc, uint8_t *code, int nbyte); -}; - -#endif \ No newline at end of file diff --git a/npc/utils/sdb/CMakeLists.txt b/npc/utils/sdb/CMakeLists.txt deleted file mode 100644 index 6b1cb2c..0000000 --- a/npc/utils/sdb/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -find_package(Readline REQUIRED) -find_package(FLEX REQUIRED) -find_package(BISON REQUIRED) -set(PARSER_DIR "${CMAKE_CURRENT_BINARY_DIR}") -set(LEXER_OUT "${PARSER_DIR}/lexer.c") -set(PARSER_OUT "${PARSER_DIR}/parser.c") -flex_target(LEXER addrexp.l "${LEXER_OUT}" DEFINES_FILE "${PARSER_DIR}/addrexp_lex.h") -bison_target(PARSER addrexp.y "${PARSER_OUT}" DEFINES_FILE "${PARSER_DIR}/addrexp.h") -add_flex_bison_dependency(LEXER PARSER) - -add_library(sdb sdb.cpp console.cpp "${LEXER_OUT}" "${PARSER_OUT}") -target_link_libraries(sdb PRIVATE ${Readline_LIBRARY}) -target_include_directories(sdb PRIVATE ${Readline_INCLUDE_DIR}) -target_include_directories(sdb PUBLIC include) diff --git a/npc/utils/sdb/addrexp.l b/npc/utils/sdb/addrexp.l deleted file mode 100644 index d81f0e1..0000000 --- a/npc/utils/sdb/addrexp.l +++ /dev/null @@ -1,26 +0,0 @@ -%{ - #include - #include - #include "addrexp.h" - static bool success = false; - void yyerror(word_t *result, const char *err); - word_t reg_str2val(const char *name, bool*); -%} -%option noyywrap - -%% - -0[xX][0-9a-fA-F]+ { yylval = strtoul(yytext, NULL, 16); return HEX_NUMBER; } -[0-9]+ { yylval = strtoul(yytext, NULL, 10); return NUMBER; } -$[asgprt$][0-9pa][0-9]? { - yylval = reg_str2val(yytext + 1, &success); - if(!success) { - yyerror(NULL, "Failed to convert reg to value"); - return YYerror; - } - return REGISTER; -} -[+\-*/<=()] { return *yytext; } -[ \t] { } -. { printf("Unexpected character: %s\n", yytext); return YYerror; } -%% diff --git a/npc/utils/sdb/addrexp.y b/npc/utils/sdb/addrexp.y deleted file mode 100644 index ca1a5c9..0000000 --- a/npc/utils/sdb/addrexp.y +++ /dev/null @@ -1,58 +0,0 @@ -%code requires { - #include - #include - #include - extern int yylex(void); -} -%{ - #include - #include - #include - void yyerror(word_t *result, const char *err) { - fprintf(stderr, "%s", err); - } - int pmem_read(int raddr); -%} - -%token NUMBER HEX_NUMBER -%token REGISTER -%locations -%start input -%define api.value.type { word_t } -%parse-param { uint32_t *result } -%left '-' '+' -%left '*' '/' - -%% -input - : expression { *result = $1; } - ; - -expression - : number { $$ = $1; } - | expression '>' '=' expression { $$ = ($1 >= $4); } - | expression '<' '=' expression { $$ = ($1 <= $4); } - | expression '=' '=' expression { $$ = ($1 == $4); } - | expression '!' '=' expression { $$ = ($1 == $4); } - | expression '>' expression { $$ = ($1 > $3); } - | expression '<' expression { $$ = ($1 < $3); } - | expression '+' expression { $$ = $1 + $3; } - | expression '-' expression { $$ = $1 - $3; } - | expression '*' expression { $$ = $1 * $3; } - | expression '/' expression { - if($3 == 0) { - fprintf(stderr, "Error: divide by zero at" FMT_WORD " / " FMT_WORD "\n", $1, $3); - YYABORT; - }; - $$ = $1 / $3; - } - | '-' number { $$ = -$2; } - | '*' expression { $$ = pmem_read($2); } - | '(' expression ')' { $$ = $2; } - -number - : REGISTER - | NUMBER - | HEX_NUMBER - -%% diff --git a/npc/utils/sdb/console.cpp b/npc/utils/sdb/console.cpp deleted file mode 100644 index 485e192..0000000 --- a/npc/utils/sdb/console.cpp +++ /dev/null @@ -1,215 +0,0 @@ -// cpp-readline library -// -// @author zmij -// @date Nov 30, 2015 - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace CppReadline { -namespace { - -Console *currentConsole = nullptr; -HISTORY_STATE *emptyHistory = history_get_history_state(); - -} /* namespace */ - -struct Console::Impl { - using RegisteredCommands = - std::unordered_map; - - ::std::string greeting_; - // These are hardcoded commands. They do not do anything and are catched manually in the executeCommand function. - RegisteredCommands commands_; - HISTORY_STATE *history_ = nullptr; - - Impl(::std::string const &greeting) : greeting_(greeting), commands_() {} - ~Impl() { free(history_); } - - Impl(Impl const &) = delete; - Impl(Impl &&) = delete; - Impl &operator=(Impl const &) = delete; - Impl &operator=(Impl &&) = delete; -}; - -// Here we set default commands, they do nothing since we quit with them -// Quitting behaviour is hardcoded in readLine() -Console::Console(std::string const &greeting) : pimpl_{new Impl{greeting}} { - // Init readline basics - rl_attempted_completion_function = &Console::getCommandCompletions; - - // These are default hardcoded commands. - // Help command lists available commands. - pimpl_->commands_["help"] = [this](const Arguments &) { - auto commands = getRegisteredCommands(); - std::cout << "Available commands are:\n"; - for (auto &command : commands) - std::cout << "\t" << command << "\n"; - return ReturnCode::Ok; - }; - // Run command executes all commands in an external file. - pimpl_->commands_["run"] = [this](const Arguments &input) { - if (input.size() < 2) { - std::cout << "Usage: " << input[0] << " script_filename\n"; - return 1; - } - return executeFile(input[1]); - }; - // Quit and Exit simply terminate the console. - pimpl_->commands_["quit"] = [this](const Arguments &) { - return ReturnCode::Quit; - }; - - pimpl_->commands_["exit"] = [this](const Arguments &) { - return ReturnCode::Quit; - }; -} - -Console::~Console() = default; - -void Console::registerCommand(const std::string &s, CommandFunction f) { - pimpl_->commands_[s] = f; -} - -std::vector Console::getRegisteredCommands() const { - std::vector allCommands; - for (auto &pair : pimpl_->commands_) - allCommands.push_back(pair.first); - - return allCommands; -} - -void Console::saveState() { - free(pimpl_->history_); - pimpl_->history_ = history_get_history_state(); -} - -void Console::reserveConsole() { - if (currentConsole == this) - return; - - // Save state of other Console - if (currentConsole) - currentConsole->saveState(); - - // Else we swap state - if (!pimpl_->history_) - history_set_history_state(emptyHistory); - else - history_set_history_state(pimpl_->history_); - - // Tell others we are using the console - currentConsole = this; -} - -void Console::setGreeting(const std::string &greeting) { - pimpl_->greeting_ = greeting; -} - -std::string Console::getGreeting() const { return pimpl_->greeting_; } - -int Console::executeCommand(const std::string &command) { - // Convert input to vector - std::vector inputs; - { - std::istringstream iss(command); - std::copy(std::istream_iterator(iss), - std::istream_iterator(), std::back_inserter(inputs)); - } - - if (inputs.size() == 0) - return ReturnCode::Ok; - - Impl::RegisteredCommands::iterator it; - if ((it = pimpl_->commands_.find(inputs[0])) != end(pimpl_->commands_)) { - return static_cast((it->second)(inputs)); - } - - std::cout << "Command '" << inputs[0] << "' not found.\n"; - return ReturnCode::Error; -} - -int Console::executeFile(const std::string &filename) { - std::ifstream input(filename); - if (!input) { - std::cout << "Could not find the specified file to execute.\n"; - return ReturnCode::Error; - } - std::string command; - int counter = 0, result; - - while (std::getline(input, command)) { - if (command[0] == '#') - continue; // Ignore comments - // Report what the Console is executing. - std::cout << "[" << counter << "] " << command << '\n'; - if ((result = executeCommand(command))) - return result; - ++counter; - std::cout << '\n'; - } - - // If we arrived successfully at the end, all is ok - return ReturnCode::Ok; -} - -int Console::readLine() { - reserveConsole(); - - char *buffer = readline(pimpl_->greeting_.c_str()); - if (!buffer) { - std::cout - << '\n'; // EOF doesn't put last endline so we put that so that it looks uniform. - return ReturnCode::Quit; - } - - // TODO: Maybe add commands to history only if succeeded? - if (buffer[0] != '\0') - add_history(buffer); - - std::string line(buffer); - free(buffer); - - return executeCommand(line); -} - -char **Console::getCommandCompletions(const char *text, int start, int) { - char **completionList = nullptr; - - if (start == 0) - completionList = rl_completion_matches(text, &Console::commandIterator); - - return completionList; -} - -char *Console::commandIterator(const char *text, int state) { - static Impl::RegisteredCommands::iterator it; - if (!currentConsole) - return nullptr; - auto &commands = currentConsole->pimpl_->commands_; - - if (state == 0) - it = begin(commands); - - while (it != end(commands)) { - auto &command = it->first; - ++it; - if (command.find(text) != std::string::npos) { - return strdup(command.c_str()); - } - } - return nullptr; -} -} // namespace CppReadline diff --git a/npc/utils/sdb/include/console.hpp b/npc/utils/sdb/include/console.hpp deleted file mode 100644 index 538ce2f..0000000 --- a/npc/utils/sdb/include/console.hpp +++ /dev/null @@ -1,145 +0,0 @@ -// cpp-readline library -// -// @author zmij -// @date Nov 30, 2015 - -#ifndef CONSOLE_CONSOLE_HEADER_FILE -#define CONSOLE_CONSOLE_HEADER_FILE - -#include -#include -#include -#include - -namespace CppReadline { -class Console { -public: - /** - * @brief This is the function type that is used to interface with the Console class. - * - * These are the functions that are going to get called by Console - * when the user types in a message. The vector will hold the - * command elements, and the function needs to return its result. - * The result can either be Quit (-1), OK (0), or an arbitrary - * error (>=1). - */ - using Arguments = std::vector; - using CommandFunction = std::function; - - enum ReturnCode { - Quit = -1, - Ok = 0, - Error = 1 // Or greater! - }; - - /** - * @brief Basic constructor. - * - * The Console comes with two predefined commands: "quit" and - * "exit", which both terminate the console, "help" which prints a - * list of all registered commands, and "run" which executes script - * files. - * - * These commands can be overridden or unregistered - but remember - * to leave at least one to quit ;). - * - * @param greeting This represents the prompt of the Console. - */ - explicit Console(std::string const &greeting); - - /** - * @brief Basic destructor. - * - * Frees the history which is been produced by GNU readline. - */ - ~Console(); - - /** - * @brief This function registers a new command within the Console. - * - * If the command already existed, it overwrites the previous entry. - * - * @param s The name of the command as inserted by the user. - * @param f The function that will be called once the user writes the command. - */ - void registerCommand(const std::string &s, CommandFunction f); - - /** - * @brief This function returns a list with the currently available commands. - * - * @return A vector containing all registered commands names. - */ - std::vector getRegisteredCommands() const; - - /** - * @brief Sets the prompt for this Console. - * - * @param greeting The new greeting. - */ - void setGreeting(const std::string &greeting); - - /** - * @brief Gets the current prompt of this Console. - * - * @return The currently set greeting. - */ - std::string getGreeting() const; - - /** - * @brief This function executes an arbitrary string as if it was inserted via stdin. - * - * @param command The command that needs to be executed. - * - * @return The result of the operation. - */ - int executeCommand(const std::string &command); - - /** - * @brief This function calls an external script and executes all commands inside. - * - * This function stops execution as soon as any single command returns something - * different from 0, be it a quit code or an error code. - * - * @param filename The pathname of the script. - * - * @return What the last command executed returned. - */ - int executeFile(const std::string &filename); - - /** - * @brief This function executes a single command from the user via stdin. - * - * @return The result of the operation. - */ - int readLine(); - -private: - Console(const Console &) = delete; - Console(Console &&) = delete; - Console &operator=(Console const &) = delete; - Console &operator=(Console &&) = delete; - - struct Impl; - using PImpl = ::std::unique_ptr; - PImpl pimpl_; - - /** - * @brief This function saves the current state so that some other Console can make use of the GNU readline facilities. - */ - void saveState(); - /** - * @brief This function reserves the use of the GNU readline facilities to the calling Console instance. - */ - void reserveConsole(); - - // GNU newline interface to our commands. - using commandCompleterFunction = char **(const char *text, int start, - int end); - using commandIteratorFunction = char *(const char *text, int state); - - static commandCompleterFunction getCommandCompletions; - static commandIteratorFunction commandIterator; -}; -} // namespace CppReadline - -#endif diff --git a/npc/utils/sdb/include/sdb.hpp b/npc/utils/sdb/include/sdb.hpp deleted file mode 100644 index 18aae8a..0000000 --- a/npc/utils/sdb/include/sdb.hpp +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef _SDB_SDB_HEADER_FILE_ -#define _SDB_SDB_HEADER_FILE_ - -#include -#include -#include -#include -#include -#include - -namespace cr = CppReadline; -using ret = cr::Console::ReturnCode; - -namespace SDB { - -enum SDBStatus { - SDB_SUCCESS, - SDB_WRONG_ARGUMENT, -}; - -struct Handler { - const std::vector names; - cr::Console::CommandFunction f; -}; - -template class _SDBHandlers { - using CPUState = CPUStateBase; - -private: - std::vector all_handlers; - -public: - static CPUState cpu; - -private: - static _SDBHandlers *instance; - static int cmd_continue(const cr::Console::Arguments &input); - static int cmd_step(const std::vector &input); - static int cmd_info_registers(const std::vector &input); - static int cmd_print(const std::vector &input); - _SDBHandlers(std::vector all_handlers) - : all_handlers(all_handlers){}; - -public: - _SDBHandlers(const _SDBHandlers &) = delete; - _SDBHandlers operator=(const _SDBHandlers &) = delete; - - static _SDBHandlers *getInstance() { - if (instance == nullptr) { - std::vector all_handlers{ - Handler{{"c", "continue"}, &_SDBHandlers::cmd_continue}, - Handler{{"si", "step-instruction"}, &_SDBHandlers::cmd_step}, - }; - instance = new _SDBHandlers(all_handlers); - } - return instance; - } - - void registerHandlers(cr::Console *c); -}; - -template -_SDBHandlers *_SDBHandlers::instance = nullptr; - -template -CPUState _SDBHandlers::cpu = CPUState(); - -template -int _SDBHandlers::cmd_continue(const cr::Console::Arguments &input) { - if (input.size() > 1) - return SDB_WRONG_ARGUMENT; - funcs.exec(-1); - return SDB_SUCCESS; -} - -template -int _SDBHandlers::cmd_step(const std::vector &input) { - if (input.size() > 2) { - return SDB_WRONG_ARGUMENT; - } - uint64_t step_count = input.size() == 2 ? std::stoull(input[1]) : 1; - funcs.exec(step_count); - return SDB_SUCCESS; -} - -template -int _SDBHandlers::cmd_info_registers( - const std::vector &input) { - if (input.size() > 1) - return SDB_WRONG_ARGUMENT; - std::cout << _SDBHandlers::getInstance()->cpu << std::endl; - return SDB_SUCCESS; -} - -template -int _SDBHandlers::cmd_print(const std::vector &input) { - exit(1); -} - -template -void _SDBHandlers::registerHandlers(cr::Console *c) { - for (auto &h : this->all_handlers) { - for (auto &name : h.names) { - c->registerCommand(name, h.f); - } - } -} - -template class SDB { -private: - std::unique_ptr c; - using SDBHandlers = _SDBHandlers; - -public: - SDB(std::string const &greeting = "\033[1;34m(npc)\033[0m ") { - c = std::make_unique(greeting); - SDBHandlers::getInstance()->registerHandlers(c.get()); - }; - - word_t reg_str2val(const char *name, bool *success) { - try { - *success = true; - return SDBHandlers::getInstance()->cpu.at(name); - } catch (std::runtime_error) { - *success = false; - return 0; - } - } - - int main_loop() { - int retCode; - do { - retCode = c->readLine(); - // We can also change the prompt based on last return value: - if (retCode == ret::Ok) - c->setGreeting("\033[1;34m(npc)\033[0m "); - else - c->setGreeting("\033[1;31m(npc)\033[0m "); - - if (retCode == SDB_WRONG_ARGUMENT) { - std::cout << "Wrong argument give to command\n"; - } - } while (retCode != ret::Quit); - return 0; - } -}; -} // namespace SDB - -#endif \ No newline at end of file diff --git a/npc/utils/sdb/sdb.cpp b/npc/utils/sdb/sdb.cpp deleted file mode 100644 index 9bfa6b5..0000000 --- a/npc/utils/sdb/sdb.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include -#include -#include -#include -#include - -namespace cr = CppReadline; -using ret = cr::Console::ReturnCode; - -namespace SDB {}