From ddf3159d615b1898943046d58953e0bd68371cba Mon Sep 17 00:00:00 2001 From: Paul Rigge Date: Wed, 6 Mar 2019 18:22:21 -0800 Subject: [PATCH] Bump rocket, make possible to use published deps (#47) * Use published rocketchip * Simulator works! * Gitignore was masking csrc * Fix broken submodules * Update gitignore * Fix things up * Some more cleanup * Clean up so that using maven works * Incorporate feedback * Oops * Add workaround for some of csrc * Forgot dtm and jtag * Make name better and add comment * Extraneous comment * Fix includes. After running a clean build, I realized old build state was masking this problem. verisim/csrc needs to be in the include path until we find a more permanent solution to our problem. * Add target to generate verilator-specific files. * Ignore DS_Store * Generate bootrom from testchipip * Oops * Add extraneous rocket-dsptools reference --- .gitignore | 8 +- Makefrag | 32 +- build.sbt | 23 +- project/build.properties | 2 +- rocket-chip | 2 +- .../project-template/csrc/emulator.cc | 356 ++++++++++++++++++ src/main/scala/example/Configs.scala | 2 +- src/main/scala/example/TestHarness.scala | 16 + src/main/scala/example/Top.scala | 9 +- src/main/scala/example/Verilator.scala | 92 +++++ testchipip | 2 +- verisim/Makefile | 31 +- verisim/Makefrag-verilator | 4 +- verisim/csrc/verilator-harness.cc | 167 -------- 14 files changed, 531 insertions(+), 215 deletions(-) create mode 100644 src/main/resources/project-template/csrc/emulator.cc create mode 100644 src/main/scala/example/Verilator.scala delete mode 100644 verisim/csrc/verilator-harness.cc diff --git a/.gitignore b/.gitignore index fb11174b..f0fb9a39 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,12 @@ +bootrom /Makefrag.pkgs target *.jar *.stamp /vsim -/verisim +/verisim/generated-src* +/verisim/simulator-* +/verisim/verilator +simv* +*.vcd +.DS_Store diff --git a/Makefrag b/Makefrag index 02c21b06..8ef6ae2e 100644 --- a/Makefrag +++ b/Makefrag @@ -1,4 +1,5 @@ ROCKETCHIP_DIR=$(base_dir)/rocket-chip +TESTCHIP_DIR = $(base_dir)/testchipip SCALA_VERSION=2.12.4 SCALA_VERSION_MAJOR=$(basename $(SCALA_VERSION)) @@ -11,8 +12,8 @@ PACKAGES=rocket-chip testchipip SCALA_SOURCES=$(foreach pkg,$(PACKAGES),$(call lookup_scala_srcs,$(base_dir)/$(pkg)/src/main/scala)) $(call lookup_scala_srcs,$(base_dir)/src/main/scala) ROCKET_CLASSES ?= "$(ROCKETCHIP_DIR)/target/scala-$(SCALA_VERSION_MAJOR)/classes:$(ROCKETCHIP_DIR)/chisel3/target/scala-$(SCALA_VERSION_MAJOR)/*" +TESTCHIPIP_CLASSES ?= "$(TESTCHIP_DIR)/target/scala-$(SCALA_VERSION_MAJOR)/classes" FIRRTL_JAR ?= $(ROCKETCHIP_DIR)/lib/firrtl.jar -FIRRTL ?= java -Xmx2G -Xss8M -XX:MaxPermSize=256M -cp $(ROCKET_CLASSES):$(FIRRTL_JAR) firrtl.Driver $(FIRRTL_JAR): $(call lookup_scala_srcs, $(ROCKETCHIP_DIR)/firrtl/src/main/scala) $(MAKE) -C $(ROCKETCHIP_DIR)/firrtl SBT="$(SBT)" root_dir=$(ROCKETCHIP_DIR)/firrtl build-scala @@ -21,9 +22,6 @@ $(FIRRTL_JAR): $(call lookup_scala_srcs, $(ROCKETCHIP_DIR)/firrtl/src/main/scala touch $@ build_dir=$(sim_dir)/generated-src -testchip_dir = $(base_dir)/testchipip - -include $(testchip_dir)/Makefrag CHISEL_ARGS ?= @@ -35,35 +33,39 @@ VERILOG_FILE ?=$(build_dir)/$(long_name).top.v HARNESS_FILE ?=$(build_dir)/$(long_name).harness.v SMEMS_FILE ?=$(build_dir)/$(long_name).mems.v SMEMS_CONF ?=$(build_dir)/$(long_name).mems.conf +verilator_dotf ?= $(build_dir)/verilator_files.f REPL_SEQ_MEM = --repl-seq-mem -c:$(MODEL):-o:$(SMEMS_CONF) # This should match whatever the commonSettings version is in build.sbt BARSTOOLS_VER=1.0 -TAPEOUT_JAR=$(base_dir)/barstools/tapeout/target/scala-$(SCALA_VERSION_MAJOR)/tapeout_$(SCALA_VERSION_MAJOR)-$(BARSTOOLS_VER).jar +TAPEOUT_JAR=$(base_dir)/barstools/tapeout/target/scala-$(SCALA_VERSION_MAJOR)/tapeout-assembly-$(BARSTOOLS_VER).jar MACROCOMPILER_JAR=$(base_dir)/barstools/macros/target/scala-$(SCALA_VERSION_MAJOR)/barstools-macros-assembly-$(BARSTOOLS_VER).jar -TAPEOUT ?= java -Xmx8G -Xss8M -cp $(ROCKET_CLASSES):$(FIRRTL_JAR):$(TAPEOUT_JAR) -MACROCOMPILER ?= java -Xmx8G -Xss8M -cp $(ROCKET_CLASSES):$(FIRRTL_JAR):$(MACROCOMPILER_JAR) +TAPEOUT ?= java -Xmx8G -Xss8M -cp $(ROCKET_CLASSES):$(TESTCHIPIP_CLASSES):$(TAPEOUT_JAR) +MACROCOMPILER ?= java -Xmx8G -Xss8M -cp $(ROCKET_CLASSES):$(TESTCHIPIP_CLASSES):$(MACROCOMPILER_JAR) -$(TAPEOUT_JAR): $(call lookup_scala_srcs, $(base_dir)/barstools/tapeout/src/main/scala) $(FIRRTL_JAR) - cd $(base_dir) && $(SBT) "tapeout/package" +$(TAPEOUT_JAR): $(call lookup_scala_srcs, $(base_dir)/barstools/tapeout/src/main/scala) + cd $(base_dir) && $(SBT) "tapeout/assembly" -$(MACROCOMPILER_JAR): $(call lookup_scala_srcs, $(base_dir)/barstools/macros/src/main/scala) $(call lookup_scala_srcs, $(base_dir)/barstools/mdf/scalalib/src/main/scala) $(FIRRTL_JAR) +$(MACROCOMPILER_JAR): $(call lookup_scala_srcs, $(base_dir)/barstools/macros/src/main/scala) $(call lookup_scala_srcs, $(base_dir)/barstools/mdf/scalalib/src/main/scala) cd $(base_dir) && $(SBT) "barstools-macros/assembly" .PHONY: jars jars: $(MACROCOMPILER_JAR) $(TAPEOUT_JAR) -$(FIRRTL_FILE) $(ANNO_FILE): $(SCALA_SOURCES) $(bootrom_img) $(FIRRTL_JAR) +$(verilator_dotf): $(SCALA_SOURCES) + cd $(base_dir) && $(SBT) "runMain example.GenerateSimFiles -td $(build_dir)" + +$(FIRRTL_FILE) $(ANNO_FILE): $(SCALA_SOURCES) $(verilator_dotf) mkdir -p $(build_dir) cd $(base_dir) && $(SBT) "runMain $(PROJECT).Generator $(CHISEL_ARGS) $(build_dir) $(PROJECT) $(MODEL) $(CFG_PROJECT) $(CONFIG)" $(VERILOG_FILE) $(SMEMS_CONF): $(FIRRTL_FILE) $(ANNO_FILE) $(TAPEOUT_JAR) - $(TAPEOUT) barstools.tapeout.transforms.GenerateTop -o $(VERILOG_FILE) -i $(FIRRTL_FILE) --syn-top $(TOP) --harness-top $(MODEL) -faf $(ANNO_FILE) $(REPL_SEQ_MEM) + $(TAPEOUT) barstools.tapeout.transforms.GenerateTop -o $(VERILOG_FILE) -i $(FIRRTL_FILE) --syn-top $(TOP) --harness-top $(MODEL) -faf $(ANNO_FILE) $(REPL_SEQ_MEM) -td $(build_dir) $(HARNESS_FILE): $(FIRRTL_FILE) $(ANNO_FILE) $(TAPEOUT_JAR) - $(TAPEOUT) barstools.tapeout.transforms.GenerateHarness -o $(HARNESS_FILE) -i $(FIRRTL_FILE) --syn-top $(TOP) --harness-top $(MODEL) -faf $(ANNO_FILE) + $(TAPEOUT) barstools.tapeout.transforms.GenerateHarness -o $(HARNESS_FILE) -i $(FIRRTL_FILE) --syn-top $(TOP) --harness-top $(MODEL) -faf $(ANNO_FILE) -td $(build_dir) # This file is for simulation only. VLSI flows should replace this file with one containing hard SRAMs $(SMEMS_FILE): $(SMEMS_CONF) $(MACROCOMPILER_JAR) @@ -102,3 +104,7 @@ $(output_dir)/%: $(RISCV)/riscv64-unknown-elf/share/riscv-tests/isa/% mkdir -p $(output_dir) ln -sf $< $@ +.PHONY: clean-scala +clean-scala: + rm -rf $(MACROCOMPILER_JAR) $(TAPEOUT_JAR) + diff --git a/build.sbt b/build.sbt index 5f88c22d..553ca61b 100644 --- a/build.sbt +++ b/build.sbt @@ -12,6 +12,7 @@ lazy val commonSettings = Seq( libraryDependencies += "org.json4s" %% "json4s-native" % "3.5.3", libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value, libraryDependencies += "edu.berkeley.cs" %% "firrtl-interpreter" % "1.2-SNAPSHOT", + libraryDependencies += "com.github.scopt" %% "scopt" % "3.7.1", addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full), resolvers ++= Seq( Resolver.sonatypeRepo("snapshots"), @@ -23,18 +24,28 @@ lazy val rocketchip = RootProject(file("rocket-chip")) lazy val testchipip = project.settings(commonSettings) .dependsOn(rocketchip) -lazy val example = (project in file(".")) +// Checks for -DROCKET_USE_MAVEN. +// If it's there, use a maven dependency. +// Else, depend on subprojects in git submodules. +def conditionalDependsOn(prj: Project): Project = { + if (sys.props.contains("ROCKET_USE_MAVEN")) { + prj.settings(Seq( + libraryDependencies += "edu.berkeley.cs" %% "testchipip" % "1.0-020719-SNAPSHOT", + )) + } else { + prj.dependsOn(testchipip) + } +} +lazy val example = conditionalDependsOn(project in file(".")) .settings(commonSettings) - .dependsOn(testchipip) -lazy val tapeout = (project in file("./barstools/tapeout/")) +lazy val tapeout = conditionalDependsOn(project in file("./barstools/tapeout/")) .settings(commonSettings) - .dependsOn(rocketchip) lazy val mdf = (project in file("./barstools/mdf/scalalib/")) -lazy val `barstools-macros` = (project in file("./barstools/macros/")) +lazy val `barstools-macros` = conditionalDependsOn(project in file("./barstools/macros/")) .enablePlugins(sbtassembly.AssemblyPlugin) .settings(commonSettings) - .dependsOn(rocketchip, mdf) + .dependsOn(mdf) diff --git a/project/build.properties b/project/build.properties index 72f90289..c0bab049 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.2.7 +sbt.version=1.2.8 diff --git a/rocket-chip b/rocket-chip index 50bb13d7..a05728c4 160000 --- a/rocket-chip +++ b/rocket-chip @@ -1 +1 @@ -Subproject commit 50bb13d7887e5f9ca192431234b057ae9d8edb6c +Subproject commit a05728c4fab84a13585e14ac684b47c875b17b57 diff --git a/src/main/resources/project-template/csrc/emulator.cc b/src/main/resources/project-template/csrc/emulator.cc new file mode 100644 index 00000000..1a4f4dd2 --- /dev/null +++ b/src/main/resources/project-template/csrc/emulator.cc @@ -0,0 +1,356 @@ +// See LICENSE.SiFive for license details. +// See LICENSE.Berkeley for license details. + +#include "verilated.h" +#if VM_TRACE +#include +#include "verilated_vcd_c.h" +#endif +#include +#include +#include "remote_bitbang.h" +#include +#include +#include +#include +#include +#include +#include + +// 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 tsi_t* tsi; +extern dtm_t* dtm; +extern remote_bitbang_t * jtag; + +static uint64_t trace_count = 0; +bool verbose; +bool done_reset; + +void handle_sigterm(int sig) +{ + dtm->stop(); +} + +double sc_time_stamp() +{ + return trace_count; +} + +extern "C" int vpi_get_vlog_info(void* arg) +{ + return 0; +} + +static void usage(const char * program_name) +{ + printf("Usage: %s [EMULATOR OPTION]... [VERILOG PLUSARG]... [HOST OPTION]... BINARY [TARGET OPTION]...\n", + program_name); + fputs("\ +Run a BINARY on the Rocket Chip emulator.\n\ +\n\ +Mandatory arguments to long options are mandatory for short options too.\n\ +\n\ +EMULATOR OPTIONS\n\ + -c, --cycle-count Print the cycle count before exiting\n\ + +cycle-count\n\ + -h, --help Display this help and exit\n\ + -m, --max-cycles=CYCLES Kill the emulation after CYCLES\n\ + +max-cycles=CYCLES\n\ + -s, --seed=SEED Use random number seed SEED\n\ + -r, --rbb-port=PORT Use PORT for remote bit bang (with OpenOCD and GDB) \n\ + If not specified, a random port will be chosen\n\ + automatically.\n\ + -V, --verbose Enable all Chisel printfs (cycle-by-cycle info)\n\ + +verbose\n\ +", stdout); +#if VM_TRACE == 0 + fputs("\ +\n\ +EMULATOR DEBUG OPTIONS (only supported in debug build -- try `make debug`)\n", + stdout); +#endif + fputs("\ + -v, --vcd=FILE, Write vcd trace to FILE (or '-' for stdout)\n\ + -x, --dump-start=CYCLE Start VCD tracing at CYCLE\n\ + +dump-start\n\ +", stdout); + fputs("\n" PLUSARG_USAGE_OPTIONS, stdout); + fputs("\n" HTIF_USAGE_OPTIONS, stdout); + printf("\n" +"EXAMPLES\n" +" - run a bare metal test:\n" +" %s $RISCV/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-add\n" +" - run a bare metal test showing cycle-by-cycle information:\n" +" %s +verbose $RISCV/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-add 2>&1 | spike-dasm\n" +#if VM_TRACE +" - run a bare metal test to generate a VCD waveform:\n" +" %s -v rv64ui-p-add.vcd $RISCV/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-add\n" +#endif +" - run an ELF (you wrote, called 'hello') using the proxy kernel:\n" +" %s pk hello\n", + program_name, program_name, program_name +#if VM_TRACE + , program_name +#endif + ); +} + +int main(int argc, char** argv) +{ + unsigned random_seed = (unsigned)time(NULL) ^ (unsigned)getpid(); + uint64_t max_cycles = -1; + int ret = 0; + bool print_cycles = false; + // Port numbers are 16 bit unsigned integers. + uint16_t rbb_port = 0; +#if VM_TRACE + FILE * vcdfile = NULL; + uint64_t start = 0; +#endif + char ** htif_argv = NULL; + int verilog_plusargs_legal = 1; + + while (1) { + static struct option long_options[] = { + {"cycle-count", no_argument, 0, 'c' }, + {"help", no_argument, 0, 'h' }, + {"max-cycles", required_argument, 0, 'm' }, + {"seed", required_argument, 0, 's' }, + {"rbb-port", required_argument, 0, 'r' }, + {"verbose", no_argument, 0, 'V' }, +#if VM_TRACE + {"vcd", required_argument, 0, 'v' }, + {"dump-start", required_argument, 0, 'x' }, +#endif + HTIF_LONG_OPTIONS + }; + int option_index = 0; +#if VM_TRACE + int c = getopt_long(argc, argv, "-chm:s:r:v:Vx:", long_options, &option_index); +#else + int c = getopt_long(argc, argv, "-chm:s:r:V", long_options, &option_index); +#endif + if (c == -1) break; + retry: + switch (c) { + // Process long and short EMULATOR options + case '?': usage(argv[0]); return 1; + case 'c': print_cycles = true; break; + case 'h': usage(argv[0]); return 0; + case 'm': max_cycles = atoll(optarg); break; + case 's': random_seed = atoi(optarg); break; + case 'r': rbb_port = atoi(optarg); break; + case 'V': verbose = true; break; +#if VM_TRACE + case 'v': { + vcdfile = strcmp(optarg, "-") == 0 ? stdout : fopen(optarg, "w"); + if (!vcdfile) { + std::cerr << "Unable to open " << optarg << " for VCD write\n"; + return 1; + } + break; + } + case 'x': start = atoll(optarg); break; +#endif + // Process legacy '+' EMULATOR arguments by replacing them with + // their getopt equivalents + case 1: { + std::string arg = optarg; + if (arg.substr(0, 1) != "+") { + optind--; + goto done_processing; + } + if (arg == "+verbose") + c = 'V'; + else if (arg.substr(0, 12) == "+max-cycles=") { + c = 'm'; + optarg = optarg+12; + } +#if VM_TRACE + else if (arg.substr(0, 12) == "+dump-start=") { + c = 'x'; + optarg = optarg+12; + } +#endif + 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. + else if (verilog_plusargs_legal) { + const char ** plusarg = &verilog_plusargs[0]; + int legal_verilog_plusarg = 0; + while (*plusarg && (legal_verilog_plusarg == 0)){ + if (arg.substr(1, strlen(*plusarg)) == *plusarg) { + legal_verilog_plusarg = 1; + } + plusarg ++; + } + if (!legal_verilog_plusarg) { + verilog_plusargs_legal = 0; + } else { + c = 'P'; + } + goto retry; + } + // If we STILL don't find a legacy '+' argument, it still could be + // an HTIF (HOST) argument and not an error. If this is the case, then + // we're done processing EMULATOR and VERILOG arguments. + else { + static struct option htif_long_options [] = { HTIF_LONG_OPTIONS }; + struct option * htif_option = &htif_long_options[0]; + while (htif_option->name) { + if (arg.substr(1, strlen(htif_option->name)) == htif_option->name) { + optind--; + goto done_processing; + } + htif_option++; + } + std::cerr << argv[0] << ": invalid plus-arg (Verilog or HTIF) \"" + << arg << "\"\n"; + c = '?'; + } + goto retry; + } + case 'P': break; // Nothing to do here, Verilog PlusArg + // Realize that we've hit HTIF (HOST) arguments or error out + default: + if (c >= HTIF_LONG_OPTIONS_OPTIND) { + optind--; + goto done_processing; + } + c = '?'; + goto retry; + } + } + +done_processing: + if (optind == argc) { + std::cerr << "No binary specified for emulator\n"; + usage(argv[0]); + return 1; + } + int htif_argc = 1 + argc - optind; + htif_argv = (char **) malloc((htif_argc) * sizeof (char *)); + htif_argv[0] = argv[0]; + for (int i = 1; optind < argc;) htif_argv[i++] = argv[optind++]; + + if (verbose) + fprintf(stderr, "using random seed %u\n", random_seed); + + srand(random_seed); + srand48(random_seed); + + Verilated::randReset(2); + Verilated::commandArgs(argc, argv); + TEST_HARNESS *tile = new TEST_HARNESS; + +#if VM_TRACE + Verilated::traceEverOn(true); // Verilator must compute traced signals + std::unique_ptr vcdfd(new VerilatedVcdFILE(vcdfile)); + std::unique_ptr tfp(new VerilatedVcdC(vcdfd.get())); + if (vcdfile) { + tile->trace(tfp.get(), 99); // Trace 99 levels of hierarchy + tfp->open(""); + } +#endif + + jtag = new remote_bitbang_t(rbb_port); + dtm = new dtm_t(htif_argc, htif_argv); + tsi = new tsi_t(htif_argc, htif_argv); + + signal(SIGTERM, handle_sigterm); + + bool dump; + // reset for several cycles to handle pipelined reset + for (int i = 0; i < 10; i++) { + tile->reset = 1; + tile->clock = 0; + tile->eval(); +#if VM_TRACE + dump = tfp && trace_count >= start; + if (dump) + tfp->dump(static_cast(trace_count * 2)); +#endif + tile->clock = 1; + tile->eval(); +#if VM_TRACE + if (dump) + tfp->dump(static_cast(trace_count * 2 + 1)); +#endif + trace_count ++; + } + tile->reset = 0; + done_reset = true; + + while (!dtm->done() && !jtag->done() && !tsi->done() && + !tile->io_success && trace_count < max_cycles) { + tile->clock = 0; + tile->eval(); +#if VM_TRACE + dump = tfp && trace_count >= start; + if (dump) + tfp->dump(static_cast(trace_count * 2)); +#endif + + tile->clock = 1; + tile->eval(); +#if VM_TRACE + if (dump) + tfp->dump(static_cast(trace_count * 2 + 1)); +#endif + trace_count++; + } + +#if VM_TRACE + if (tfp) + tfp->close(); + if (vcdfile) + fclose(vcdfile); +#endif + + if (dtm->exit_code()) + { + fprintf(stderr, "*** FAILED *** via dtm (code = %d, seed %d) after %ld cycles\n", dtm->exit_code(), random_seed, trace_count); + ret = dtm->exit_code(); + } + else if (tsi->exit_code()) + { + fprintf(stderr, "*** FAILED *** (code = %d, seed %d) after %ld cycles\n", tsi->exit_code(), random_seed, trace_count); + ret = tsi->exit_code(); + } + else if (jtag->exit_code()) + { + fprintf(stderr, "*** FAILED *** via jtag (code = %d, seed %d) after %ld cycles\n", jtag->exit_code(), random_seed, trace_count); + ret = jtag->exit_code(); + } + else if (trace_count == max_cycles) + { + fprintf(stderr, "*** FAILED *** via trace_count (timeout, seed %d) after %ld cycles\n", random_seed, trace_count); + ret = 2; + } + else if (verbose || print_cycles) + { + fprintf(stderr, "*** PASSED *** Completed after %ld cycles\n", trace_count); + } + + if (dtm) delete dtm; + if (tsi) delete tsi; + if (jtag) delete jtag; + if (tile) delete tile; + if (htif_argv) free(htif_argv); + return ret; +} diff --git a/src/main/scala/example/Configs.scala b/src/main/scala/example/Configs.scala index 3076c862..b7664614 100644 --- a/src/main/scala/example/Configs.scala +++ b/src/main/scala/example/Configs.scala @@ -10,7 +10,7 @@ import testchipip._ class WithBootROM extends Config((site, here, up) => { case BootROMParams => BootROMParams( - contentFileName = s"./testchipip/bootrom/bootrom.rv${site(XLen)}.img") + contentFileName = s"./bootrom/bootrom.rv${site(XLen)}.img") }) object ConfigValName { diff --git a/src/main/scala/example/TestHarness.scala b/src/main/scala/example/TestHarness.scala index 20b7dc06..dfff7e26 100644 --- a/src/main/scala/example/TestHarness.scala +++ b/src/main/scala/example/TestHarness.scala @@ -1,6 +1,8 @@ package example import chisel3._ +import chisel3.experimental._ +import firrtl.transforms.{BlackBoxResourceAnno, BlackBoxSourceHelper} import freechips.rocketchip.diplomacy.LazyModule import freechips.rocketchip.config.{Field, Parameters} import freechips.rocketchip.util.GeneratorApp @@ -15,8 +17,21 @@ class TestHarness(implicit val p: Parameters) extends Module { val dut = p(BuildTop)(clock, reset.toBool, p) dut.debug := DontCare dut.connectSimAXIMem() + dut.connectSimAXIMMIO() dut.dontTouchPorts() dut.tieOffInterrupts() + dut.l2_frontend_bus_axi4.foreach(axi => { + axi.tieoff() + experimental.DataMirror.directionOf(axi.ar.ready) match { + case core.ActualDirection.Input => + axi.r.bits := DontCare + axi.b.bits := DontCare + case core.ActualDirection.Output => + axi.aw.bits := DontCare + axi.ar.bits := DontCare + axi.w.bits := DontCare + } + }) io.success := dut.connectSimSerial() } @@ -24,4 +39,5 @@ object Generator extends GeneratorApp { val longName = names.topModuleProject + "." + names.topModuleClass + "." + names.configs generateFirrtl generateAnno + generateArtefacts } diff --git a/src/main/scala/example/Top.scala b/src/main/scala/example/Top.scala index 98f8107e..bcc745ad 100644 --- a/src/main/scala/example/Top.scala +++ b/src/main/scala/example/Top.scala @@ -2,26 +2,27 @@ package example import chisel3._ import freechips.rocketchip.subsystem._ +import freechips.rocketchip.system._ import freechips.rocketchip.config.Parameters import freechips.rocketchip.devices.tilelink._ import freechips.rocketchip.util.DontTouch import testchipip._ -class ExampleTop(implicit p: Parameters) extends RocketSubsystem +class ExampleTop(implicit p: Parameters) extends ExampleRocketSystem //RocketSubsystem with CanHaveMasterAXI4MemPort with HasPeripheryBootROM // with HasSystemErrorSlave - with HasSyncExtInterrupts +// with HasSyncExtInterrupts with HasNoDebug with HasPeripherySerial { override lazy val module = new ExampleTopModule(this) } -class ExampleTopModule[+L <: ExampleTop](l: L) extends RocketSubsystemModuleImp(l) +class ExampleTopModule[+L <: ExampleTop](l: L) extends ExampleRocketSystemModuleImp(l) // RocketSubsystemModuleImp(l) with HasRTCModuleImp with CanHaveMasterAXI4MemPortModuleImp with HasPeripheryBootROMModuleImp - with HasExtInterruptsModuleImp +// with HasExtInterruptsModuleImp with HasNoDebugModuleImp with HasPeripherySerialModuleImp with DontTouch diff --git a/src/main/scala/example/Verilator.scala b/src/main/scala/example/Verilator.scala new file mode 100644 index 00000000..cf6c14f2 --- /dev/null +++ b/src/main/scala/example/Verilator.scala @@ -0,0 +1,92 @@ +package example + +import java.io.File + +case class GenerateSimConfig( + targetDir: String = ".", + dotFName: String = "verilator_files.f", +) + +trait HasGenerateSimConfig { + val parser = new scopt.OptionParser[GenerateSimConfig]("GenerateSimFiles") { + head("GenerateSimFiles", "0.1") + + opt[String]("target-dir") + .abbr("td") + .valueName("") + .action((x, c) => c.copy(targetDir = x)) + .text("Target director to put files") + + opt[String]("dotFName") + .abbr("df") + .valueName("") + .action((x, c) => c.copy(dotFName = x)) + .text("Name of generated dot-f file") + } +} + +object GenerateSimFiles extends App with HasGenerateSimConfig { + def addOption(file: File): String = { + val fname = file.getCanonicalPath + // add -FI flag for header files + if (fname.takeRight(2) == ".h") { + s"-FI ${fname}" + } else { // do nothing otherwise + fname + } + } + def writeDotF(lines: Seq[String], cfg: GenerateSimConfig): Unit = { + writeTextToFile(lines.mkString("\n"), new File(cfg.targetDir, cfg.dotFName)) + } + // From FIRRTL + def safeFile[A](fileName: String)(code: => A) = try { code } catch { + case e@ (_: java.io.FileNotFoundException | _: NullPointerException) => throw new Exception(fileName, e) + case t: Throwable => throw t + } + // From FIRRTL + def writeResource(name: String, targetDir: String): File = { + val in = getClass.getResourceAsStream(name) + val p = java.nio.file.Paths.get(name) + val fname = p.getFileName().toString(); + + val f = new File(targetDir, fname) + val out = new java.io.FileOutputStream(f) + safeFile(name)(Iterator.continually(in.read).takeWhile(-1 != _).foreach(out.write)) + out.close() + f + } + // From FIRRTL + def writeTextToFile(text: String, file: File) { + val out = new java.io.PrintWriter(file) + out.write(text) + out.close() + } + val resources = Seq( + // TODO(rigge): make conditional on if we are using verilator + "/project-template/csrc/emulator.cc", + "/csrc/SimDTM.cc", + "/csrc/SimJTAG.cc", + "/csrc/remote_bitbang.h", + "/csrc/remote_bitbang.cc", + "/csrc/verilator.h", + "/vsrc/EICG_wrapper.v", + "/testchipip/bootrom/bootrom.rv64.img", + ) + + def writeBootrom(): Unit = { + firrtl.FileUtils.makeDirectory("./bootrom/") + writeResource("/testchipip/bootrom/bootrom.rv64.img", "./bootrom/") + } + + def writeFiles(cfg: GenerateSimConfig): Unit = { + writeBootrom() + firrtl.FileUtils.makeDirectory(cfg.targetDir) + val files = resources.map { writeResource(_, cfg.targetDir) } + writeDotF(files.map(addOption), cfg) + } + + parser.parse(args, GenerateSimConfig()) match { + case Some(cfg) => writeFiles(cfg) + case _ => // error message already shown + } +} diff --git a/testchipip b/testchipip index 4775caf9..b30b7261 160000 --- a/testchipip +++ b/testchipip @@ -1 +1 @@ -Subproject commit 4775caf9f23826fed9e2400c48ca0cfb88f9eb8f +Subproject commit b30b72615ac2c9f7e4fa8e7847e832cefc4c7de4 diff --git a/verisim/Makefile b/verisim/Makefile index 316c4adc..7e1f0507 100644 --- a/verisim/Makefile +++ b/verisim/Makefile @@ -21,19 +21,15 @@ LDFLAGS := $(LDFLAGS) -L$(RISCV)/lib -Wl,-rpath,$(RISCV)/lib -L$(sim_dir) -lfesv include $(base_dir)/Makefrag include $(sim_dir)/Makefrag-verilator +sim_blackboxes = \ + $(build_dir)/firrtl_black_box_resource_files.f + rocketchip_vsrc_dir = $(ROCKETCHIP_DIR)/src/main/resources/vsrc sim_vsrcs = \ $(VERILOG_FILE) \ $(HARNESS_FILE) \ - $(SMEMS_FILE) \ - $(rocketchip_vsrc_dir)/AsyncResetReg.v \ - $(rocketchip_vsrc_dir)/plusarg_reader.v \ - $(testchip_vsrcs) - -sim_csrcs = \ - $(sim_dir)/csrc/verilator-harness.cc \ - $(testchip_csrcs) + $(SMEMS_FILE) model_dir = $(build_dir)/$(long_name) model_dir_debug = $(build_dir)/$(long_name).debug @@ -44,26 +40,27 @@ model_header_debug = $(model_dir_debug)/V$(MODEL).h model_mk = $(model_dir)/V$(MODEL).mk model_mk_debug = $(model_dir_debug)/V$(MODEL).mk -$(model_mk): $(sim_vsrcs) $(INSTALLED_VERILATOR) +$(model_mk): $(sim_vsrcs) $(verilator_dotf) $(INSTALLED_VERILATOR) rm -rf $(build_dir)/$(long_name) mkdir -p $(build_dir)/$(long_name) $(VERILATOR) $(VERILATOR_FLAGS) -Mdir $(build_dir)/$(long_name) \ - -o $(sim) $(sim_vsrcs) $(sim_csrcs) -LDFLAGS "$(LDFLAGS)" \ - -CFLAGS "-I$(build_dir) -include $(model_header)" + -o $(sim) $(sim_vsrcs) -f $(verilator_dotf) -f $(sim_blackboxes) -LDFLAGS "$(LDFLAGS)" \ + -CFLAGS "-I$(build_dir) -include $(build_dir)/$(long_name).plusArgs -include $(model_header)" touch $@ -$(sim): $(model_mk) $(sim_csrcs) +$(sim): $(model_mk) $(MAKE) VM_PARALLEL_BUILDS=1 -C $(build_dir)/$(long_name) -f V$(MODEL).mk -$(model_mk_debug): $(sim_vsrcs) $(INSTALLED_VERILATOR) +$(model_mk_debug): $(sim_vsrcs) $(verilator_dotf) $(INSTALLED_VERILATOR) + rm -rf $(build_dir)/$(long_name) mkdir -p $(build_dir)/$(long_name).debug $(VERILATOR) $(VERILATOR_FLAGS) -Mdir $(build_dir)/$(long_name).debug --trace \ - -o $(sim_debug) $(sim_vsrcs) $(sim_csrcs) -LDFLAGS "$(LDFLAGS)" \ - -CFLAGS "-I$(build_dir) -include $(model_header_debug)" + -o $(sim_debug) $(sim_vsrcs) -f $(verilator_dotf) -f $(sim_blackboxes) -LDFLAGS "$(LDFLAGS)" \ + -CFLAGS "-I$(build_dir) -include $(build_dir)/$(long_name).plusArgs -include $(model_header_debug)" touch $@ -$(sim_debug): $(model_mk_debug) $(sim_csrcs) +$(sim_debug): $(model_mk_debug) $(MAKE) VM_PARALLEL_BUILDS=1 -C $(build_dir)/$(long_name).debug -f V$(MODEL).mk $(output_dir)/%.out: $(output_dir)/% $(sim) @@ -83,5 +80,5 @@ run-regression-tests-fast: $(addprefix $(output_dir)/,$(addsuffix .run,$(regress run-regression-tests-debug: $(addprefix $(output_dir)/,$(addsuffix .vpd,$(regression-tests))) -clean: +clean: clean-scala rm -rf generated-src ./simulator-* diff --git a/verisim/Makefrag-verilator b/verisim/Makefrag-verilator index 01928f75..f8ea0b4c 100644 --- a/verisim/Makefrag-verilator +++ b/verisim/Makefrag-verilator @@ -24,8 +24,6 @@ verilator/verilator-$(VERILATOR_VERSION).tar.gz: mkdir -p $(dir $@) wget http://www.veripool.org/ftp/verilator-$(VERILATOR_VERSION).tgz -O $@ -rocketchip_csrc_dir = $(ROCKETCHIP_DIR)/src/main/resources/csrc - # Run Verilator to produce a fast binary to emulate this circuit. VERILATOR := $(INSTALLED_VERILATOR) --cc --exe VERILATOR_FLAGS := --top-module $(MODEL) \ @@ -33,4 +31,4 @@ VERILATOR_FLAGS := --top-module $(MODEL) \ +define+STOP_COND=\$$c\(\"done_reset\"\) --assert \ --output-split 20000 \ -Wno-STMTDLY --x-assign unique \ - -O3 -CFLAGS "$(CXXFLAGS) -DVERILATOR -include $(rocketchip_csrc_dir)/verilator.h" + -O3 -CFLAGS "$(CXXFLAGS) -DTEST_HARNESS=V$(MODEL) -DVERILATOR" diff --git a/verisim/csrc/verilator-harness.cc b/verisim/csrc/verilator-harness.cc deleted file mode 100644 index 475123c3..00000000 --- a/verisim/csrc/verilator-harness.cc +++ /dev/null @@ -1,167 +0,0 @@ -// See LICENSE for license details. - -#include "verilated.h" -#if VM_TRACE -#include "verilated_vcd_c.h" -#endif -#include -#include -#include -#include -#include -#include -#include - -extern tsi_t* tsi; -static uint64_t trace_count = 0; -bool verbose; -bool done_reset; - -void handle_sigterm(int sig) -{ - tsi->stop(); -} - -double sc_time_stamp() -{ - return trace_count; -} - -extern "C" int vpi_get_vlog_info(void* arg) -{ - return 0; -} - -static inline int copy_argv(int argc, char **argv, char **new_argv) -{ - int optind = 1; - int new_argc = argc; - - new_argv[0] = argv[0]; - - for (int i = 1; i < argc; i++) { - if (argv[i][0] != '+' && argv[i][0] != '-') { - optind = i - 1; - new_argc = argc - i + 1; - break; - } - } - - for (int i = 1; i < new_argc; i++) - new_argv[i] = argv[i + optind]; - - return new_argc; -} - -int main(int argc, char** argv) -{ - unsigned random_seed = (unsigned)time(NULL) ^ (unsigned)getpid(); - uint64_t max_cycles = -1; - uint64_t start = 0; - int ret = 0; - FILE *vcdfile = NULL; - bool print_cycles = false; - char *new_argv[argc]; - int new_argc; - - for (int i = 1; i < argc; i++) { - std::string arg = argv[i]; - if (arg.substr(0, 2) == "-v") { - const char* filename = argv[i]+2; - vcdfile = strcmp(filename, "-") == 0 ? stdout : fopen(filename, "w"); - if (!vcdfile) - abort(); - } else if (arg.substr(0, 2) == "-s") - random_seed = atoi(argv[i]+2); - else if (arg == "+verbose") - verbose = true; - else if (arg.substr(0, 12) == "+max-cycles=") - max_cycles = atoll(argv[i]+12); - else if (arg.substr(0, 7) == "+start=") - start = atoll(argv[i]+7); - else if (arg.substr(0, 12) == "+cycle-count") - print_cycles = true; - } - - if (verbose) - fprintf(stderr, "using random seed %u\n", random_seed); - - srand(random_seed); - srand48(random_seed); - - Verilated::randReset(2); - Verilated::commandArgs(argc, argv); - VTestHarness *tile = new VTestHarness; - -#if VM_TRACE - Verilated::traceEverOn(true); // Verilator must compute traced signals - std::unique_ptr vcdfd(new VerilatedVcdFILE(vcdfile)); - std::unique_ptr tfp(new VerilatedVcdC(vcdfd.get())); - if (vcdfile) { - tile->trace(tfp.get(), 99); // Trace 99 levels of hierarchy - tfp->open(""); - } -#endif - - new_argc = copy_argv(argc, argv, new_argv); - tsi = new tsi_t(new_argc, new_argv); - - signal(SIGTERM, handle_sigterm); - - // reset for several cycles to handle pipelined reset - for (int i = 0; i < 10; i++) { - tile->reset = 1; - tile->clock = 0; - tile->eval(); - tile->clock = 1; - tile->eval(); - tile->reset = 0; - } - done_reset = true; - - while (!tsi->done() && !tile->io_success && trace_count < max_cycles) { - tile->clock = 0; - tile->eval(); -#if VM_TRACE - bool dump = tfp && trace_count >= start; - if (dump) - tfp->dump(static_cast(trace_count * 2)); -#endif - - tile->clock = 1; - tile->eval(); -#if VM_TRACE - if (dump) - tfp->dump(static_cast(trace_count * 2 + 1)); -#endif - trace_count++; - } - -#if VM_TRACE - if (tfp) - tfp->close(); -#endif - - if (vcdfile) - fclose(vcdfile); - - if (tsi->exit_code()) - { - fprintf(stderr, "*** FAILED *** (code = %d, seed %d) after %ld cycles\n", tsi->exit_code(), random_seed, trace_count); - ret = tsi->exit_code(); - } - else if (trace_count == max_cycles) - { - fprintf(stderr, "*** FAILED *** (timeout, seed %d) after %ld cycles\n", random_seed, trace_count); - ret = 2; - } - else if (verbose || print_cycles) - { - fprintf(stderr, "Completed after %ld cycles\n", trace_count); - } - - delete tsi; - delete tile; - - return ret; -}