From e52d52ae991b5b6cd6f009e80cb0ce9eeeb25ddb Mon Sep 17 00:00:00 2001 From: Schuyler Eldridge Date: Mon, 15 Jan 2018 14:21:09 -0500 Subject: [PATCH] Link PlusArg to emulator command line options - adds a mutable singleton (PlusArgArtefacts) to store information about Rocket PlusArgs - adds methods to PlusArgArtefacts to emit C snippets that are consumed by emulator.cc for correct argument parsing and help text generation - emits snippets in $(CONFIG).plusArgs via BaseCoreplex-set ElaborationArtefacts - modify emulator/Makefrag-verilator to include $(CONFIG).plusArgs - cleanup help text (docstring) for existing PlusArgs Signed-off-by: Schuyler Eldridge --- csrc/emulator.cc | 44 ++++++++++++---------- emulator/Makefrag-verilator | 2 +- src/main/scala/coreplex/BaseCoreplex.scala | 1 + src/main/scala/rocket/RocketCore.scala | 6 +-- src/main/scala/tilelink/Monitor.scala | 3 +- src/main/scala/util/PlusArg.scala | 40 +++++++++++++++++++- 6 files changed, 71 insertions(+), 25 deletions(-) diff --git a/csrc/emulator.cc b/csrc/emulator.cc index bbba3c61..ecbf6a21 100644 --- a/csrc/emulator.cc +++ b/csrc/emulator.cc @@ -15,12 +15,20 @@ #include #include -//TODO: GENERATE THESE AUTOMATICALLY! -static const char * verilog_plusargs [] = { "max-core-cycles", - "jtag_rbb_enable", - "tilelink_timeout", - 0}; - +// For option parsing, which is split across this file, Verilog, and +// FESVR's HTIF, a few external files must be pulled in. The list of +// files and what they provide is enumerated: +// +// $RISCV/include/fesvr/htif.h: +// defines: +// - HTIF_USAGE_OPTIONS +// - HTIF_LONG_OPTIONS_OPTIND +// - HTIF_LONG_OPTIONS +// $(ROCKETCHIP_DIR)/generated-src(-debug)?/$(CONFIG).plusArgs: +// defines: +// - PLUSARG_USAGE_OPTIONS +// variables: +// - static const char * verilog_plusargs extern dtm_t* dtm; extern remote_bitbang_t * jtag; @@ -66,7 +74,7 @@ EMULATOR OPTIONS\n\ #if VM_TRACE == 0 fputs("\ \n\ -EMULATOR OPTIONS (only supported in debug build -- try `make debug`)\n", +EMULATOR DEBUG OPTIONS (only supported in debug build -- try `make debug`)\n", stdout); #endif fputs("\ @@ -74,14 +82,7 @@ EMULATOR OPTIONS (only supported in debug build -- try `make debug`)\n", -x, --dump-start=CYCLE Start VCD tracing at CYCLE\n\ +dump-start\n\ ", stdout); - fputs("\ -\n\ -VERILOG PLUSARGS (accepted by the Verilog itself):\n" , stdout); - const char ** vpa = &verilog_plusargs[0]; - while (*vpa) { - fprintf(stdout, " +%s=...\n", *vpa); - vpa ++; - } + fputs("\n" PLUSARG_USAGE_OPTIONS, stdout); fputs("\n" HTIF_USAGE_OPTIONS, stdout); printf("\n" "EXAMPLES\n" @@ -95,7 +96,11 @@ VERILOG PLUSARGS (accepted by the Verilog itself):\n" , stdout); #endif " - run an ELF (you wrote, called 'hello') using the proxy kernel:\n" " %s pk hello\n", - program_name, program_name, program_name, program_name); + program_name, program_name, program_name +#if VM_TRACE + , program_name +#endif + ); } int main(int argc, char** argv) @@ -110,7 +115,7 @@ int main(int argc, char** argv) #endif char ** htif_argv = NULL; int verilog_plusargs_legal = 1; - + while (1) { static struct option long_options[] = { {"cycle-count", no_argument, 0, 'c' }, @@ -174,7 +179,7 @@ int main(int argc, char** argv) else if (arg.substr(0, 12) == "+cycle-count") c = 'c'; // If we don't find a legacy '+' EMULATOR argument, it still could be - // a VERILOG_PLUSARG and not an error. + // a VERILOG_PLUSARG and not an error. else if (verilog_plusargs_legal) { const char ** plusarg = &verilog_plusargs[0]; int legal_verilog_plusarg = 0; @@ -204,7 +209,8 @@ int main(int argc, char** argv) } htif_option++; } - std::cerr << argv[0] << ": invalid HTIF legacy plus-arg \"" << arg << "\"\n"; + std::cerr << argv[0] << ": invalid plus-arg (Verilog or HTIF) \"" + << arg << "\"\n"; c = '?'; } goto retry; diff --git a/emulator/Makefrag-verilator b/emulator/Makefrag-verilator index a83426ba..0310b702 100644 --- a/emulator/Makefrag-verilator +++ b/emulator/Makefrag-verilator @@ -60,7 +60,7 @@ VERILATOR_FLAGS := --top-module $(MODEL) \ --output-split-cfuncs 20000 \ -Wno-STMTDLY --x-assign unique \ -I$(base_dir)/vsrc \ - -O3 -CFLAGS "$(CXXFLAGS) -DVERILATOR -DTEST_HARNESS=V$(MODEL) -include $(base_dir)/csrc/verilator.h" + -O3 -CFLAGS "$(CXXFLAGS) -DVERILATOR -DTEST_HARNESS=V$(MODEL) -include $(base_dir)/csrc/verilator.h -include $(generated_dir)/$(CONFIG).plusArgs" cppfiles = $(addprefix $(base_dir)/csrc/, $(addsuffix .cc, $(CXXSRCS))) headers = $(wildcard $(base_dir)/csrc/*.h) diff --git a/src/main/scala/coreplex/BaseCoreplex.scala b/src/main/scala/coreplex/BaseCoreplex.scala index be23ee83..41af61ec 100644 --- a/src/main/scala/coreplex/BaseCoreplex.scala +++ b/src/main/scala/coreplex/BaseCoreplex.scala @@ -21,6 +21,7 @@ abstract class BareCoreplexModule[+L <: BareCoreplex](_outer: L) extends LazyMod ElaborationArtefacts.add("graphml", outer.graphML) ElaborationArtefacts.add("dts", outer.dts) ElaborationArtefacts.add("json", outer.json) + ElaborationArtefacts.add("plusArgs", PlusArgArtefacts.serialize) println(outer.dts) } diff --git a/src/main/scala/rocket/RocketCore.scala b/src/main/scala/rocket/RocketCore.scala index efc86b9c..a9d6868a 100644 --- a/src/main/scala/rocket/RocketCore.scala +++ b/src/main/scala/rocket/RocketCore.scala @@ -286,7 +286,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) alu.io.fn := ex_ctrl.alu_fn alu.io.in2 := ex_op2.asUInt alu.io.in1 := ex_op1.asUInt - + // multiplier and divider val div = Module(new MulDiv(mulDivParams, width = xLen)) div.io.req.valid := ex_reg_valid && ex_ctrl.div @@ -525,7 +525,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) val wb_valid = wb_reg_valid && !replay_wb && !wb_xcpt val wb_wen = wb_valid && wb_ctrl.wxd - val rf_wen = wb_wen || ll_wen + val rf_wen = wb_wen || ll_wen val rf_waddr = Mux(ll_wen, ll_waddr, wb_waddr) val rf_wdata = Mux(dmem_resp_valid && dmem_resp_xpu, io.dmem.resp.bits.data, Mux(ll_wen, ll_wdata, @@ -724,7 +724,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) val max_core_cycles = PlusArg("max-core-cycles", default = 0, - docstring = "Maximum Core Clock cycles simulation may run before timeout. Ignored if 0 (Default).") + docstring = "Kill the emulation after INT rdtime cycles. Off if 0.") when (max_core_cycles > UInt(0)) { assert (csr.io.time < max_core_cycles, "Maximum Core Cycles reached.") } diff --git a/src/main/scala/tilelink/Monitor.scala b/src/main/scala/tilelink/Monitor.scala index d15c5bbe..6a795e69 100644 --- a/src/main/scala/tilelink/Monitor.scala +++ b/src/main/scala/tilelink/Monitor.scala @@ -442,7 +442,8 @@ class TLMonitor(args: TLMonitorArgs) extends TLMonitorBase(args) inflight := (inflight | a_set) & ~d_clr val watchdog = RegInit(UInt(0, width = 32)) - val limit = PlusArg("tilelink_timeout") + val limit = PlusArg("tilelink_timeout", + docstring="Kill emulation after INT waiting TileLink cycles. Off if 0.") assert (!inflight.orR || limit === UInt(0) || watchdog < limit, "TileLink timeout expired" + extra) watchdog := watchdog + UInt(1) diff --git a/src/main/scala/util/PlusArg.scala b/src/main/scala/util/PlusArg.scala index e9c9373b..97e8a0f5 100644 --- a/src/main/scala/util/PlusArg.scala +++ b/src/main/scala/util/PlusArg.scala @@ -4,6 +4,8 @@ package freechips.rocketchip.util import Chisel._ +case class PlusArgInfo(default: Int, docstring: String) + class plusarg_reader(val format: String, val default: Int, val docstring: String) extends BlackBox(Map( "FORMAT" -> chisel3.core.StringParam(format), "DEFAULT" -> chisel3.core.IntParam(default))) { @@ -20,6 +22,42 @@ object PlusArg // Add a docstring to document the arg, which can be dumped in an elaboration // pass. - def apply(name: String, default: Int = 0, docstring: String = ""): UInt = + def apply(name: String, default: Int = 0, docstring: String = ""): UInt = { + PlusArgArtefacts.append(name, default, docstring) Module(new plusarg_reader(name + "=%d", default, docstring)).io.out + } +} + +object PlusArgArtefacts { + private var artefacts: Map[String, PlusArgInfo] = Map.empty + + /* Add a new PlusArg */ + def append(name: String, default: Int, docstring: String): Unit = + artefacts = artefacts ++ Map(name -> PlusArgInfo(default, docstring)) + + /* From plus args, generate help text */ + private def serializeHelp(tab: String = ""): String = artefacts + .map{ case(arg, PlusArgInfo(default, docstring)) => + s"""|$tab+$arg=INT\\n\\ + |$tab${" "*20}$docstring\\n\\ + |$tab${" "*22}(default=$default)""".stripMargin }.toSeq + .mkString("\\n\\\n") ++ "\"" + + /* From plus args, generate a char array of their names */ + private def serializeArray(tab: String = ""): String = { + val prettyTab = tab + " " * 44 // Length of 'static const ...' + s"${tab}static const char * verilog_plusargs [] = {\\\n" ++ + artefacts + .map{ case(arg, _) => s"""$prettyTab"$arg",\\\n""" } + .mkString("")++ + s"${prettyTab}0};" + } + + /* Generate C code to be included in emulator.cc that helps with + * argument parsing based on available Verilog PlusArgs */ + def serialize(): String = + s"""|#define PLUSARG_USAGE_OPTIONS \"EMULATOR VERILOG PLUSARGS\\n\\ + |${serializeHelp(" "*7)} + |${serializeArray()} + |""".stripMargin }