From 84c8de84618a555904095f3bfbd2f0d1c01fe319 Mon Sep 17 00:00:00 2001 From: xinyangli Date: Fri, 29 Mar 2024 10:35:49 +0800 Subject: [PATCH] npc: reg file access through vpi --- npc/CMakeLists.txt | 161 ++++++++++++------ npc/core/build.sbt | 12 +- .../main/scala/{Main.scala => FlowMain.scala} | 13 +- npc/core/src/main/scala/Mem.scala | 1 + npc/core/src/main/scala/RegisterFile.scala | 74 +++----- npc/core/src/main/scala/top/ArgParse.scala | 47 +++++ npc/core/src/main/scala/top/Config.scala | 16 ++ npc/core/src/main/scala/top/Main.scala | 72 ++++++++ npc/core/src/main/scala/utils/DPI.scala | 11 ++ npc/csrc/Flow/main.cpp | 113 ++++++++---- npc/flake.nix | 3 +- 11 files changed, 378 insertions(+), 145 deletions(-) rename npc/core/src/main/scala/{Main.scala => FlowMain.scala} (93%) create mode 100644 npc/core/src/main/scala/Mem.scala create mode 100644 npc/core/src/main/scala/top/ArgParse.scala create mode 100644 npc/core/src/main/scala/top/Config.scala create mode 100644 npc/core/src/main/scala/top/Main.scala create mode 100644 npc/core/src/main/scala/utils/DPI.scala diff --git a/npc/CMakeLists.txt b/npc/CMakeLists.txt index db9d0a1..bd56708 100644 --- a/npc/CMakeLists.txt +++ b/npc/CMakeLists.txt @@ -1,91 +1,157 @@ -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.26) project(flow) -set (CMAKE_CXX_STANDARD 11) +set (CMAKE_CXX_STANDARD 14) cmake_policy(SET CMP0144 NEW) -execute_process( - COMMAND ${CMAKE_SOURCE_DIR}/../git_commit.sh "configure(npc)" - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/.. -) +include(CMakeDependentOption) +enable_testing() -find_package(SDL2 REQUIRED) -find_package(SDL2_image REQUIRED) +# -- Build options +option(BUILD_USE_BLOOP "Whether to use bloop to spped up elaborate" ON) +option(BUILD_SIM_TARGET "Whether to build verilator simulation binary" ON) +cmake_dependent_option(BUILD_SIM_NVBOARD_TARGET "Whether to build nvboard target" OFF "BUILD_SIM_TARGET" OFF) +option(ENABLE_YSYX_GIT_TRACKER "Ysyx tracker support" OFF) +set(TOPMODULE "Flow" CACHE STRING "Topmodule name in chisel") -find_package(verilator REQUIRED) +# -- Ysyx tracker, configure +if(ENABLE_YSYX_GIT_TRACKER) + execute_process( + COMMAND ${CMAKE_SOURCE_DIR}/../git_commit.sh "configure(npc)" + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/.. + ) +endif() + +# -- Check dependencies +if(BUILD_SIM_TARGET) + find_package(verilator REQUIRED) +endif() +if(BUILD_SIM_NVBOARD_TARGET) + find_package(SDL2 REQUIRED) + find_package(SDL2_image REQUIRED) +endif() find_library(NVBOARD_LIBRARY NAMES nvboard) find_path(NVBOARD_INCLUDE_DIR NAMES nvboard.h) -set(TOPMODULES "Flow") +# FIXME: all scala source file are tracked here, cause all files to rebuild +# after a source update. +set(SCALA_CORE "${CMAKE_CURRENT_SOURCE_DIR}/core") +set(CHISEL_MODULE_CLASS "${CMAKE_PROJECT_NAME}.${TOPMODULE}") -foreach(TOPMODULE IN LISTS TOPMODULES) - - # FIXME: all scala source file are tracked here, cause all files to rebuild - # after a source update. - set(SCALA_CORE "${CMAKE_CURRENT_SOURCE_DIR}/core") - set(CHISEL_MODULE_CLASS "${CMAKE_PROJECT_NAME}.${TOPMODULE}") - file(GLOB_RECURSE SCALA_CORE_SOURCES "${SCALA_CORE}/src/main/scala/*.scala") - file(GLOB_RECURSE SCALA_CORE_TEST_SOURCES "${SCALA_CORE}/src/test/scala/*.scala") +# Verilog files are generted in CHISEL_OUTPUT_TMP_DIR and copy to +# CHISEL_OUTPUT_DIR if content changes +set(CHISEL_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc/) +set(CHISEL_OUTPUT_TMP_DIR ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc_tmp/) - # Configure time verilog source generation for verilator - execute_process( - COMMAND sbt "runMain circt.stage.ChiselMain --target-dir ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc --module ${CHISEL_MODULE_CLASS} --target verilog" - WORKING_DIRECTORY ${SCALA_CORE} - ) +set(CHISEL_OUTPUT_VERILATOR_CONF ${CHISEL_OUTPUT_DIR}/conf.vlt) +set(CHISEL_OUTPUT_TOPMODULE ${CHISEL_OUTPUT_DIR}/${TOPMODULE}.sv) +set(CHISEL_EMIT_ARGS "--target-dir ${CHISEL_OUTPUT_TMP_DIR}") +# -- Add an always run target to generate verilog files with sbt/bloop, +# as we don't know if the result files will be different from cmake +# NOTE: Must reconfigure if we add new files in SCALA_CORE directory +file(GLOB_RECURSE SCALA_CORE_SOURCES "${SCALA_CORE}/src/main/scala/*.scala") +file(GLOB_RECURSE SCALA_CORE_RESOURCES "${SCALA_CORE}/src/resource/*") +set(CHISEL_DEPENDENCY ${SCALA_CORE_SOURCES} ${SCALA_CORE_RESOURCE} ${SCALA_CORE}/build.sbt) + +if(BUILD_USE_BLOOP) + set(CHISEL_TARGET bloop_${TOPMODULE}) + set(CHISEL_TEST_TARGET bloop_${TOPMODULE}_test) + # Export sbt build config to bloop + if(NOT EXISTS ${SCALA_CORE}/.bloop) + execute_process( + COMMAND sbt bloopInstall + WORKING_DIRECTORY ${SCALA_CORE} + ) + endif() + string(REPLACE " " ";" CHISEL_EMIT_ARGS_LIST ${CHISEL_EMIT_ARGS}) + list(TRANSFORM CHISEL_EMIT_ARGS_LIST PREPEND "--args;") add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc/${TOPMODULE}.v - COMMAND sbt "runMain circt.stage.ChiselMain --target-dir ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc --module ${CHISEL_MODULE_CLASS} --target verilog" + OUTPUT ${CHISEL_OUTPUT_TOPMODULE} + COMMAND bloop run root ${CHISEL_EMIT_ARGS_LIST} + COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CHISEL_OUTPUT_TMP_DIR} ${CHISEL_OUTPUT_DIR} WORKING_DIRECTORY ${SCALA_CORE} - DEPENDS ${SCALA_CORE_SOURCES} + DEPENDS ${CHISEL_DEPENDENCY} + COMMAND_EXPAND_LISTS ) - - add_custom_target( - ChiselBuild_${TOPMODULE} - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc/${TOPMODULE}.v + add_test( + NAME bloop_${TOPMODULE}_test + COMMAND bloop test + WORKING_DIRECTORY ${SCALA_CORE} ) +else() + set(CHISEL_TARGET sbt_${TOPMODULE}) + set(CHISEL_TEST_TARGET sbt_${TOPMODULE}_test) + add_custom_command( + OUTPUT ${CHISEL_OUTPUT_TOPMODULE} + COMMAND sbt "run ${CHISEL_EMIT_ARGS}" + COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CHISEL_OUTPUT_TMP_DIR} ${CHISEL_OUTPUT_DIR} + WORKING_DIRECTORY ${SCALA_CORE} + DEPENDS ${CHISEL_DEPENDENCY} + VERBATIM + ) + add_test( + NAME sbt_${TOPMODULE}_test + COMMAND sbt test + WORKING_DIRECTORY ${SCALA_CORE} + ) +endif() - # -- Build NVBoard executable +if(NOT EXISTS ${CHISEL_OUTPUT_TOPMODULE}) + # Probably cold build, generate verilog at configure time to produce top module file + execute_process( + COMMAND sbt "run ${CHISEL_EMIT_ARGS}" + WORKING_DIRECTORY ${SCALA_CORE} + ) + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CHISEL_OUTPUT_TMP_DIR} ${CHISEL_OUTPUT_DIR} + ) +endif() +# -- Build NVBoard executable +if(BUILD_SIM_NVBOARD_TARGET) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/auto_bind.cpp COMMAND auto_pin_bind ${CMAKE_SOURCE_DIR}/constr/${TOPMODULE}.nxdc ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/auto_bind.cpp DEPENDS ${CMAKE_SOURCE_DIR}/constr/${TOPMODULE}.nxdc ) - unset(SOURCES) file(GLOB_RECURSE SOURCES csrc_nvboard/${TOPMODULE}/*.cpp) add_executable(V${TOPMODULE}_nvboard ${SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/auto_bind.cpp) verilate(V${TOPMODULE}_nvboard TRACE THREADS TOP_MODULE ${TOPMODULE} PREFIX V${TOPMODULE} - SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc/${TOPMODULE}.v) + SOURCES ${CHISEL_OUTPUT_TOPMODULE} + INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc) add_dependencies(V${TOPMODULE}_nvboard ChiselBuild_${TOPMODULE}) target_include_directories(V${TOPMODULE}_nvboard PRIVATE ${NVBOARD_INCLUDE_DIR} ${SDL2_INCLUDE_DIRS}) target_link_libraries(V${TOPMODULE}_nvboard PRIVATE ${NVBOARD_LIBRARY} SDL2::SDL2 SDL2_image::SDL2_image) install(TARGETS V${TOPMODULE}_nvboard) +endif() - # -- Build Verilator executable and add to test +# -- Build Verilator executable and add to test +file(GLOB_RECURSE SOURCES csrc/${TOPMODULE}/*.cpp) +add_executable(V${TOPMODULE} ${SOURCES}) - unset(SOURCES) - file(GLOB_RECURSE SOURCES csrc/${TOPMODULE}/*.cpp) - add_executable(V${TOPMODULE} ${SOURCES}) +verilate(V${TOPMODULE} TRACE COVERAGE THREADS + TOP_MODULE ${TOPMODULE} + PREFIX V${TOPMODULE} + SOURCES ${CHISEL_OUTPUT_TOPMODULE} ${CHISEL_OUTPUT_VERILATOR_CONF} + INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc + VERILATOR_ARGS + "--vpi" # Enable VPI + +) - verilate(V${TOPMODULE} TRACE COVERAGE THREADS - TOP_MODULE ${TOPMODULE} - PREFIX V${TOPMODULE} - SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc/${TOPMODULE}.v) - add_dependencies(V${TOPMODULE} ChiselBuild_${TOPMODULE}) +add_test(NAME V${TOPMODULE} COMMAND V${TOPMODULE}) - enable_testing() - add_test(NAME V${TOPMODULE} COMMAND V${TOPMODULE}) - - # -- Add build tracking +# -- Add build tracking +if(ENABLE_YSYX_GIT_TRACKER) add_custom_command( TARGET V${TOPMODULE}_nvboard PRE_BUILD COMMAND ${CMAKE_SOURCE_DIR}/../git_commit.sh "build_${CMAKE_PROJECT_NAME}_V${TOPMODULE}_nvboard" @@ -97,5 +163,4 @@ foreach(TOPMODULE IN LISTS TOPMODULES) COMMAND ${CMAKE_SOURCE_DIR}/../git_commit.sh "build_${CMAKE_PROJECT_NAME}_V${TOPMODULE}" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/.. ) - -endforeach() +endif() diff --git a/npc/core/build.sbt b/npc/core/build.sbt index e04b603..3d0f4f8 100644 --- a/npc/core/build.sbt +++ b/npc/core/build.sbt @@ -3,6 +3,7 @@ ThisBuild / version := "0.1.0" val chiselVersion = "6.2.0" +val circeVersion = "0.14.1" lazy val root = (project in file(".")) .settings( @@ -10,8 +11,13 @@ lazy val root = (project in file(".")) libraryDependencies ++= Seq( "org.chipsalliance" %% "chisel" % chiselVersion, "edu.berkeley.cs" %% "chiseltest" % "6.0.0" % "test", - "com.chuusai" %% "shapeless" % "2.3.3" - ), + "com.chuusai" %% "shapeless" % "2.3.3", + "com.github.scopt" %% "scopt" % "4.1.0", + ) ++ Seq( + "io.circe" %% "circe-core", + "io.circe" %% "circe-generic", + "io.circe" %% "circe-parser" + ).map(_ % circeVersion), scalacOptions ++= Seq( "-language:reflectiveCalls", "-deprecation", @@ -20,4 +26,4 @@ lazy val root = (project in file(".")) "-Ymacro-annotations", ), addCompilerPlugin("org.chipsalliance" % "chisel-plugin" % chiselVersion cross CrossVersion.full), - ) + ) \ No newline at end of file diff --git a/npc/core/src/main/scala/Main.scala b/npc/core/src/main/scala/FlowMain.scala similarity index 93% rename from npc/core/src/main/scala/Main.scala rename to npc/core/src/main/scala/FlowMain.scala index 1ede7e1..ae39e24 100644 --- a/npc/core/src/main/scala/Main.scala +++ b/npc/core/src/main/scala/FlowMain.scala @@ -5,16 +5,17 @@ import chisel3._ import chisel3.util.{MuxLookup, Fill, Decoupled, Counter, Queue, Reverse} import chisel3.util.{SRAM} import chisel3.util.experimental.decode.{decoder, TruthTable} -import chisel3.stage.ChiselOption import chisel3.util.log2Ceil import chisel3.util.BitPat import chisel3.util.Enum -import chisel3.experimental.prefix +import chisel3.experimental.Trace._ import shapeless.{HNil, ::} import shapeless.HList import shapeless.ops.coproduct.Prepend import chisel3.util.{ BinaryMemoryFile, HexMemoryFile } +import chisel3.experimental.Trace + object RV32Inst { private val bp = BitPat val addi = this.bp("b???????_?????_?????_000_?????_00100_11") @@ -73,7 +74,7 @@ class Control(width: Int) extends Module { }) } -import flow.components.{RegisterFile, RegFileInterface, ProgramCounter, ALU} +import flow.components.{RegisterFile, ProgramCounter, ALU} import chisel3.util.experimental.loadMemoryFromFileInline class Flow extends Module { val dataType = UInt(32.W) @@ -87,7 +88,7 @@ class Flow extends Module { memoryFile = HexMemoryFile("./resource/addi.txt") ) val control = Module(new Control(32)) - val reg = RegisterFile(32, dataType, 2, 2) + val reg = Module(new RegisterFile(dataType, 32, 2)) val pc = Module(new ProgramCounter(dataType)) val alu = Module(new ALU(dataType)) @@ -95,6 +96,9 @@ class Flow extends Module { ram.readPorts(0).address := pc.out - 0x80000000L.U val inst = ram.readPorts(0).data + Trace.traceName(reg.control.writeEnable) + dontTouch(reg.control.writeEnable) + import control.pc.SrcSelect._ pc.in.pcSrcs(pStaticNpc.litValue.toInt) := pc.out + 4.U @@ -125,5 +129,6 @@ class Flow extends Module { alu.in.a(aSrcImm.litValue.toInt) := inst(31, 20) alu.in.b := reg.out.src(1) + dontTouch(control.out) } diff --git a/npc/core/src/main/scala/Mem.scala b/npc/core/src/main/scala/Mem.scala new file mode 100644 index 0000000..2a39fce --- /dev/null +++ b/npc/core/src/main/scala/Mem.scala @@ -0,0 +1 @@ +package flow.components \ No newline at end of file diff --git a/npc/core/src/main/scala/RegisterFile.scala b/npc/core/src/main/scala/RegisterFile.scala index 509ceaa..28ec02c 100644 --- a/npc/core/src/main/scala/RegisterFile.scala +++ b/npc/core/src/main/scala/RegisterFile.scala @@ -4,6 +4,7 @@ import chisel3._ import chisel3.util.log2Ceil import chisel3.util.UIntToOH import chisel3.util.MuxLookup +import chisel3.experimental.Trace._ import shapeless.{ HNil, :: } class RegControl extends Bundle { @@ -18,69 +19,34 @@ class RegControl extends Bundle { def ctrlBindPorts: CtrlTypes = { writeEnable :: writeSelect :: HNil } + traceName(writeEnable) } -class RegFileData[T <: Data](size:Int, tpe: T, numReadPorts: Int, numWritePorts: Int) extends Bundle { - val write = new Bundle { - val addr = Input(UInt(size.W)) - val data = Vec(numWritePorts, Input(tpe)) - } - val read = Vec(numReadPorts, new Bundle { - val rs = Input(UInt(size.W)) - val src = Output(tpe) - }) -} - -class RegFileInterface[T <: Data](size: Int, tpe: T, numReadPorts: Int, numWritePorts: Int) extends Bundle { - val control = new RegControl - // val data = new RegFileData(size, tpe, numReadPorts, numWritePorts) - val in = new Bundle { - val writeAddr = Input(UInt(size.W)) - val writeData = Input(Vec(numWritePorts, tpe)) - val rs = Input(Vec(numReadPorts, UInt(size.W))) - } - val out = new Bundle { - val src = Output(Vec(numReadPorts, tpe)) - } -} - -class RegisterFileCore[T <: Data](size: Int, tpe: T, numReadPorts: Int) extends Module { +class RegisterFile[T <: Data](tpe: T, regCount: Int, numReadPorts: Int) extends Module { require(numReadPorts >= 0) - val writePort = IO(new Bundle { - val enable = Input(Bool()) - val addr = Input(UInt(log2Ceil(size).W)) - val data = Input(tpe) + val control = IO(new RegControl) + val dataAddrWidth = log2Ceil(tpe.getWidth).W + val in = IO(new Bundle { + val writeAddr = Input(UInt(dataAddrWidth)) + val writeData = Input(Vec(control.WriteSelect.all.length, tpe)) + val rs = Input(Vec(numReadPorts, UInt(dataAddrWidth))) + }) + val out = IO(new Bundle { + val src = Output(Vec(numReadPorts, tpe)) }) - val readPorts = IO(Vec(numReadPorts, new Bundle { - val addr = Input(UInt(log2Ceil(size).W)) - val data = Output(tpe) - })) - val regFile = RegInit(VecInit(Seq.fill(size)(0.U(tpe.getWidth.W)))) - val writeAddrOH = UIntToOH(writePort.addr) + val regResetValue = 0.U(tpe.getWidth.W) + val regFile = RegInit(VecInit(Seq.fill(regCount)(regResetValue))) + val writeAddrOH = UIntToOH(in.writeAddr) + for ((reg, i) <- regFile.zipWithIndex.tail) { - reg := Mux(writeAddrOH(i) && writePort.enable, writePort.data, reg) + reg := Mux(writeAddrOH(i.U(log2Ceil(regCount).W)) && control.writeEnable, in.writeData(control.writeSelect.asUInt), reg) } regFile(0) := 0.U - for (readPort <- readPorts) { - readPort.data := regFile(readPort.addr) + for (port <- 0 until numReadPorts) { + out.src(port) := regFile(in.rs(port).asUInt) } + traceName(regFile) dontTouch(regFile) } - -object RegisterFile { - def apply[T <: Data](size: Int, tpe: T, numReadPorts: Int, numWritePorts: Int): RegFileInterface[T] = { - val core = Module(new RegisterFileCore(size, tpe, numReadPorts)) - val _out = Wire(new RegFileInterface(size, tpe, numReadPorts, numWritePorts)) - val clock = core.clock - for (i <- 0 until numReadPorts) { - core.readPorts(i).addr := _out.in.rs(i) - _out.out.src(i) := core.readPorts(i).data - } - core.writePort.addr := _out.in.writeAddr - core.writePort.data := _out.in.writeData(_out.control.writeSelect.asUInt) - core.writePort.enable := _out.control.writeEnable - _out - } -} diff --git a/npc/core/src/main/scala/top/ArgParse.scala b/npc/core/src/main/scala/top/ArgParse.scala new file mode 100644 index 0000000..b430a70 --- /dev/null +++ b/npc/core/src/main/scala/top/ArgParse.scala @@ -0,0 +1,47 @@ +package flow + +import scopt.{ OParser, DefaultOEffectSetup } +import java.io.File + +case class CliOptions( + targetDir: File = new File("."), + configFile: Option[File] = None, + argsFile: Option[File] = None, + verilatorConfigFileOut: File = new File("conf.vlt"), +) { + val builder = OParser.builder[CliOptions] + val parser = { + import builder._ + OParser.sequence( + programName("flow"), + help("help"), + opt[Option[File]]('c', "config") + .action((x, c) => c.copy(configFile = x)) + .text("JSON Configuration file for generation"), + opt[Option[File]]("args-file") + .action((x, c) => c.copy(argsFile = x)) + .text("Passing file content as args when emit"), + opt[File]('o', "target-dir") + .action((x, c) => c.copy(targetDir = x)) + .text("Output files relative to this path"), + opt[File]("out-verilator-conf") + .action((x, c) => c.copy(verilatorConfigFileOut = x)) + .text("Options needed when simulating with verilator") + ) + } + + def parse(args: Array[String]): CliOptions = { + OParser.runParser(parser, args, CliOptions()) match { + case (result, effects) => + OParser.runEffects(effects, new DefaultOEffectSetup { + // ignore terminate + override def terminate(exitState: Either[String, Unit]): Unit = () + }) + + result match { + case Some(cliOptions: CliOptions) => { return cliOptions } + case _ => { throw new IllegalArgumentException("Wrong command line argument") } + } + } + } +} diff --git a/npc/core/src/main/scala/top/Config.scala b/npc/core/src/main/scala/top/Config.scala new file mode 100644 index 0000000..aa58107 --- /dev/null +++ b/npc/core/src/main/scala/top/Config.scala @@ -0,0 +1,16 @@ +package flow + +import io.circe.generic.JsonCodec + +// Which group of signals to trace +@JsonCodec case class TraceConfig ( + enable: Boolean = false, + registers: Array[Int] = Array(), + mem: Array[(Int, Int)] = Array(), +) + +@JsonCodec case class Config( + // Whether to enable Difftest + enableDifftest: Boolean = true, + traceConfig: TraceConfig = TraceConfig(), +) diff --git a/npc/core/src/main/scala/top/Main.scala b/npc/core/src/main/scala/top/Main.scala new file mode 100644 index 0000000..3c02ff3 --- /dev/null +++ b/npc/core/src/main/scala/top/Main.scala @@ -0,0 +1,72 @@ +package flow + +import flow._ + +import chisel3._ +import chisel3.experimental.Trace._ +import chisel3.stage.{ChiselGeneratorAnnotation, DesignAnnotation} +import chisel3.util.experimental.InlineInstance +import circt.stage.ChiselStage +import firrtl.AnnotationSeq +import firrtl.annotations.TargetToken.{Instance, OfModule, Ref} +import java.io.PrintWriter +import scala.io.Source +import java.io.File + + +// TODO: Generate verilator config file + +object VerilogMain extends App { + val opt = CliOptions().parse(args) + val topName = "Flow" + + val config: Config = opt.configFile match { + case Some(f) => { + val source = Source.fromFile(f) + val jsonString = source.mkString + source.close() + io.circe.parser.decode[Config](jsonString) match { + case Right(x) => x + case Left(e) => throw e + } + } + case None => Config(traceConfig = TraceConfig(enable = true)) + } + + val annos = (new ChiselStage).execute( + Array("--target-dir", opt.targetDir.toString, "--target", "systemverilog", "--split-verilog"), + Seq( + + ) ++ (if(config.traceConfig.enable) Seq(ChiselGeneratorAnnotation(() => new Flow)) else Seq()) + ) + + if(config.traceConfig.enable) { + val dut = annos.collectFirst { case DesignAnnotation(dut) => dut }.get.asInstanceOf[Flow] + + val verilatorConfigSeq = finalTargetMap(annos) + .values + .flatten + .map(ct => + s"""public_flat_rd -module "${ + ct.tokens.collectFirst { case OfModule(m) => m }.get + }" -var "${ct.tokens.collectFirst { case Ref(r) => r }.get}"""") + finalTargetMap(annos) + .values + .flatten + .foreach( + ct => println(s"""TOP.${ct.circuit}.${ct.path.map { case (Instance(i), _) => i }.mkString(".")}.${ct.tokens.collectFirst { + case Ref(r) => r + }.get}""") + ) + + val verilatorConfigWriter = new PrintWriter(new File(opt.targetDir, opt.verilatorConfigFileOut.toString())) + verilatorConfigWriter.write("`verilator_config\n") + try { + for(ct <- verilatorConfigSeq) { + verilatorConfigWriter.println(ct) + } + } finally { + verilatorConfigWriter.close() + } + } +} \ No newline at end of file diff --git a/npc/core/src/main/scala/utils/DPI.scala b/npc/core/src/main/scala/utils/DPI.scala new file mode 100644 index 0000000..2c83be5 --- /dev/null +++ b/npc/core/src/main/scala/utils/DPI.scala @@ -0,0 +1,11 @@ +package flow.utils + +import chisel3._ +import chisel3.util.HasBlackBoxResource + +// class DiffTester extends BlackBox with HasBlackBoxResource { +// val io = IO(new Bundle { +// val regs = +// }) +// addResource("difftest.v"); +// } diff --git a/npc/csrc/Flow/main.cpp b/npc/csrc/Flow/main.cpp index c708610..465e1f0 100644 --- a/npc/csrc/Flow/main.cpp +++ b/npc/csrc/Flow/main.cpp @@ -1,43 +1,86 @@ +#include +#include #include -#include -#include +#include +#include #include #include -#include +#include +#include #define MAX_SIM_TIME 100 #define VERILATOR_TRACE -int main(int argc, char **argv, char **env) { - int sim_time = 0; - Verilated::commandArgs(argc, argv); +std::vector regsHandle; +int regs[32]; - VFlow *top = new VFlow; - - Verilated::traceEverOn(true); - VerilatedVcdC *m_trace = new VerilatedVcdC; -#ifdef VERILATOR_TRACE - top->trace(m_trace, 5); - m_trace->open("waveform.vcd"); -#endif - for (sim_time = 0; sim_time < 10; sim_time++) { - top->eval(); - top->clock = !top->clock; - top->reset = 1; -#ifdef VERILATOR_TRACE - m_trace->dump(sim_time); -#endif - } - top->reset = 0; - for (sim_time = 10; sim_time < MAX_SIM_TIME; sim_time++) { - top->eval(); - top->clock = !top->clock; -#ifdef VERILATOR_TRACE - m_trace->dump(sim_time); -#endif - } -#ifdef VERILATOR_TRACE - m_trace->close(); -#endif - delete top; - exit(EXIT_SUCCESS); +static void init_vpi_regs() { + std::string regfile = "TOP.Flow.reg_0.regFile_"; + for(int i = 0; i < 32; i++) { + std::string regname = regfile + std::to_string(i); + vpiHandle vh = vpi_handle_by_name((PLI_BYTE8 *)regname.c_str(), NULL); + regsHandle.push_back(vh); + } +} + +static void init_vpi() { + init_vpi_regs(); +} + +static int vpi_get_int(vpiHandle vh) { + s_vpi_value v; + v.format = vpiIntVal; + vpi_get_value(vh, &v); + return v.value.integer; +} + +static void update_regs() { + for(int i = 0; i < 32; i++) { + regs[i] = vpi_get_int(regsHandle[i]); + } +} + +static void print_regs() { + for(int i = 0; i < 32; i++) { + printf("%d: %d\t", i, regs[i]); + if(i % 8 == 7) putchar('\n'); + } + putchar('\n'); +} + +static int sim_time = 0; + +int main(int argc, char **argv, char **env) { + int sim_time = 0; + int posedge_cnt = 0; + Verilated::commandArgs(argc, argv); + + std::unique_ptr top{new VFlow}; + Verilated::traceEverOn(true); + VerilatedVcdC *m_trace = new VerilatedVcdC; +#ifdef VERILATOR_TRACE + top->trace(m_trace, 5); + m_trace->open("waveform.vcd"); +#endif + + init_vpi(); + + top->reset = 0; + for (sim_time = 10; sim_time < MAX_SIM_TIME; sim_time++) { + top->eval(); + top->clock = !top->clock; + if(top->clock == 1) { + // Posedge + ++posedge_cnt; + update_regs(); + print_regs(); + } + +#ifdef VERILATOR_TRACE + m_trace->dump(sim_time); +#endif + } +#ifdef VERILATOR_TRACE + m_trace->close(); +#endif + exit(EXIT_SUCCESS); } diff --git a/npc/flake.nix b/npc/flake.nix index 15b910f..00a98ba 100644 --- a/npc/flake.nix +++ b/npc/flake.nix @@ -20,9 +20,10 @@ CHISEL_FIRTOOL_PATH = "${nixpkgs-circt162.legacyPackages.${system}.circt}/bin"; packages = [ clang-tools - # rnix-lsp + cmake coursier espresso + bloop gdb jre