diff --git a/.circleci/check-commit.sh b/.circleci/check-commit.sh index 98c770ad..7824b943 100755 --- a/.circleci/check-commit.sh +++ b/.circleci/check-commit.sh @@ -82,7 +82,12 @@ search submodules=("coremark" "firemarshal" "nvdla-workload" "spec2017") dir="software" -branches=("master") +if [ "$CIRCLE_BRANCH" == "master" ] || [ "$CIRCLE_BRANCH" == "dev" ] +then + branches=("master") +else + branches=("master" "dev") +fi search submodules=("DRAMSim2" "axe" "barstools" "chisel-testers" "dsptools" "firrtl-interpreter" "torture" "treadle") diff --git a/.circleci/config.yml b/.circleci/config.yml index b6556850..a6d2e495 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,7 +6,7 @@ version: 2.1 parameters: tools-cache-version: type: string - default: "v5" + default: "v6" # default execution env.s executors: @@ -73,7 +73,7 @@ commands: tools-version: type: string default: "riscv-tools" - project-key: + group-key: type: string timeout: type: string @@ -85,11 +85,11 @@ commands: - setup-tools: tools-version: "<< parameters.tools-version >>" - run: - name: Building << parameters.project-key >> subproject using Verilator - command: .circleci/<< parameters.build-script >> << parameters.project-key >> + name: Building << parameters.group-key >> subproject using Verilator + command: .circleci/<< parameters.build-script >> << parameters.group-key >> no_output_timeout: << parameters.timeout >> - save_cache: - key: << parameters.project-key >>-{{ .Branch }}-{{ .Revision }} + key: << parameters.group-key >>-{{ .Branch }}-{{ .Revision }} paths: - "/home/riscvuser/project" @@ -99,11 +99,10 @@ commands: tools-version: type: string default: "riscv-tools" + group-key: + type: string project-key: type: string - extra-cache-restore: - type: string - default: "" run-script: type: string default: "run-tests.sh" @@ -115,13 +114,7 @@ commands: tools-version: "<< parameters.tools-version >>" - restore_cache: keys: - - << parameters.project-key >>-{{ .Branch }}-{{ .Revision }} - - when: - condition: << parameters.extra-cache-restore >> - steps: - - restore_cache: - keys: - - << parameters.extra-cache-restore >>-{{ .Branch }}-{{ .Revision }} + - << parameters.group-key >>-{{ .Branch }}-{{ .Revision }} - run: name: Run << parameters.project-key >> subproject tests command: .circleci/<< parameters.run-script >> << parameters.project-key >> @@ -194,177 +187,154 @@ jobs: key: extra-tests-{{ .Branch }}-{{ .Revision }} paths: - "/home/riscvuser/project/tests" - prepare-chipyard-rocket: + + prepare-chipyard-cores: executor: main-env steps: - prepare-rtl: - project-key: "chipyard-rocket" - prepare-chipyard-sha3: + group-key: "group-cores" + prepare-chipyard-peripherals: executor: main-env steps: - prepare-rtl: - project-key: "chipyard-sha3" - prepare-chipyard-streaming-fir: - executor: main-env - steps: - - prepare-rtl: - project-key: "chipyard-streaming-fir" - prepare-chipyard-streaming-passthrough: - executor: main-env - steps: - - prepare-rtl: - project-key: "chipyard-streaming-passthrough" - prepare-chipyard-hetero: - executor: main-env - steps: - - prepare-rtl: - project-key: "chipyard-hetero" - timeout: "240m" - prepare-chipyard-boom: - executor: main-env - steps: - - prepare-rtl: - project-key: "chipyard-boom" - prepare-rocketchip: - executor: main-env - steps: - - prepare-rtl: - project-key: "rocketchip" - prepare-chipyard-blkdev: - executor: main-env - steps: - - prepare-rtl: - project-key: "chipyard-blkdev" - prepare-chipyard-hwacha: + group-key: "group-peripherals" + prepare-chipyard-accels: executor: main-env steps: - prepare-rtl: tools-version: "esp-tools" - project-key: "chipyard-hwacha" - prepare-chipyard-gemmini: + group-key: "group-accels" + prepare-chipyard-tracegen: executor: main-env steps: - prepare-rtl: - tools-version: "esp-tools" - project-key: "chipyard-gemmini" - prepare-tracegen: + group-key: "group-tracegen" + prepare-chipyard-other: executor: main-env steps: - prepare-rtl: - project-key: "tracegen" - prepare-tracegen-boom: - executor: main-env - steps: - - prepare-rtl: - project-key: "tracegen-boom" - prepare-chipyard-ariane: - executor: main-env - steps: - - prepare-rtl: - project-key: "chipyard-ariane" - prepare-icenet: - executor: main-env - steps: - - prepare-rtl: - project-key: "icenet" - prepare-testchipip: - executor: main-env - steps: - - prepare-rtl: - project-key: "testchipip" - prepare-chipyard-nvdla: - executor: main-env - steps: - - prepare-rtl: - project-key: "chipyard-nvdla" - prepare-chipyard-spiflashwrite: - executor: main-env - steps: - - prepare-rtl: - project-key: "chipyard-spiflashwrite" - prepare-chipyard-spiflashread: - executor: main-env - steps: - - prepare-rtl: - project-key: "chipyard-spiflashread" - prepare-chipyard-mmios: - executor: main-env - steps: - - prepare-rtl: - project-key: "chipyard-mmios" + group-key: "group-other" + chipyard-rocket-run-tests: executor: main-env steps: - run-tests: + group-key: "group-cores" project-key: "chipyard-rocket" - chipyard-sha3-run-tests: - executor: main-env - steps: - - run-tests: - project-key: "chipyard-sha3" - chipyard-streaming-fir-run-tests: - executor: main-env - steps: - - run-tests: - project-key: "chipyard-streaming-fir" - chipyard-streaming-passthrough-run-tests: - executor: main-env - steps: - - run-tests: - project-key: "chipyard-streaming-passthrough" chipyard-hetero-run-tests: executor: main-env steps: - run-tests: + group-key: "group-cores" project-key: "chipyard-hetero" timeout: "15m" chipyard-boom-run-tests: executor: main-env steps: - run-tests: + group-key: "group-cores" project-key: "chipyard-boom" - rocketchip-run-tests: + chipyard-ariane-run-tests: executor: main-env steps: - run-tests: - project-key: "rocketchip" + group-key: "group-cores" + project-key: "chipyard-ariane" + timeout: "30m" + chipyard-dmirocket-run-tests: + executor: main-env + steps: + - run-tests: + group-key: "group-peripherals" + project-key: "chipyard-dmirocket" + chipyard-spiflashwrite-run-tests: + executor: main-env + steps: + - run-tests: + group-key: "group-peripherals" + project-key: "chipyard-spiflashwrite" + chipyard-spiflashread-run-tests: + executor: main-env + steps: + - run-tests: + group-key: "group-peripherals" + project-key: "chipyard-spiflashread" + chipyard-lbwif-run-tests: + executor: main-env + steps: + - run-tests: + group-key: "group-peripherals" + project-key: "chipyard-lbwif" + + chipyard-sha3-run-tests: + executor: main-env + steps: + - run-tests: + group-key: "group-accels" + project-key: "chipyard-sha3" + chipyard-streaming-fir-run-tests: + executor: main-env + steps: + - run-tests: + group-key: "group-accels" + project-key: "chipyard-streaming-fir" + chipyard-streaming-passthrough-run-tests: + executor: main-env + steps: + - run-tests: + group-key: "group-accels" + project-key: "chipyard-streaming-passthrough" chipyard-hwacha-run-tests: executor: main-env steps: - run-tests: tools-version: "esp-tools" + group-key: "group-accels" project-key: "chipyard-hwacha" chipyard-gemmini-run-tests: executor: main-env steps: - run-tests: tools-version: "esp-tools" + group-key: "group-accels" project-key: "chipyard-gemmini" - chipyard-spiflashwrite-run-tests: + chipyard-nvdla-run-tests: executor: main-env steps: - run-tests: - project-key: "chipyard-spiflashwrite" - chipyard-spiflashread-run-tests: - executor: main-env - steps: - - run-tests: - project-key: "chipyard-spiflashread" + group-key: "group-accels" + project-key: "chipyard-nvdla" tracegen-run-tests: executor: main-env steps: - run-tests: + group-key: "group-tracegen" project-key: "tracegen" tracegen-boom-run-tests: executor: main-env steps: - run-tests: + group-key: "group-tracegen" project-key: "tracegen-boom" + icenet-run-tests: + executor: main-env + steps: + - run-tests: + group-key: "group-other" + project-key: "icenet" + timeout: "30m" + testchipip-run-tests: + executor: main-env + steps: + - run-tests: + group-key: "group-other" + project-key: "testchipip" + timeout: "30m" firesim-run-tests: executor: main-env steps: - run-tests: - extra-cache-restore: "extra-tests" + group-key: "extra-tests" project-key: "firesim" run-script: "run-firesim-scala-tests.sh" timeout: "20m" @@ -372,7 +342,7 @@ jobs: executor: main-env steps: - run-tests: - extra-cache-restore: "extra-tests" + group-key: "extra-tests" project-key: "fireboom" run-script: "run-firesim-scala-tests.sh" timeout: "45m" @@ -380,33 +350,10 @@ jobs: executor: main-env steps: - run-tests: - extra-cache-restore: "extra-tests" + group-key: "extra-tests" project-key: "firesim-multiclock" run-script: "run-firesim-scala-tests.sh" timeout: "20m" - chipyard-ariane-run-tests: - executor: main-env - steps: - - run-tests: - project-key: "chipyard-ariane" - timeout: "30m" - chipyard-nvdla-run-tests: - executor: main-env - steps: - - run-tests: - project-key: "chipyard-nvdla" - icenet-run-tests: - executor: main-env - steps: - - run-tests: - project-key: "icenet" - timeout: "30m" - testchipip-run-tests: - executor: main-env - steps: - - run-tests: - project-key: "testchipip" - timeout: "30m" # Order and dependencies of jobs to run workflows: @@ -446,154 +393,86 @@ workflows: - install-riscv-toolchain # Prepare the verilator builds - - prepare-chipyard-rocket: + - prepare-chipyard-cores: requires: - install-riscv-toolchain - install-verilator - - - prepare-chipyard-sha3: + - prepare-chipyard-peripherals: requires: - install-riscv-toolchain - install-verilator - - - prepare-chipyard-streaming-fir: - requires: - - install-riscv-toolchain - - install-verilator - - - prepare-chipyard-streaming-passthrough: - requires: - - install-riscv-toolchain - - install-verilator - - - prepare-chipyard-hetero: - requires: - - install-riscv-toolchain - - install-verilator - - - prepare-chipyard-boom: - requires: - - install-riscv-toolchain - - install-verilator - - - prepare-rocketchip: - requires: - - install-riscv-toolchain - - install-verilator - - - prepare-chipyard-blkdev: - requires: - - install-riscv-toolchain - - install-verilator - - - prepare-chipyard-hwacha: + - prepare-chipyard-accels: requires: - install-esp-toolchain - install-verilator - - - prepare-chipyard-gemmini: - requires: - - install-esp-toolchain - - install-verilator - - - prepare-tracegen: + - prepare-chipyard-tracegen: requires: - install-riscv-toolchain - install-verilator - - - prepare-tracegen-boom: + - prepare-chipyard-other: requires: - install-riscv-toolchain - install-verilator - - prepare-chipyard-ariane: - requires: - - install-riscv-toolchain - - install-verilator - - - prepare-icenet: - requires: - - install-riscv-toolchain - - install-verilator - - - prepare-testchipip: - requires: - - install-riscv-toolchain - - install-verilator - - - prepare-chipyard-nvdla: - requires: - - install-riscv-toolchain - - install-verilator - - - prepare-chipyard-spiflashwrite: - requires: - - install-riscv-toolchain - - install-verilator - - - prepare-chipyard-spiflashread: - requires: - - install-riscv-toolchain - - install-verilator - - - prepare-chipyard-mmios: - requires: - - install-riscv-toolchain - - # Run the respective tests - # Run the example tests - chipyard-rocket-run-tests: requires: - - prepare-chipyard-rocket + - prepare-chipyard-cores + - chipyard-hetero-run-tests: + requires: + - prepare-chipyard-cores + - chipyard-boom-run-tests: + requires: + - prepare-chipyard-cores + - chipyard-ariane-run-tests: + requires: + - prepare-chipyard-cores + + - chipyard-dmirocket-run-tests: + requires: + - prepare-chipyard-peripherals + - chipyard-spiflashwrite-run-tests: + requires: + - prepare-chipyard-peripherals + - chipyard-spiflashread-run-tests: + requires: + - prepare-chipyard-peripherals + - chipyard-lbwif-run-tests: + requires: + - prepare-chipyard-peripherals - chipyard-sha3-run-tests: requires: - - prepare-chipyard-sha3 - + - prepare-chipyard-accels - chipyard-streaming-fir-run-tests: requires: - - prepare-chipyard-streaming-fir - + - prepare-chipyard-accels - chipyard-streaming-passthrough-run-tests: requires: - - prepare-chipyard-streaming-passthrough - - - chipyard-hetero-run-tests: - requires: - - prepare-chipyard-hetero - - - chipyard-boom-run-tests: - requires: - - prepare-chipyard-boom - - - rocketchip-run-tests: - requires: - - prepare-rocketchip - + - prepare-chipyard-accels - chipyard-hwacha-run-tests: requires: - - prepare-chipyard-hwacha - + - prepare-chipyard-accels - chipyard-gemmini-run-tests: requires: - - prepare-chipyard-gemmini + - prepare-chipyard-accels + - chipyard-nvdla-run-tests: + requires: + - prepare-chipyard-accels - tracegen-run-tests: requires: - - prepare-tracegen - + - prepare-chipyard-tracegen - tracegen-boom-run-tests: requires: - - prepare-tracegen-boom + - prepare-chipyard-tracegen - - chipyard-spiflashwrite-run-tests: + - icenet-run-tests: requires: - - prepare-chipyard-spiflashwrite - - - chipyard-spiflashread-run-tests: + - prepare-chipyard-other + - testchipip-run-tests: requires: - - prepare-chipyard-spiflashread + - prepare-chipyard-other # Run the firesim tests - firesim-run-tests: @@ -612,17 +491,4 @@ workflows: - install-verilator - build-extra-tests - - chipyard-ariane-run-tests: - requires: - - prepare-chipyard-ariane - - chipyard-nvdla-run-tests: - requires: - - prepare-chipyard-nvdla - - icenet-run-tests: - requires: - - prepare-icenet - - - testchipip-run-tests: - requires: - - prepare-testchipip diff --git a/.circleci/defaults.sh b/.circleci/defaults.sh index 7cb8c1e2..80e3b112 100755 --- a/.circleci/defaults.sh +++ b/.circleci/defaults.sh @@ -45,9 +45,19 @@ LOCAL_CHIPYARD_DIR=$LOCAL_CHECKOUT_DIR LOCAL_SIM_DIR=$LOCAL_CHIPYARD_DIR/sims/verilator LOCAL_FIRESIM_DIR=$LOCAL_CHIPYARD_DIR/sims/firesim/sim +# key value store to get the build groups +declare -A grouping +grouping["group-cores"]="chipyard-ariane chipyard-rocket chipyard-hetero chipyard-boom" +grouping["group-peripherals"]="chipyard-dmirocket chipyard-blkdev chipyard-spiflashread chipyard-spiflashwrite chipyard-mmios chipyard-lbwif" +grouping["group-accels"]="chipyard-nvdla chipyard-sha3 chipyard-hwacha chipyard-gemmini chipyard-streaming-fir chipyard-streaming-passthrough" +grouping["group-tracegen"]="tracegen tracegen-boom" +grouping["group-other"]="icenet testchipip" + # key value store to get the build strings declare -A mapping mapping["chipyard-rocket"]="" +mapping["chipyard-dmirocket"]=" CONFIG=dmiRocketConfig" +mapping["chipyard-lbwif"]=" CONFIG=LBWIFRocketConfig" mapping["chipyard-sha3"]=" CONFIG=Sha3RocketConfig" mapping["chipyard-streaming-fir"]=" CONFIG=StreamingFIRRocketConfig" mapping["chipyard-streaming-passthrough"]=" CONFIG=StreamingPassthroughRocketConfig" @@ -60,9 +70,10 @@ mapping["chipyard-ariane"]=" CONFIG=ArianeConfig" mapping["chipyard-spiflashread"]=" CONFIG=LargeSPIFlashROMRocketConfig" mapping["chipyard-spiflashwrite"]=" CONFIG=SmallSPIFlashRocketConfig" mapping["chipyard-mmios"]=" CONFIG=MMIORocketConfig verilog" -mapping["tracegen"]=" CONFIG=NonBlockingTraceGenL2Config TOP=TraceGenSystem" -mapping["tracegen-boom"]=" CONFIG=BoomTraceGenConfig TOP=TraceGenSystem" +mapping["tracegen"]=" CONFIG=NonBlockingTraceGenL2Config" +mapping["tracegen-boom"]=" CONFIG=BoomTraceGenConfig" mapping["chipyard-nvdla"]=" CONFIG=SmallNVDLARocketConfig" + mapping["firesim"]="SCALA_TEST=firesim.firesim.RocketNICF1Tests" mapping["firesim-multiclock"]="SCALA_TEST=firesim.firesim.RocketMulticlockF1Tests" mapping["fireboom"]="SCALA_TEST=firesim.firesim.BoomF1Tests" diff --git a/.circleci/do-rtl-build.sh b/.circleci/do-rtl-build.sh index a7c8ad50..784dbc04 100755 --- a/.circleci/do-rtl-build.sh +++ b/.circleci/do-rtl-build.sh @@ -31,7 +31,7 @@ run "cp -r ~/.sbt $REMOTE_WORK_DIR" TOOLS_DIR=$REMOTE_RISCV_DIR LD_LIB_DIR=$REMOTE_RISCV_DIR/lib -if [ $1 = "chipyard-gemmini" ]; then +if [ $1 = "group-accels" ]; then export RISCV=$LOCAL_ESP_DIR export LD_LIBRARY_PATH=$LOCAL_ESP_DIR/lib export PATH=$RISCV/bin:$PATH @@ -40,9 +40,7 @@ if [ $1 = "chipyard-gemmini" ]; then git submodule update --init --recursive gemmini-rocc-tests cd gemmini-rocc-tests ./build.sh -fi -if [ $1 = "chipyard-hwacha" ] || [ $1 = "chipyard-gemmini" ]; then TOOLS_DIR=$REMOTE_ESP_DIR LD_LIB_DIR=$REMOTE_ESP_DIR/lib run "mkdir -p $REMOTE_ESP_DIR" @@ -54,16 +52,19 @@ fi # enter the verilator directory and build the specific config on remote server run "export RISCV=\"$TOOLS_DIR\"; \ - export LD_LIBRARY_PATH=\"$LD_LIB_DIR\"; \ - export PATH=\"$REMOTE_VERILATOR_DIR/bin:\$PATH\"; \ - export VERILATOR_ROOT=\"$REMOTE_VERILATOR_DIR\"; \ - export COURSIER_CACHE=\"$REMOTE_WORK_DIR/.coursier-cache\"; \ - make -C $REMOTE_SIM_DIR clean; \ - make -j$REMOTE_MAKE_NPROC -C $REMOTE_SIM_DIR JAVA_ARGS=\"$REMOTE_JAVA_ARGS\" ${mapping[$1]}" -run "rm -rf $REMOTE_CHIPYARD_DIR/project" + make -C $REMOTE_SIM_DIR clean;" -# copy back the final build +read -a keys <<< ${grouping[$1]} +for key in "${keys[@]}" +do + run "export RISCV=\"$TOOLS_DIR\"; \ + export LD_LIBRARY_PATH=\"$LD_LIB_DIR\"; \ + export PATH=\"$REMOTE_VERILATOR_DIR/bin:\$PATH\"; \ + export VERILATOR_ROOT=\"$REMOTE_VERILATOR_DIR\"; \ + export COURSIER_CACHE=\"$REMOTE_WORK_DIR/.coursier-cache\"; \ + make -j$REMOTE_MAKE_NPROC -C $REMOTE_SIM_DIR FIRRTL_LOGLEVEL=info JAVA_ARGS=\"$REMOTE_JAVA_ARGS\" ${mapping[$key]}" +done run "rm -rf $REMOTE_CHIPYARD_DIR/project" diff --git a/.circleci/run-tests.sh b/.circleci/run-tests.sh index 08b95e68..20104f18 100755 --- a/.circleci/run-tests.sh +++ b/.circleci/run-tests.sh @@ -32,6 +32,12 @@ case $1 in chipyard-rocket) run_bmark ${mapping[$1]} ;; + chipyard-dmirocket) + run_bmark ${mapping[$1]} + ;; + chipyard-lbwif) + run_bmark ${mapping[$1]} + ;; chipyard-boom) run_bmark ${mapping[$1]} ;; @@ -86,7 +92,7 @@ case $1 in run_tracegen ${mapping[$1]} ;; chipyard-ariane) - make run-binary-fast -C $LOCAL_SIM_DIR ${mapping[$1]} BINARY=$RISCV/riscv64-unknown-elf/share/riscv-tests/benchmarks/dhrystone.riscv + make run-binary-fast -C $LOCAL_SIM_DIR ${mapping[$1]} BINARY=$RISCV/riscv64-unknown-elf/share/riscv-tests/benchmarks/multiply.riscv ;; chipyard-nvdla) make -C $LOCAL_CHIPYARD_DIR/tests diff --git a/.gitignore b/.gitignore index 35d9b2d8..a85d0dd2 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ target *.stamp *.vcd *.swp +*.swo *.log *# *~ diff --git a/common.mk b/common.mk index 43615a92..f8bd4cf4 100644 --- a/common.mk +++ b/common.mk @@ -3,22 +3,49 @@ ######################################################################################### SHELL=/bin/bash - ifndef RISCV $(error RISCV is unset. You must set RISCV yourself, or through the Chipyard auto-generated env file) else $(info Running with RISCV=$(RISCV)) endif +######################################################################################### +# specify user-interface variables +######################################################################################### +HELP_COMPILATION_VARIABLES += \ +" EXTRA_GENERATOR_REQS = additional make requirements needed for the main generator" \ +" EXTRA_SIM_CXXFLAGS = additional CXXFLAGS for building simulators" \ +" EXTRA_SIM_LDFLAGS = additional LDFLAGS for building simulators" \ +" EXTRA_SIM_SOURCES = additional simulation sources needed for simulator" \ +" EXTRA_SIM_REQS = additional make requirements to build the simulator" + +EXTRA_GENERATOR_REQS ?= +EXTRA_SIM_CXXFLAGS ?= +EXTRA_SIM_LDFLAGS ?= +EXTRA_SIM_SOURCES ?= +EXTRA_SIM_REQS ?= + +#---------------------------------------------------------------------------- +HELP_SIMULATION_VARIABLES += \ +" EXTRA_SIM_FLAGS = additional runtime simulation flags (passed within +permissive)" \ +" NUMACTL = set to '1' to wrap simulator in the appropriate numactl command" + +EXTRA_SIM_FLAGS ?= +NUMACTL ?= 0 + +NUMA_PREFIX = $(if $(filter $(NUMACTL),0),,$(shell $(base_dir)/scripts/numa_prefix)) + +#---------------------------------------------------------------------------- +HELP_COMMANDS += \ +" run-binary = run [./$(shell basename $(sim))] and log instructions to file" \ +" run-binary-fast = run [./$(shell basename $(sim))] and don't log instructions" \ +" run-binary-debug = run [./$(shell basename $(sim_debug))] and log instructions and waveform to files" \ +" verilog = generate intermediate verilog files from chisel elaboration and firrtl passes" \ +" run-tests = run all assembly and benchmark tests" ######################################################################################### -# extra make variables/rules from subprojects -# -# EXTRA_GENERATOR_REQS - requirements needed for the main generator -# EXTRA_SIM_FLAGS - runtime simulation flags -# EXTRA_SIM_CC_FLAGS - cc flags for simulators -# EXTRA_SIM_SOURCES - simulation sources needed for simulator -# EXTRA_SIM_REQS - requirements to build the simulator +# include additional subproject make fragments +# see HELP_COMPILATION_VARIABLES ######################################################################################### include $(base_dir)/generators/ariane/ariane.mk include $(base_dir)/generators/tracegen/tracegen.mk @@ -35,7 +62,8 @@ SOURCE_DIRS = $(addprefix $(base_dir)/,generators sims/firesim/sim tools/barstoo SCALA_SOURCES = $(call lookup_srcs,$(SOURCE_DIRS),scala) VLOG_SOURCES = $(call lookup_srcs,$(SOURCE_DIRS),sv) $(call lookup_srcs,$(SOURCE_DIRS),v) # This assumes no SBT meta-build sources -SBT_SOURCES = $(call lookup_srcs,$(base_dir),sbt) +SBT_SOURCE_DIRS = $(addprefix $(base_dir)/,generators sims/firesim/sim tools) +SBT_SOURCES = $(call lookup_srcs,$(SBT_SOURCE_DIRS),sbt) $(base_dir)/build.sbt $(base_dir)/project/plugins.sbt ######################################################################################### # jar creation variables and rules @@ -55,7 +83,6 @@ $(FIRRTL_TEST_JAR): $(call lookup_srcs,$(CHIPYARD_FIRRTL_DIR),scala) cp -p $(CHIPYARD_FIRRTL_DIR)/utils/bin/firrtl-test.jar $@ touch $@ - ######################################################################################### # Bloop Project Definitions ######################################################################################### @@ -140,20 +167,18 @@ verilog: $(sim_vsrcs) # helper rules to run simulations ######################################################################################### .PHONY: run-binary run-binary-fast run-binary-debug run-fast + +# run normal binary with hardware-logged insn dissassembly run-binary: $(output_dir) $(sim) - (set -o pipefail && $(sim) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(SEED_FLAG) $(VERBOSE_FLAGS) $(PERMISSIVE_OFF) $(BINARY) >(spike-dasm > $(sim_out_name).out) | tee $(sim_out_name).log) + (set -o pipefail && $(NUMA_PREFIX) $(sim) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(SEED_FLAG) $(VERBOSE_FLAGS) $(PERMISSIVE_OFF) $(BINARY) >(spike-dasm > $(sim_out_name).out) | tee $(sim_out_name).log) -######################################################################################### -# helper rules to run simulator as fast as possible -######################################################################################### +# run simulator as fast as possible (no insn disassembly) run-binary-fast: $(output_dir) $(sim) - (set -o pipefail && $(sim) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(SEED_FLAG) $(PERMISSIVE_OFF) $(BINARY) >(spike-dasm > $(sim_out_name).out) | tee $(sim_out_name).log) + (set -o pipefail && $(NUMA_PREFIX) $(sim_debug) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(SEED_FLAG) $(VERBOSE_FLAGS) $(WAVEFORM_FLAG) $(PERMISSIVE_OFF) $(BINARY) >(spike-dasm > $(sim_out_name).out) | tee $(sim_out_name).log) run-fast: run-asm-tests-fast run-bmark-tests-fast @@ -189,10 +214,10 @@ $(output_dir)/%: $(RISCV)/riscv64-unknown-elf/share/riscv-tests/isa/% $(output_d ln -sf $< $@ $(output_dir)/%.run: $(output_dir)/% $(sim) - (set -o pipefail && $(sim) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(SEED_FLAG) $(PERMISSIVE_OFF) $< >(spike-dasm > $@) | tee $<.log) + (set -o pipefail && $(NUMA_PREFIX) $(sim) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(SEED_FLAG) $(VERBOSE_FLAGS) $(PERMISSIVE_OFF) $< >(spike-dasm > $@) | tee $<.log) ######################################################################################### # include build/project specific makefrags made from the generator @@ -211,6 +236,13 @@ dramsim_lib = $(dramsim_dir)/libdramsim.a $(dramsim_lib): $(MAKE) -C $(dramsim_dir) $(notdir $@) +######################################################################################### +# print help text +######################################################################################### +.PHONY: help +help: + @for line in $(HELP_LINES); do echo "$$line"; done + ######################################################################################### # Implicit rule handling ######################################################################################### diff --git a/docs/Advanced-Concepts/Chip-Communication.rst b/docs/Advanced-Concepts/Chip-Communication.rst index e36805ec..8d63992a 100644 --- a/docs/Advanced-Concepts/Chip-Communication.rst +++ b/docs/Advanced-Concepts/Chip-Communication.rst @@ -130,38 +130,8 @@ Using the JTAG Interface ------------------------ The main way to use JTAG with a Rocket Chip based system is to instantiate the Debug Transfer Module (DTM) -and configure it to use a JTAG interface (by default the DTM is setup to use the DMI interface mentioned above). - -Creating a DTM+JTAG Config -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -First, a DTM config must be created for the system that you want to create. -This step is similar to the DMI simulation section within the :ref:`Starting the TSI or DMI Simulation` section. -The configuration is very similar to a DMI-based configuration. The main difference -is the addition of the ``WithJtagDTM`` config fragment that configures the instantiated DTM to use the JTAG protocol as the -bringup method. - -.. literalinclude:: ../../generators/chipyard/src/main/scala/config/RocketConfigs.scala - :language: scala - :start-after: DOC include start: JtagRocket - :end-before: DOC include end: JtagRocket - -Building a DTM+JTAG Simulator -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -After creating the config, call the ``make`` command like the following to build a simulator for your RTL: - -.. code-block:: bash - - cd sims/verilator - # or - cd sims/vcs - - make CONFIG=jtagRocketConfig - -In this example, the simulation will use the config that you previously specified, as well as set -the other parameters that are needed to satisfy the build system. After that point, you -should have a JTAG enabled simulator that you can attach to using OpenOCD and GDB! +and configure it to use a JTAG interface. The default Chipyard designs instantiate the DTM and configure it +to use JTAG. You may attach OpenOCD and GDB to any of the default JTAG-enabled designs. Debugging with JTAG ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/Advanced-Concepts/Debugging-BOOM.rst b/docs/Advanced-Concepts/Debugging-BOOM.rst index 1e61804c..fd41a9d7 100644 --- a/docs/Advanced-Concepts/Debugging-BOOM.rst +++ b/docs/Advanced-Concepts/Debugging-BOOM.rst @@ -12,11 +12,14 @@ to verify functionality. Setting up Dromajo Co-simulation -------------------------------------- -Dromajo co-simulation is setup to work when two config fragments are added to a BOOM config. -First, a ``chipyard.config.WithTraceIO`` config fragment must be added so that BOOM's traceport is enabled. -Second, a ``chipyard.iobinders.WithSimDromajoBridge`` config fragment must be added to -connect the Dromajo co-simulator to the traceport. -Once both config fragments are added Dromajo should be enabled. +Dromajo co-simulation is setup to work when three config fragments are added to a BOOM config. + + * A ``chipyard.config.WithTraceIO`` config fragment must be added so that BOOM's traceport is enabled. + * A ``chipyard.iobinders.WithTraceIOPunchthrough`` config fragment must be added to add the ``TraceIO`` to the ``ChipTop`` + * A ``chipyard.harness.WithSimDromajoBridge`` config fragment must be added to instantiate a Dromajo cosimulator in the ``TestHarness`` and connect it to the ``ChipTop``'s ``TraceIO`` + + +Once all config fragments are added Dromajo should be enabled. To build/run Dromajo with a BOOM design, run your configuration the following make commands: diff --git a/docs/Advanced-Concepts/Top-Testharness.rst b/docs/Advanced-Concepts/Top-Testharness.rst index ebd5b370..43a8a338 100644 --- a/docs/Advanced-Concepts/Top-Testharness.rst +++ b/docs/Advanced-Concepts/Top-Testharness.rst @@ -14,9 +14,9 @@ ChipTop/DUT ``ChipTop`` is the top-level module that instantiates the ``System`` submodule, usually an instance of the concrete class ``DigitalTop``. The vast majority of the design resides in the ``System``. Other components that exist inside the ``ChipTop`` layer are generally IO cells, clock receivers and multiplexers, reset synchronizers, and other analog IP that needs to exist outside of the ``System``. -The ``IOBinders`` are responsible for instantiating the IO cells and defining the test harness collateral that connects to the top-level ports. -Most of these types of devices can be instantiated using custom ``IOBinders``, so the provided ``ChipTop`` and ``ChipTopCaughtReset`` classes are sufficient. -However, if needed, the ``BaseChipTop`` abstract class can be extended for building more custom ``ChipTop`` designs. +The ``IOBinders`` are responsible for instantiating the IO cells for ``ChipTop`` IO that correspond to IO of the ``System``. +The ``HarnessBinders`` are responsible for instantiating test harness collateral that connects to the ``ChipTop`` ports. +Most types of devices and testing collateral can be instantiated using custom ``IOBinders`` and ``HarnessBinders``. System/DigitalTop diff --git a/docs/Customization/IOBinders.rst b/docs/Customization/IOBinders.rst index 6332d07a..ff180bcd 100644 --- a/docs/Customization/IOBinders.rst +++ b/docs/Customization/IOBinders.rst @@ -1,41 +1,43 @@ +IOBinders and HarnessBinders +============================ + +In Chipyard we use special ``Parameters`` keys, ``IOBinders`` and ``HarnessBinders`` to bridge the gap between digital system IOs and TestHarness collateral. + IOBinders ========= -In Chipyard we use a special ``Parameters`` key, ``IOBinders`` to instantiate IO cells in the ``ChipTop`` layer and determine what modules to bind to the IOs of a ``ChipTop`` in the ``TestHarness``. +The ``IOBinder`` functions are responsible for instantiating IO cells and IOPorts in the ``ChipTop`` layer. + +``IOBinders`` are typically defined using the ``OverrideIOBinder`` or ``ComposeIOBinder`` macros. An ``IOBinder`` consists of a function matching ``Systems`` with a given trait that generates IO ports and IOCells, and returns a list of generated ports and cells. + +For example, the ``WithUARTIOCells`` IOBinder will, for any ``System`` that might have UART ports (``HasPeripheryUARTModuleImp``, generate ports within the ``ChipTop`` (``ports``) as well as IOCells with the appropriate type and direction (``cells2d``). This function returns a the list of generated ports, and the list of generated IOCells. The list of generated ports is passed to the ``HarnessBinders`` such that they can be connected to ``TestHarness`` devices. + .. literalinclude:: ../../generators/chipyard/src/main/scala/IOBinders.scala :language: scala - :start-after: DOC include start: IOBinders - :end-before: DOC include end: IOBinders + :start-after: DOC include start: WithUARTIOCells + :end-before: DOC include end: WithUARTIOCells +HarnessBinders +============== -This special key solves the problem of duplicating test-harnesses for each different ``System`` type. -You could just as well create a custom harness module that attaches IOs explicitly. -Instead, the ``IOBinders`` key provides a map from Scala traits to attachment behaviors. -Each ``IOBinder`` returns a tuple of three values: the list of ``ChipTop`` ports created by the ``IOBinder``, the list of all IO cell modules instantiated by the ``IOBinder``, and an optional function to be called inside the test harness. -This function is responsible for instantiating logic inside the ``TestHarness`` to appropriately drive the ``ChipTop`` IO ports created by the ``IOBinder``. -Conveniently, because the ``IOBinder`` is generating the port, it may also use the port inside this function, which prevents the ``BaseChipTop`` code from ever needing to access the port ``val``, thus having the ``IOBinder`` house all port specific code. -This scheme prevents the need to have two separate binder functions for each ``System`` trait. -When creating custom ``IOBinders`` it is important to use ``suggestName`` to name ports; otherwise Chisel will raise an exception trying to name the IOs. -The example ``IOBinders`` demonstrate this. +The ``HarnessBinder`` functions determine what modules to bind to the IOs of a ``ChipTop`` in the ``TestHarness``. The ``HarnessBinder`` interface is designed to be reused across various simulation/implementation modes, enabling decoupling of the target design from simulation and testing concerns. -As an example, the ``WithGPIOTiedOff`` IOBinder creates IO cells for the GPIO module(s) instantiated in the ``System``, then punches out new ``Analog`` ports for each one. -The test harness simply ties these off, but additional logic could be inserted to perform some kind of test in the ``TestHarness``. + * For SW RTL or GL simulations, the default set of ``HarnessBinders`` instantiate software-simulated models of various devices, for example external memory or UART, and connect those models to the IOs of the ``ChipTop``. + * For FireSim simulations, FireSim-specific ``HarnessBinders`` instantiate ``Bridges``, which faciliate cycle-accurate simulation across the simulated chip's IOs. See the FireSim documentation for more details. + * In the future, a Chipyard FPGA prototyping flow may use ``HarnessBinders`` to connect ``ChipTop`` IOs to other devices or IOs in the FPGA harness. -.. literalinclude:: ../../generators/chipyard/src/main/scala/IOBinders.scala +Like ``IOBinders``, ``HarnessBinders`` are defined using macros (``OverrideHarnessBinder, ComposeHarnessBinder``), and match ``Systems`` with a given trait. However, ``HarnessBinders`` are also passed a reference to the ``TestHarness`` (``th: HasHarnessSignalReferences``) and the list of ports generated by the corresponding ``IOBinder`` (``ports: Seq[Data]``). + +For exmaple, the ``WithUARTAdapter`` will connect the UART SW display adapter to the ports generated by the ``WithUARTIOCells`` described earlier, if those ports are present. + +.. literalinclude:: ../../generators/chipyard/src/main/scala/HarnessBinders.scala :language: scala - :start-after: DOC include start: WithGPIOTiedOff - :end-before: DOC include end: WithGPIOTiedOff + :start-after: DOC include start: WithUARTAdapter + :end-before: DOC include end: WithUARTAdapter +The ``IOBinder`` and ``HarnessBinder`` system is designed to enable decoupling of concerns between the target design and the simulation system. -``IOBinders`` also do not need to create ports. Some ``IOBinders`` can simply insert circuitry inside the ``ChipTop`` layer. -For example, the ``WithSimAXIMemTiedOff`` IOBinder specifies that any ``System`` which matches ``CanHaveMasterAXI4MemPortModuleImp`` will have a ``SimAXIMem`` connected inside ``ChipTop``. +For a given set of chip IOs, there may be not only multiple simulation platforms ("harnesses", so-to-speak), but also multiple simulation strategies. For example, the choice of whether to connect the backing AXI4 memory port to an accurate DRAM model (``SimDRAM``) or a simple simulated memory model (``SimAXIMem``) is isolated in ``HarnessBinders``, and does not affect target RTL generation. -.. literalinclude:: ../../generators/chipyard/src/main/scala/IOBinders.scala - :language: scala - :start-after: DOC include start: WithSimAXIMem - :end-before: DOC include end: WithSimAXIMem - -These classes are all ``Config`` objects, which can be mixed into the configs to specify IO connection behaviors. - -There are two macros for generating these ``Config``s. ``OverrideIOBinder`` overrides any existing behaviors set for a particular IO in the ``Config`` object. This macro is frequently used because typically top-level IOs drive or are driven by only one source, so a composition of ``IOBinders`` does not make sense. The ``ComposeIOBinder`` macro provides the functionality of not overriding existing behaviors. +Similarly, for a given simulation platform and strategy, there may be multiple strategies for generating the chip IOs. This target-design configuration is isolated in the ``IOBinders``. diff --git a/docs/Simulation/Software-RTL-Simulation.rst b/docs/Simulation/Software-RTL-Simulation.rst index 28ae223e..d952c62c 100644 --- a/docs/Simulation/Software-RTL-Simulation.rst +++ b/docs/Simulation/Software-RTL-Simulation.rst @@ -40,8 +40,7 @@ For a proprietry VCS simulation, enter the ``sims/vcs`` directory # Enter VCS directory cd sims/vcs - -.. _sim-default: +.. _sw-sim-help: Simulating The Default Example ------------------------------- @@ -82,6 +81,22 @@ For example: .. _sw-sim-custom: +Makefile Variables and Commands +------------------------------- +You can get a list of useful Makefile variables and commands available from the Verilator or VCS directories. simply run ``make help``: + +.. code-block:: shell + + # Enter Verilator directory + cd sims/verilator + make help + + # Enter VCS directory + cd sims/vcs + make help + +.. _sim-default: + Simulating A Custom Project ------------------------------- @@ -167,3 +182,18 @@ An open-source vcd-capable waveform viewer is `GTKWave `` option enables the compiled Verilator simulator to use ```` parallel threads. +On a multi-socket machine, you will want to make sure all threads are on the same socket by using ``NUMACTL=1`` to enable ``numactl``. +By enabling this, you will use Chipyard's ``numa_prefix`` wrapper, which is a simple wrapper around ``numactl`` that runs your verilated simulator like this: ``$(numa_prefix) ./simulator- ``. +Note that both these flags are mutually exclusive, you can use either independently (though it makes sense to use ``NUMACTL`` just with ``VERILATOR_THREADS=8`` during a Verilator simulation). diff --git a/generators/ariane b/generators/ariane index 0ed91074..3a2eed60 160000 --- a/generators/ariane +++ b/generators/ariane @@ -1 +1 @@ -Subproject commit 0ed9107485281545bf5abf2a042dface55e740bf +Subproject commit 3a2eed602faac24e58a530db429f23f11810aae9 diff --git a/generators/boom b/generators/boom index 859c6055..dc22cacf 160000 --- a/generators/boom +++ b/generators/boom @@ -1 +1 @@ -Subproject commit 859c60553b0cd2e84ee586ad6de25223baefb722 +Subproject commit dc22cacf71fe88b95f3393d622f53648bf0440bd diff --git a/generators/chipyard/src/main/scala/ChipTop.scala b/generators/chipyard/src/main/scala/ChipTop.scala index d0b4df02..dfe08780 100644 --- a/generators/chipyard/src/main/scala/ChipTop.scala +++ b/generators/chipyard/src/main/scala/ChipTop.scala @@ -4,118 +4,59 @@ import chisel3._ import scala.collection.mutable.{ArrayBuffer} +import freechips.rocketchip.prci.{ClockGroupIdentityNode, ClockSinkParameters, ClockSinkNode, ClockGroup} +import freechips.rocketchip.subsystem.{BaseSubsystem, SubsystemDriveAsyncClockGroupsKey} import freechips.rocketchip.config.{Parameters, Field} -import freechips.rocketchip.diplomacy.{LazyModule} +import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, LazyRawModuleImp, LazyModuleImpLike} import freechips.rocketchip.util.{ResetCatchAndSync} -import chipyard.config.ConfigValName._ -import chipyard.iobinders.{IOBinders, TestHarnessFunction, IOBinderTuple} +import chipyard.iobinders._ import barstools.iocell.chisel._ -case object BuildSystem extends Field[Parameters => LazyModule]((p: Parameters) => LazyModule(new DigitalTop()(p))) - -/** - * Chipyard provides three baseline, top-level reset schemes, set using the - * [[GlobalResetSchemeKey]] in a Parameters instance. These are: - * - * 1) Synchronous: The input coming to the chip is synchronous to the provided - * clocks and will be used without modification as a synchronous reset. - * This is safe only for use in FireSim and SW simulation. - * - * 2) Asynchronous: The input reset is asynchronous to the input clock, but it - * is caught and synchronized to that clock before it is dissemenated. - * Thus, downsteam modules will be emitted with synchronously reset state - * elements. - * - * 3) Asynchronous Full: The input reset is asynchronous to the input clock, - * and is used globally as an async reset. Downstream modules will be emitted - * with asynchronously reset state elements. - * - */ -sealed trait GlobalResetScheme { - def pinIsAsync: Boolean -} -sealed trait HasAsyncInput { self: GlobalResetScheme => - def pinIsAsync = true -} - -sealed trait HasSyncInput { self: GlobalResetScheme => - def pinIsAsync = false -} - -case object GlobalResetSynchronous extends GlobalResetScheme with HasSyncInput -case object GlobalResetAsynchronous extends GlobalResetScheme with HasAsyncInput -case object GlobalResetAsynchronousFull extends GlobalResetScheme with HasAsyncInput -case object GlobalResetSchemeKey extends Field[GlobalResetScheme](GlobalResetSynchronous) +case object BuildSystem extends Field[Parameters => LazyModule]((p: Parameters) => new DigitalTop()(p)) /** * The base class used for building chips. This constructor instantiates a module specified by the BuildSystem parameter, - * named "system", which is an instance of DigitalTop by default. The default clock and reset for "system" are set by two - * wires, "systemClock" and "systemReset", which are intended to be driven by traits mixed-in with this base class. + * named "system", which is an instance of DigitalTop by default. The diplomatic clocks of System, as well as its implicit clock, + * is aggregated into the clockGroupNode. The parameterized functions controlled by ClockingSchemeKey and GlobalResetSchemeKey + * drive clock and reset generation */ -abstract class BaseChipTop()(implicit val p: Parameters) extends RawModule with HasTestHarnessFunctions { +class ChipTop(implicit p: Parameters) extends LazyModule with HasTestHarnessFunctions { // A publicly accessible list of IO cells (useful for a floorplanning tool, for example) val iocells = ArrayBuffer.empty[IOCell] - // A list of functions to call in the test harness - val harnessFunctions = ArrayBuffer.empty[TestHarnessFunction] - // The system clock - // These are given so that IOCell can use DataMirror and generate ports with - // the right flow (Input/Output) - val systemClock = Wire(Input(Clock())) - val systemReset = Wire(Input(Reset())) // The system module specified by BuildSystem - val lSystem = p(BuildSystem)(p).suggestName("system") - val system = withClockAndReset(systemClock, systemReset) { Module(lSystem.module) } + val lazySystem = LazyModule(p(BuildSystem)(p)).suggestName("system") - // Call all of the IOBinders and provide them with a default clock and reset - withClockAndReset(systemClock, systemReset) { - // Call each IOBinder on both the lazyModule instance and the module - // instance. Generally, an IOBinder PF should only be defined on one, so - // this should not lead to two invocations. - val (_ports, _iocells, _harnessFunctions) = p(IOBinders).values.flatMap(f => f(lSystem) ++ f(system)).unzip3 + // The implicitClockSinkNode provides the implicit clock and reset for the System + val implicitClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters())) + + // Generate Clocks and Reset + p(ClockingSchemeKey)(this) + + // NOTE: Making this a LazyRawModule is moderately dangerous, as anonymous children + // of ChipTop (ex: ClockGroup) do not receive clock or reset. + // However. anonymous children of ChipTop should not need an implicit Clock or Reset + // anyways, they probably need to be explicitly clocked. + lazy val module: LazyModuleImpLike = new LazyRawModuleImp(this) { + // These become the implicit clock and reset to the System + val implicit_clock = implicitClockSinkNode.in.head._1.clock + val implicit_reset = implicitClockSinkNode.in.head._1.reset + + + // Note: IOBinders cannot rely on the implicit clock/reset, as this is a LazyRawModuleImp + val (_ports, _iocells, _portMap) = ApplyIOBinders(lazySystem, p(IOBinders)) // We ignore _ports for now... - iocells ++= _iocells.flatten - harnessFunctions ++= _harnessFunctions.flatten - } + iocells ++= _iocells + portMap ++= _portMap + // Connect the implicit clock/reset, if present + lazySystem.module match { case l: LazyModuleImp => { + l.clock := implicit_clock + l.reset := implicit_reset + }} + } } -/** - * A simple clock and reset implementation that punches out clock and reset ports with the same - * names as the implicit clock and reset for standard Module classes. Three basic reset schemes - * are provided. See [[GlobalResetScheme]]. - */ -trait HasChipTopSimpleClockAndReset { this: BaseChipTop => - - val (clock, systemClockIO) = IOCell.generateIOFromSignal(systemClock, Some("iocell_clock")) - val (reset, systemResetIO) = p(GlobalResetSchemeKey) match { - case GlobalResetSynchronous => - IOCell.generateIOFromSignal(systemReset, Some("iocell_reset")) - case GlobalResetAsynchronousFull => - IOCell.generateIOFromSignal(systemReset, Some("iocell_reset"), abstractResetAsAsync = true) - case GlobalResetAsynchronous => - val asyncResetCore = Wire(Input(AsyncReset())) - systemReset := ResetCatchAndSync(systemClock, asyncResetCore.asBool) - IOCell.generateIOFromSignal(asyncResetCore, Some("iocell_reset"), abstractResetAsAsync = true) - } - - iocells ++= systemClockIO - iocells ++= systemResetIO - - // Add a TestHarnessFunction that connects clock and reset - harnessFunctions += { (th: TestHarness) => { - // Connect clock; it's not done implicitly with RawModule - clock := th.clock - // Connect reset; it's not done implicitly with RawModule - // Note that we need to use dutReset, not harnessReset - reset := th.dutReset - Nil - } } - -} - -class ChipTop()(implicit p: Parameters) extends BaseChipTop()(p) - with HasChipTopSimpleClockAndReset diff --git a/generators/chipyard/src/main/scala/Clocks.scala b/generators/chipyard/src/main/scala/Clocks.scala new file mode 100644 index 00000000..38ab105a --- /dev/null +++ b/generators/chipyard/src/main/scala/Clocks.scala @@ -0,0 +1,175 @@ +package chipyard + +import chisel3._ + +import scala.collection.mutable.{ArrayBuffer} + +import freechips.rocketchip.prci._ +import freechips.rocketchip.subsystem.{BaseSubsystem, SubsystemDriveAsyncClockGroupsKey} +import freechips.rocketchip.config.{Parameters, Field} +import freechips.rocketchip.diplomacy.{OutwardNodeHandle, InModuleBody, LazyModule} +import freechips.rocketchip.util.{ResetCatchAndSync, Pow2ClockDivider} + +import barstools.iocell.chisel._ + +/** + * Chipyard provides three baseline, top-level reset schemes, set using the + * [[GlobalResetSchemeKey]] in a Parameters instance. These are: + * + * 1) Synchronous: The input coming to the chip is synchronous to the provided + * clocks and will be used without modification as a synchronous reset. + * This is safe only for use in FireSim and SW simulation. + * + * 2) Asynchronous: The input reset is asynchronous to the input clock, but it + * is caught and synchronized to that clock before it is dissemenated. + * Thus, downsteam modules will be emitted with synchronously reset state + * elements. + * + * 3) Asynchronous Full: The input reset is asynchronous to the input clock, + * and is used globally as an async reset. Downstream modules will be emitted + * with asynchronously reset state elements. + * + */ +sealed trait GlobalResetScheme { + def pinIsAsync: Boolean +} +sealed trait HasAsyncInput { self: GlobalResetScheme => + def pinIsAsync = true +} + +sealed trait HasSyncInput { self: GlobalResetScheme => + def pinIsAsync = false +} + +case object GlobalResetSynchronous extends GlobalResetScheme with HasSyncInput +case object GlobalResetAsynchronous extends GlobalResetScheme with HasAsyncInput +case object GlobalResetAsynchronousFull extends GlobalResetScheme with HasAsyncInput +case object GlobalResetSchemeKey extends Field[GlobalResetScheme](GlobalResetSynchronous) + +/** + * A simple reset implementation that punches out reset ports + * for standard Module classes. Three basic reset schemes + * are provided. See [[GlobalResetScheme]]. + */ +object GenerateReset { + def apply(chiptop: ChipTop, clock: Clock): Reset = { + implicit val p = chiptop.p + // this needs directionality so generateIOFromSignal works + val reset_wire = Wire(Input(Reset())) + val (reset_io, resetIOCell) = p(GlobalResetSchemeKey) match { + case GlobalResetSynchronous => + IOCell.generateIOFromSignal(reset_wire, "reset") + case GlobalResetAsynchronousFull => + IOCell.generateIOFromSignal(reset_wire, "reset", abstractResetAsAsync = true) + case GlobalResetAsynchronous => { + val async_reset_wire = Wire(Input(AsyncReset())) + reset_wire := ResetCatchAndSync(clock, async_reset_wire.asBool()) + IOCell.generateIOFromSignal(async_reset_wire, "reset", abstractResetAsAsync = true) + } + } + chiptop.iocells ++= resetIOCell + chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => { + reset_io := th.dutReset + Nil + }) + reset_wire + } +} + + +case object ClockingSchemeKey extends Field[ChipTop => Unit](ClockingSchemeGenerators.harnessClock) + + + +object ClockingSchemeGenerators { + // A simple clock provider, for testing + val harnessClock: ChipTop => Unit = { chiptop => + implicit val p = chiptop.p + + val implicitClockSourceNode = ClockSourceNode(Seq(ClockSourceParameters())) + chiptop.implicitClockSinkNode := implicitClockSourceNode + + // Drive the diplomaticclock graph of the DigitalTop (if present) + val simpleClockGroupSourceNode = chiptop.lazySystem match { + case l: BaseSubsystem if (p(SubsystemDriveAsyncClockGroupsKey).isEmpty) => { + val n = ClockGroupSourceNode(Seq(ClockGroupSourceParameters())) + l.asyncClockGroupsNode := n + Some(n) + } + case _ => None + } + + InModuleBody { + //this needs directionality so generateIOFromSignal works + val clock_wire = Wire(Input(Clock())) + val reset_wire = GenerateReset(chiptop, clock_wire) + val (clock_io, clockIOCell) = IOCell.generateIOFromSignal(clock_wire, "clock") + chiptop.iocells ++= clockIOCell + + implicitClockSourceNode.out.unzip._1.map { o => + o.clock := clock_wire + o.reset := reset_wire + } + + simpleClockGroupSourceNode.map { n => n.out.unzip._1.map { out: ClockGroupBundle => + out.member.data.foreach { o => + o.clock := clock_wire + o.reset := reset_wire + } + }} + + chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => { + clock_io := th.harnessClock + Nil + }) + } + + } + + + val harnessDividedClock: ChipTop => Unit = { chiptop => + implicit val p = chiptop.p + + require(false, "Divided clock is broken until we fix passing onchip clocks to TestHarness objects") + + val implicitClockSourceNode = ClockSourceNode(Seq(ClockSourceParameters())) + chiptop.implicitClockSinkNode := implicitClockSourceNode + + val simpleClockGroupSourceNode = chiptop.lazySystem match { + case l: BaseSubsystem if (p(SubsystemDriveAsyncClockGroupsKey).isEmpty) => { + val n = ClockGroupSourceNode(Seq(ClockGroupSourceParameters())) + l.asyncClockGroupsNode := n + Some(n) + } + case _ => throw new Exception("Harness multiclock assumes BaseSubsystem") + } + + InModuleBody { + // this needs directionality so generateIOFromSignal works + val clock_wire = Wire(Input(Clock())) + val reset_wire = GenerateReset(chiptop, clock_wire) + val (clock_io, clockIOCell) = IOCell.generateIOFromSignal(clock_wire, "clock") + chiptop.iocells ++= clockIOCell + val div_clock = Pow2ClockDivider(clock_wire, 2) + + implicitClockSourceNode.out.unzip._1.map { o => + o.clock := div_clock + o.reset := reset_wire + } + + simpleClockGroupSourceNode.map { n => n.out.unzip._1.map { out: ClockGroupBundle => + out.member.elements.map { case (name, data) => + // This is mega hacks, how are you actually supposed to do this? + data.clock := (if (name.contains("core")) clock_wire else div_clock) + data.reset := reset_wire + } + }} + + chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => { + clock_io := th.harnessClock + Nil + }) + } + + } +} diff --git a/generators/chipyard/src/main/scala/ConfigFragments.scala b/generators/chipyard/src/main/scala/ConfigFragments.scala index 9bbb6cc0..cfa465e7 100644 --- a/generators/chipyard/src/main/scala/ConfigFragments.scala +++ b/generators/chipyard/src/main/scala/ConfigFragments.scala @@ -6,12 +6,13 @@ import chisel3.util.{log2Up} import freechips.rocketchip.config.{Field, Parameters, Config} import freechips.rocketchip.subsystem._ import freechips.rocketchip.diplomacy.{LazyModule, ValName} -import freechips.rocketchip.devices.tilelink.BootROMParams -import freechips.rocketchip.devices.debug.{Debug} +import freechips.rocketchip.devices.tilelink.{BootROMLocated} +import freechips.rocketchip.devices.debug.{Debug, ExportDebug, DebugModuleKey, DMI} import freechips.rocketchip.groundtest.{GroundTestSubsystem} import freechips.rocketchip.tile._ import freechips.rocketchip.rocket.{RocketCoreParams, MulDivParams, DCacheParams, ICacheParams} import freechips.rocketchip.util.{AsyncResetReg} +import freechips.rocketchip.prci._ import testchipip._ import tracegen.{TraceGenSystem} @@ -25,23 +26,15 @@ import sifive.blocks.devices.gpio._ import sifive.blocks.devices.uart._ import sifive.blocks.devices.spi._ -import chipyard.{BuildTop, BuildSystem, TestSuitesKey, TestSuiteHelper} +import chipyard.{BuildTop, BuildSystem, ClockingSchemeGenerators, ClockingSchemeKey, TestSuitesKey, TestSuiteHelper} -/** - * TODO: Why do we need this? - */ -object ConfigValName { - implicit val valName = ValName("TestHarness") -} -import ConfigValName._ // ----------------------- // Common Config Fragments // ----------------------- class WithBootROM extends Config((site, here, up) => { - case BootROMParams => BootROMParams( - contentFileName = s"./bootrom/bootrom.rv${site(XLen)}.img") + case BootROMLocated(x) => up(BootROMLocated(x), site).map(_.copy(contentFileName = s"./bootrom/bootrom.rv${site(XLen)}.img")) }) // DOC include start: gpio config fragment @@ -73,7 +66,7 @@ class WithL2TLBs(entries: Int) extends Config((site, here, up) => { }) class WithTracegenSystem extends Config((site, here, up) => { - case BuildSystem => (p: Parameters) => LazyModule(new TraceGenSystem()(p)) + case BuildSystem => (p: Parameters) => new TraceGenSystem()(p) }) /** @@ -105,7 +98,8 @@ class WithMultiRoCCHwacha(harts: Int*) extends Config( case MultiRoCCKey => { up(MultiRoCCKey, site) ++ harts.distinct.map{ i => (i -> Seq((p: Parameters) => { - LazyModule(new Hwacha()(p)).suggestName("hwacha") + val hwacha = LazyModule(new Hwacha()(p)) + hwacha })) } } @@ -156,3 +150,23 @@ class WithHwachaTest extends Config((site, here, up) => { "SRC_EXTENSION = $(base_dir)/hwacha/$(src_path)/*.scala" + "\nDISASM_EXTENSION = --extension=hwacha" } }) + +// The default RocketChip BaseSubsystem drives its diplomatic clock graph +// with the implicit clocks of Subsystem. Don't do that, instead we extend +// the diplomacy graph upwards into the ChipTop, where we connect it to +// our clock drivers +class WithNoSubsystemDrivenClocks extends Config((site, here, up) => { + case SubsystemDriveAsyncClockGroupsKey => None +}) + +class WithTileDividedClock extends Config((site, here, up) => { + case ClockingSchemeKey => ClockingSchemeGenerators.harnessDividedClock +}) + +class WithDMIDTM extends Config((site, here, up) => { + case ExportDebug => up(ExportDebug, site).copy(protocols = Set(DMI)) +}) + +class WithNoDebug extends Config((site, here, up) => { + case DebugModuleKey => None +}) diff --git a/generators/chipyard/src/main/scala/DigitalTop.scala b/generators/chipyard/src/main/scala/DigitalTop.scala index 81d0003d..c0ac1ff7 100644 --- a/generators/chipyard/src/main/scala/DigitalTop.scala +++ b/generators/chipyard/src/main/scala/DigitalTop.scala @@ -16,7 +16,7 @@ class DigitalTop(implicit p: Parameters) extends ChipyardSystem with testchipip.CanHaveTraceIO // Enables optionally adding trace IO with testchipip.CanHaveBackingScratchpad // Enables optionally adding a backing scratchpad with testchipip.CanHavePeripheryBlockDevice // Enables optionally adding the block device - with testchipip.CanHavePeripherySerial // Enables optionally adding the TSI serial-adapter and port + with testchipip.CanHavePeripheryTLSerial // Enables optionally adding the backing memory and serial adapter with sifive.blocks.devices.uart.HasPeripheryUART // Enables optionally adding the sifive UART with sifive.blocks.devices.gpio.HasPeripheryGPIO // Enables optionally adding the sifive GPIOs with sifive.blocks.devices.spi.HasPeripherySPIFlash // Enables optionally adding the sifive SPI flash controller @@ -32,12 +32,9 @@ class DigitalTop(implicit p: Parameters) extends ChipyardSystem class DigitalTopModule[+L <: DigitalTop](l: L) extends ChipyardSystemModule(l) with testchipip.CanHaveTraceIOModuleImp - with testchipip.CanHavePeripheryBlockDeviceModuleImp - with testchipip.CanHavePeripherySerialModuleImp with sifive.blocks.devices.uart.HasPeripheryUARTModuleImp with sifive.blocks.devices.gpio.HasPeripheryGPIOModuleImp with sifive.blocks.devices.spi.HasPeripherySPIFlashModuleImp - with icenet.CanHavePeripheryIceNICModuleImp with chipyard.example.CanHavePeripheryGCDModuleImp with freechips.rocketchip.util.DontTouch // DOC include end: DigitalTop diff --git a/generators/chipyard/src/main/scala/HarnessBinders.scala b/generators/chipyard/src/main/scala/HarnessBinders.scala new file mode 100644 index 00000000..e5cfacfb --- /dev/null +++ b/generators/chipyard/src/main/scala/HarnessBinders.scala @@ -0,0 +1,259 @@ +package chipyard.harness + +import chisel3._ +import chisel3.experimental.{Analog} + +import freechips.rocketchip.config.{Field, Config, Parameters} +import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImpLike} +import freechips.rocketchip.amba.axi4.{AXI4Bundle, AXI4SlaveNode, AXI4MasterNode, AXI4EdgeParameters} +import freechips.rocketchip.devices.debug._ +import freechips.rocketchip.jtag.{JTAGIO} +import freechips.rocketchip.system.{SimAXIMem} +import freechips.rocketchip.subsystem._ + +import sifive.blocks.devices.gpio._ +import sifive.blocks.devices.uart._ +import sifive.blocks.devices.spi._ + +import barstools.iocell.chisel._ + +import testchipip._ + +import chipyard.HasHarnessSignalReferences +import chipyard.iobinders.GetSystemParameters + +import tracegen.{TraceGenSystemModuleImp} +import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvonly} + +import scala.reflect.{ClassTag} + +case object HarnessBinders extends Field[Map[String, (Any, HasHarnessSignalReferences, Seq[Data]) => Seq[Any]]]( + Map[String, (Any, HasHarnessSignalReferences, Seq[Data]) => Seq[Any]]().withDefaultValue((t: Any, th: HasHarnessSignalReferences, d: Seq[Data]) => Nil) +) + + +object ApplyHarnessBinders { + def apply(th: HasHarnessSignalReferences, sys: LazyModule, map: Map[String, (Any, HasHarnessSignalReferences, Seq[Data]) => Seq[Any]], portMap: Map[String, Seq[Data]]) = { + val pm = portMap.withDefaultValue(Nil) + map.map { case (s, f) => f(sys, th, pm(s)) ++ f(sys.module, th, pm(s)) } + } +} + +class OverrideHarnessBinder[T, S <: Data](fn: => (T, HasHarnessSignalReferences, Seq[S]) => Seq[Any])(implicit tag: ClassTag[T], ptag: ClassTag[S]) extends Config((site, here, up) => { + case HarnessBinders => up(HarnessBinders, site) + (tag.runtimeClass.toString -> + ((t: Any, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + val pts = ports.collect({case p: S => p}) + require (pts.length == ports.length, s"Port type mismatch between IOBinder and HarnessBinder: ${ptag}") + t match { + case system: T => fn(system, th, pts) + case _ => Nil + } + }) + ) +}) + +class ComposeHarnessBinder[T, S <: Data](fn: => (T, HasHarnessSignalReferences, Seq[S]) => Seq[Any])(implicit tag: ClassTag[T], ptag: ClassTag[S]) extends Config((site, here, up) => { + case HarnessBinders => up(HarnessBinders, site) + (tag.runtimeClass.toString -> + ((t: Any, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + val pts = ports.collect({case p: S => p}) + require (pts.length == ports.length, s"Port type mismatch between IOBinder and HarnessBinder: ${ptag}") + t match { + case system: T => up(HarnessBinders, site)(tag.runtimeClass.toString)(system, th, pts) ++ fn(system, th, pts) + case _ => Nil + } + }) + ) +}) + +class WithGPIOTiedOff extends OverrideHarnessBinder({ + (system: HasPeripheryGPIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[Analog]) => { + ports.foreach { _ <> AnalogConst(0) } + Nil + } +}) + +// DOC include start: WithUARTAdapter +class WithUARTAdapter extends OverrideHarnessBinder({ + (system: HasPeripheryUARTModuleImp, th: HasHarnessSignalReferences, ports: Seq[UARTPortIO]) => { + UARTAdapter.connect(ports)(system.p) + Nil + } +}) +// DOC include end: WithUARTAdapter + +class WithSimSPIFlashModel(rdOnly: Boolean = true) extends OverrideHarnessBinder({ + (system: HasPeripherySPIFlashModuleImp, th: HasHarnessSignalReferences, ports: Seq[SPIChipIO]) => { + SimSPIFlashModel.connect(ports, th.harnessReset, rdOnly)(system.p) + Nil + } +}) + +class WithSimBlockDevice extends OverrideHarnessBinder({ + (system: CanHavePeripheryBlockDevice, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => { + implicit val p: Parameters = GetSystemParameters(system) + ports.map { b => SimBlockDevice.connect(b.clock, th.harnessReset.asBool, Some(b.bits)) } + Nil + } +}) + +class WithBlockDeviceModel extends OverrideHarnessBinder({ + (system: CanHavePeripheryBlockDevice, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => { + implicit val p: Parameters = GetSystemParameters(system) + ports.map { b => withClockAndReset(b.clock, th.harnessReset) { BlockDeviceModel.connect(Some(b.bits)) } } + Nil + } +}) + +class WithLoopbackNIC extends OverrideHarnessBinder({ + (system: CanHavePeripheryIceNIC, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => { + implicit val p: Parameters = GetSystemParameters(system) + ports.map { n => + withClockAndReset(n.clock, th.harnessReset) { + NicLoopback.connect(Some(n.bits), p(NICKey)) + } + } + Nil + } +}) + +class WithSimNetwork extends OverrideHarnessBinder({ + (system: CanHavePeripheryIceNIC, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => { + implicit val p: Parameters = GetSystemParameters(system) + ports.map { n => SimNetwork.connect(Some(n.bits), n.clock, th.harnessReset.asBool) } + Nil + } +}) + +class WithSimAXIMem extends OverrideHarnessBinder({ + (system: CanHaveMasterAXI4MemPort, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => { + val p: Parameters = chipyard.iobinders.GetSystemParameters(system) + (ports zip system.memAXI4Node.edges.in).map { case (port, edge) => + val mem = LazyModule(new SimAXIMem(edge, size=p(ExtMem).get.master.size)(p)) + withClockAndReset(port.clock, th.harnessReset) { + Module(mem.module).suggestName("mem") + } + mem.io_axi4.head <> port.bits + } + Nil + } +}) + +class WithBlackBoxSimMem extends OverrideHarnessBinder({ + (system: CanHaveMasterAXI4MemPort, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => { + val p: Parameters = chipyard.iobinders.GetSystemParameters(system) + (ports zip system.memAXI4Node.edges.in).map { case (port, edge) => + val memSize = p(ExtMem).get.master.size + val lineSize = p(CacheBlockBytes) + val mem = Module(new SimDRAM(memSize, lineSize, edge.bundle)).suggestName("simdram") + mem.io.axi <> port.bits + mem.io.clock := port.clock + mem.io.reset := th.harnessReset + } + Nil + } +}) + +class WithSimAXIMMIO extends OverrideHarnessBinder({ + (system: CanHaveMasterAXI4MMIOPort, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => { + val p: Parameters = chipyard.iobinders.GetSystemParameters(system) + (ports zip system.mmioAXI4Node.edges.in).map { case (port, edge) => + val mmio_mem = LazyModule(new SimAXIMem(edge, size = p(ExtBus).get.size)(p)) + withClockAndReset(port.clock, th.harnessReset) { + Module(mmio_mem.module).suggestName("mmio_mem") + } + mmio_mem.io_axi4.head <> port.bits + } + Nil + } +}) + +class WithTieOffInterrupts extends OverrideHarnessBinder({ + (system: HasExtInterruptsModuleImp, th: HasHarnessSignalReferences, ports: Seq[UInt]) => { + ports.foreach { _ := 0.U } + Nil + } +}) + +class WithTieOffL2FBusAXI extends OverrideHarnessBinder({ + (system: CanHaveSlaveAXI4Port, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => { + ports.foreach({ p => p := DontCare; p.bits.tieoff() }) + Nil + } +}) + +class WithSimDebug extends OverrideHarnessBinder({ + (system: HasPeripheryDebugModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + ports.map { + case d: ClockedDMIIO => + val dtm_success = WireInit(false.B) + when (dtm_success) { th.success := true.B } + val dtm = Module(new SimDTM()(system.p)).connect(th.harnessClock, th.harnessReset.asBool, d, dtm_success) + case j: JTAGIO => + val dtm_success = WireInit(false.B) + when (dtm_success) { th.success := true.B } + val jtag = Module(new SimJTAG(tickDelay=3)).connect(j, th.harnessClock, th.harnessReset.asBool, ~(th.harnessReset.asBool), dtm_success) + } + Nil + } +}) + +class WithTiedOffDebug extends OverrideHarnessBinder({ + (system: HasPeripheryDebugModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + ports.map { + case j: JTAGIO => + j.TCK := true.B.asClock + j.TMS := true.B + j.TDI := true.B + j.TRSTn.foreach { r => r := true.B } + case d: ClockedDMIIO => + d.dmi.req.valid := false.B + d.dmi.req.bits := DontCare + d.dmi.resp.ready := true.B + d.dmiClock := false.B.asClock + d.dmiReset := true.B + case a: ClockedAPBBundle => + a.tieoff() + a.clock := false.B.asClock + a.reset := true.B.asAsyncReset + a.psel := false.B + a.penable := false.B + } + Nil + } +}) + + +class WithSerialAdapterTiedOff extends OverrideHarnessBinder({ + (system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => { + implicit val p = chipyard.iobinders.GetSystemParameters(system) + ports.map({ port => + val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, port, th.harnessReset) + SerialAdapter.tieoff(ram.module.io.tsi_ser) + }) + } +}) + +class WithSimSerial extends OverrideHarnessBinder({ + (system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => { + implicit val p = chipyard.iobinders.GetSystemParameters(system) + ports.map({ port => + val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, port, th.harnessReset) + val success = SerialAdapter.connectSimSerial(ram.module.io.tsi_ser, port.clock, th.harnessReset.asBool) + when (success) { th.success := true.B } + }) + } +}) + +class WithTraceGenSuccess extends OverrideHarnessBinder({ + (system: TraceGenSystemModuleImp, th: HasHarnessSignalReferences, ports: Seq[Bool]) => { + ports.map { p => when (p) { th.success := true.B } } + Nil + } +}) + +class WithSimDromajoBridge extends ComposeHarnessBinder({ + (system: CanHaveTraceIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[TraceOutputTop]) => { + ports.map { p => p.traces.map(tileTrace => SimDromajoBridge(tileTrace)(system.p)) } + Nil + } +}) diff --git a/generators/chipyard/src/main/scala/IOBinders.scala b/generators/chipyard/src/main/scala/IOBinders.scala index 115723ab..4a31e2c0 100644 --- a/generators/chipyard/src/main/scala/IOBinders.scala +++ b/generators/chipyard/src/main/scala/IOBinders.scala @@ -1,12 +1,13 @@ -package chipyard -package object iobinders { +package chipyard.iobinders import chisel3._ -import chisel3.experimental.{Analog, IO} +import chisel3.util.experimental.{BoringUtils} +import chisel3.experimental.{Analog, IO, DataMirror} -import freechips.rocketchip.config.{Field, Config, Parameters} +import freechips.rocketchip.config._ import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImpLike} import freechips.rocketchip.devices.debug._ +import freechips.rocketchip.jtag.{JTAGIO} import freechips.rocketchip.subsystem._ import freechips.rocketchip.system.{SimAXIMem} import freechips.rocketchip.amba.axi4.{AXI4Bundle, AXI4SlaveNode, AXI4MasterNode, AXI4EdgeParameters} @@ -21,7 +22,9 @@ import tracegen.{TraceGenSystemModuleImp} import barstools.iocell.chisel._ import testchipip._ -import icenet.{CanHavePeripheryIceNICModuleImp, SimNetwork, NicLoopback, NICKey} +import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvonly} + +import chipyard.GlobalResetSchemeKey import scala.reflect.{ClassTag} @@ -37,20 +40,22 @@ import scala.reflect.{ClassTag} // You can add your own binder by adding a new (key, fn) pair, typically by using // the OverrideIOBinder or ComposeIOBinder macros - - -// DOC include start: IOBinders -// This type describes a function callable on the TestHarness instance. Its return type is unused. -type TestHarnessFunction = (chipyard.TestHarness) => Seq[Any] -// IOBinders will return a Seq of this tuple, which contains three fields: -// 1. A Seq containing all IO ports created by the IOBinder function -// 2. A Seq containing all IO cell modules created by the IOBinder function -// 3. An optional function to call inside the test harness (e.g. to connect the IOs) -type IOBinderTuple = (Seq[Data], Seq[IOCell], Option[TestHarnessFunction]) - -case object IOBinders extends Field[Map[String, (Any) => Seq[IOBinderTuple]]]( - Map[String, (Any) => Seq[IOBinderTuple]]().withDefaultValue((Any) => Nil) +case object IOBinders extends Field[Map[String, (Any) => (Seq[Data], Seq[IOCell])]]( + Map[String, (Any) => (Seq[Data], Seq[IOCell])]().withDefaultValue((Any) => (Nil, Nil)) ) +object ApplyIOBinders { + def apply(sys: LazyModule, map: Map[String, (Any) => (Seq[Data], Seq[IOCell])]): + (Iterable[Data], Iterable[IOCell], Map[String, Seq[Data]]) = { + val lzy = map.map({ case (s,f) => s -> f(sys) }) + val imp = map.map({ case (s,f) => s -> f(sys.module) }) + val unzipped = (lzy.values ++ imp.values).unzip + + val ports: Iterable[Data] = unzipped._1.flatten + val cells: Iterable[IOCell] = unzipped._2.flatten + val portMap: Map[String, Seq[Data]] = map.keys.map(k => k -> (lzy(k)._1 ++ imp(k)._1)).toMap + (ports, cells, portMap) + } +} // Note: The parameters instance is accessible only through LazyModule // or LazyModuleImpLike. The self-type requirement in traits like @@ -67,14 +72,18 @@ object GetSystemParameters { } } +class IOBinder(f: (View, View, View) => PartialFunction[Any, Any]) extends Config(f) + // This macro overrides previous matches on some Top mixin. This is useful for // binders which drive IO, since those typically cannot be composed -class OverrideIOBinder[T](fn: => (T) => Seq[IOBinderTuple])(implicit tag: ClassTag[T]) extends Config((site, here, up) => { +class OverrideIOBinder[T, S <: Data](fn: => (T) => (Seq[S], Seq[IOCell]))(implicit tag: ClassTag[T]) extends IOBinder((site, here, up) => { case IOBinders => up(IOBinders, site) + (tag.runtimeClass.toString -> ((t: Any) => { t match { - case system: T => fn(system) - case _ => Nil + case system: T => + val (ports, cells) = fn(system) + (ports, cells) + case _ => (Nil, Nil) } }) ) @@ -82,32 +91,44 @@ class OverrideIOBinder[T](fn: => (T) => Seq[IOBinderTuple])(implicit tag: ClassT // This macro composes with previous matches on some Top mixin. This is useful for // annotation-like binders, since those can typically be composed -class ComposeIOBinder[T](fn: => (T) => Seq[IOBinderTuple])(implicit tag: ClassTag[T]) extends Config((site, here, up) => { +class ComposeIOBinder[T, S <: Data](fn: => (T) => (Seq[S], Seq[IOCell]))(implicit tag: ClassTag[T]) extends IOBinder((site, here, up) => { case IOBinders => up(IOBinders, site) + (tag.runtimeClass.toString -> ((t: Any) => { t match { - case system: T => (up(IOBinders, site)(tag.runtimeClass.toString)(system) - ++ fn(system)) - case _ => Nil + case system: T => + val r = up(IOBinders, site)(tag.runtimeClass.toString)(system) + val h = fn(system) + val ports = r._1 ++ h._1 + val cells = r._2 ++ h._2 + (ports, cells) + case _ => (Nil, Nil) } }) ) }) -// DOC include end: IOBinders +object BoreHelper { + def apply(name: String, source: Clock): Clock = { + val clock_io = IO(Output(Clock())).suggestName(name) + val clock_wire = Wire(Clock()).suggestName(s"chiptop_${name}") + dontTouch(clock_wire) + clock_wire := false.B.asClock // necessary for BoringUtils to work properly + BoringUtils.bore(source, Seq(clock_wire)) + clock_io := clock_wire + clock_io + } +} -object AddIOCells { - /** - * Add IO cells to a SiFive GPIO devices and name the IO ports. - * @param gpios A Seq of GPIO port bundles - * @param genFn A callable function to generate a DigitalGPIOCell module to use - * @return Returns a tuple of (a 2D Seq of Analog IOs corresponding to individual GPIO pins; a 2D Seq of IOCell module references) - */ - def gpio(gpios: Seq[GPIOPortIO], genFn: () => DigitalGPIOCell = IOCell.genericGPIO): (Seq[Seq[Analog]], Seq[Seq[IOCell]]) = { - gpios.zipWithIndex.map({ case (gpio, i) => + +case object IOCellKey extends Field[IOCellTypeParams](GenericIOCellParams()) + + +class WithGPIOCells extends OverrideIOBinder({ + (system: HasPeripheryGPIOModuleImp) => { + val (ports2d, cells2d) = system.gpio.zipWithIndex.map({ case (gpio, i) => gpio.pins.zipWithIndex.map({ case (pin, j) => val g = IO(Analog(1.W)).suggestName(s"gpio_${i}_${j}") - val iocell = genFn().suggestName(s"iocell_gpio_${i}_${j}") + val iocell = system.p(IOCellKey).gpio().suggestName(s"iocell_gpio_${i}_${j}") iocell.io.o := pin.o.oval iocell.io.oe := pin.o.oe iocell.io.ie := pin.o.ie @@ -116,40 +137,37 @@ object AddIOCells { (g, iocell) }).unzip }).unzip + val ports: Seq[Analog] = ports2d.flatten + (ports, cells2d.flatten) } +}) - /** - * Add IO cells to a SiFive UART devices and name the IO ports. - * @param uartPins A Seq of UART port bundles - * @return Returns a tuple of (A Seq of top-level UARTPortIO IOs; a 2D Seq of IOCell module references) - */ - def uart(uartPins: Seq[UARTPortIO]): (Seq[UARTPortIO], Seq[Seq[IOCell]]) = { - uartPins.zipWithIndex.map({ case (u, i) => - val (port, ios) = IOCell.generateIOFromSignal(u, Some(s"iocell_uart_${i}")) - port.suggestName(s"uart_${i}") +// DOC include start: WithUARTIOCells +class WithUARTIOCells extends OverrideIOBinder({ + (system: HasPeripheryUARTModuleImp) => { + val (ports: Seq[UARTPortIO], cells2d) = system.uart.zipWithIndex.map({ case (u, i) => + val (port, ios) = IOCell.generateIOFromSignal(u, s"uart_${i}", system.p(IOCellKey)) (port, ios) }).unzip + (ports, cells2d.flatten) } +}) +// DOC include end: WithUARTIOCells - /** - * Add IO cells to a SiFive SPI devices and name the IO ports. - * @param spiPins A Seq of SPI port bundles - * @param basename The base name for this port (defaults to "spi") - * @param genFn A callable function to generate a DigitalGPIOCell module to use - * @return Returns a tuple of (A Seq of top-level SPIChipIO IOs; a 2D Seq of IOCell module references) - */ - def spi(spiPins: Seq[SPIPortIO], basename: String = "spi", genFn: () => DigitalGPIOCell = IOCell.genericGPIO): (Seq[SPIChipIO], Seq[Seq[IOCell]]) = { - spiPins.zipWithIndex.map({ case (s, i) => - val port = IO(new SPIChipIO(s.c.csWidth)).suggestName(s"${basename}_${i}") - val iocellBase = s"iocell_${basename}_${i}" +class WithSPIIOCells extends OverrideIOBinder({ + (system: HasPeripherySPIFlashModuleImp) => { + val (ports: Seq[SPIChipIO], cells2d) = system.qspi.zipWithIndex.map({ case (s, i) => + val name = s"spi_${i}" + val port = IO(new SPIChipIO(s.c.csWidth)).suggestName(name) + val iocellBase = s"iocell_${name}" // SCK and CS are unidirectional outputs - val sckIOs = IOCell.generateFromSignal(s.sck, port.sck, Some(s"${iocellBase}_sck")) - val csIOs = IOCell.generateFromSignal(s.cs, port.cs, Some(s"${iocellBase}_cs")) + val sckIOs = IOCell.generateFromSignal(s.sck, port.sck, Some(s"${iocellBase}_sck"), system.p(IOCellKey)) + val csIOs = IOCell.generateFromSignal(s.cs, port.cs, Some(s"${iocellBase}_cs"), system.p(IOCellKey)) // DQ are bidirectional, so then need special treatment val dqIOs = s.dq.zip(port.dq).zipWithIndex.map { case ((pin, ana), j) => - val iocell = genFn().suggestName(s"${iocellBase}_dq_${j}") + val iocell = system.p(IOCellKey).gpio().suggestName(s"${iocellBase}_dq_${j}") iocell.io.o := pin.o iocell.io.oe := pin.oe iocell.io.ie := true.B @@ -160,279 +178,162 @@ object AddIOCells { (port, dqIOs ++ csIOs ++ sckIOs) }).unzip - } - - /** - * Add IO cells to a debug module and name the IO ports. - * @param psd A PSDIO bundle - * @param resetctrlOpt An optional ResetCtrlIO bundle - * @param debugOpt An optional DebugIO bundle - * @return Returns a tuple3 of (Top-level PSDIO IO; Optional top-level DebugIO IO; a list of IOCell module references) - */ - def debug(psd: PSDIO, resetctrlOpt: Option[ResetCtrlIO], debugOpt: Option[DebugIO])(implicit p: Parameters): - (PSDIO, Option[ResetCtrlIO], Option[DebugIO], Seq[IOCell]) = { - val (psdPort, psdIOs) = IOCell.generateIOFromSignal( - psd, Some("iocell_psd"), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync) - val debugTuple = debugOpt.map(d => - IOCell.generateIOFromSignal(d, Some("iocell_debug"), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync)) - val debugPortOpt: Option[DebugIO] = debugTuple.map(_._1) - val debugIOs: Seq[IOCell] = debugTuple.map(_._2).toSeq.flatten - debugPortOpt.foreach(_.suggestName("debug")) - - val resetctrlTuple = resetctrlOpt.map(d => - IOCell.generateIOFromSignal(d, Some("iocell_resetctrl"), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync)) - val resetctrlPortOpt: Option[ResetCtrlIO] = resetctrlTuple.map(_._1) - val resetctrlIOs: Seq[IOCell] = resetctrlTuple.map(_._2).toSeq.flatten - resetctrlPortOpt.foreach(_.suggestName("resetctrl")) - - psdPort.suggestName("psd") - (psdPort, resetctrlPortOpt, debugPortOpt, psdIOs ++ debugIOs ++ resetctrlIOs) - } - - /** - * Add IO cells to a serial module and name the IO ports. - * @param serial A SerialIO bundle - * @return Returns a tuple of (Top-level SerialIO IO; a list of IOCell module references) - */ - def serial(serial: SerialIO): (SerialIO, Seq[IOCell]) = { - val (port, ios) = IOCell.generateIOFromSignal(serial, Some("iocell_serial")) - port.suggestName("serial") - (port, ios) - } - - def axi4(io: Seq[AXI4Bundle], node: AXI4SlaveNode, name: String): Seq[(AXI4Bundle, AXI4EdgeParameters, Seq[IOCell])] = { - io.zip(node.in).zipWithIndex.map{ case ((mem_axi4, (_, edge)), i) => { - val (port, ios) = IOCell.generateIOFromSignal(mem_axi4, Some(s"iocell_${name}_axi4_slave_${i}")) - port.suggestName(s"${name}_axi4_slave_${i}") - (port, edge, ios) - }} - } - def axi4(io: Seq[AXI4Bundle], node: AXI4MasterNode, name: String): Seq[(AXI4Bundle, AXI4EdgeParameters, Seq[IOCell])] = { - io.zip(node.out).zipWithIndex.map{ case ((mem_axi4, (_, edge)), i) => { - //val (port, ios) = IOCell.generateIOFromSignal(mem_axi4, Some(s"iocell_${name}_axi4_master_${i}")) - val port = IO(Flipped(AXI4Bundle(edge.bundle))) - val ios = IOCell.generateFromSignal(mem_axi4, port, Some(s"iocell_${name}_axi4_master_${i}")) - port.suggestName(s"${name}_axi4_master_${i}") - (port, edge, ios) - }} - } - - def blockDev(bdev: BlockDeviceIO): (BlockDeviceIO, Seq[IOCell]) = { - val (port, ios) = IOCell.generateIOFromSignal(bdev, Some("iocell_bdev")) - port.suggestName("bdev") - (port, ios) - } -} - -// DOC include start: WithGPIOTiedOff -class WithGPIOTiedOff extends OverrideIOBinder({ - (system: HasPeripheryGPIOModuleImp) => { - val (ports2d, ioCells2d) = AddIOCells.gpio(system.gpio) - val harnessFn = (th: chipyard.TestHarness) => { ports2d.flatten.foreach(_ <> AnalogConst(0)); Nil } - Seq((ports2d.flatten, ioCells2d.flatten, Some(harnessFn))) - } -}) -// DOC include end: WithGPIOTiedOff - -class WithUARTAdapter extends OverrideIOBinder({ - (system: HasPeripheryUARTModuleImp) => { - val (ports, ioCells2d) = AddIOCells.uart(system.uart) - val harnessFn = (th: chipyard.TestHarness) => { UARTAdapter.connect(ports)(system.p); Nil } - Seq((ports, ioCells2d.flatten, Some(harnessFn))) + (ports, cells2d.flatten) } }) -class WithSimSPIFlashModel(rdOnly: Boolean = true) extends OverrideIOBinder({ - (system: HasPeripherySPIFlashModuleImp) => { - val (ports, ioCells2d) = AddIOCells.spi(system.qspi, "qspi") - val harnessFn = (th: chipyard.TestHarness) => { SimSPIFlashModel.connect(ports, th.reset, rdOnly)(system.p); Nil } - Seq((ports, ioCells2d.flatten, Some(harnessFn))) - } -}) - -class WithSimBlockDevice extends OverrideIOBinder({ - (system: CanHavePeripheryBlockDeviceModuleImp) => system.bdev.map { bdev => - val (port, ios) = AddIOCells.blockDev(bdev) - val harnessFn = (th: chipyard.TestHarness) => { - SimBlockDevice.connect(th.clock, th.reset.asBool, Some(port))(system.p) - Nil +class WithExtInterruptIOCells extends OverrideIOBinder({ + (system: HasExtInterruptsModuleImp) => { + if (system.outer.nExtInterrupts > 0) { + val (port: UInt, cells) = IOCell.generateIOFromSignal(system.interrupts, "ext_interrupts", system.p(IOCellKey)) + (Seq(port), cells) + } else { + (Nil, Nil) } - Seq((Seq(port), ios, Some(harnessFn))) - }.getOrElse(Nil) + } }) -class WithBlockDeviceModel extends OverrideIOBinder({ - (system: CanHavePeripheryBlockDeviceModuleImp) => system.bdev.map { bdev => - val (port, ios) = AddIOCells.blockDev(bdev) - val harnessFn = (th: chipyard.TestHarness) => { - BlockDeviceModel.connect(Some(port))(system.p) - Nil - } - Seq((Seq(port), ios, Some(harnessFn))) - }.getOrElse(Nil) -}) -class WithLoopbackNIC extends OverrideIOBinder({ - (system: CanHavePeripheryIceNICModuleImp) => system.connectNicLoopback(); Nil -}) +class WithDebugIOCells extends OverrideIOBinder({ + (system: HasPeripheryDebugModuleImp) => { + system.debug.map({ debug => + val p = system.p + val tlbus = system.outer.asInstanceOf[BaseSubsystem].locateTLBusWrapper(p(ExportDebug).slaveWhere) + val debug_clock = Wire(Clock()).suggestName("debug_clock") + val debug_reset = Wire(Reset()).suggestName("debug_reset") + debug_clock := false.B.asClock // must provide default assignment to avoid firrtl unassigned error + debug_reset := false.B // must provide default assignment to avoid firrtl unassigned error + BoringUtils.bore(tlbus.module.clock, Seq(debug_clock)) + BoringUtils.bore(tlbus.module.reset, Seq(debug_reset)) -class WithSimNIC extends OverrideIOBinder({ - (system: CanHavePeripheryIceNICModuleImp) => system.connectSimNetwork(system.clock, system.reset.asBool); Nil -}) - -// DOC include start: WithSimAXIMem -class WithSimAXIMem extends OverrideIOBinder({ - (system: CanHaveMasterAXI4MemPort) => { - implicit val p: Parameters = GetSystemParameters(system) - val peiTuples = AddIOCells.axi4(system.mem_axi4, system.memAXI4Node, "mem") - // TODO: we are inlining the connectMem method of SimAXIMem because - // it takes in a dut rather than seq of axi4 ports - val harnessFn = (th: chipyard.TestHarness) => { - peiTuples.map { case (port, edge, ios) => - val mem = LazyModule(new SimAXIMem(edge, size = p(ExtMem).get.master.size)) - Module(mem.module).suggestName("mem") - mem.io_axi4.head <> port + // We never use the PSDIO, so tie it off on-chip + system.psd.psd.foreach { _ <> 0.U.asTypeOf(new PSDTestMode) } + system.resetctrl.map { rcio => rcio.hartIsInReset.map { _ := debug_reset.asBool } } + system.debug.map { d => + // Tie off extTrigger + d.extTrigger.foreach { t => + t.in.req := false.B + t.out.ack := t.out.req + } + // Tie off disableDebug + d.disableDebug.foreach { d => d := false.B } + // Drive JTAG on-chip IOs + d.systemjtag.map { j => + j.reset := debug_reset + j.mfr_id := system.p(JtagDTMKey).idcodeManufId.U(11.W) + j.part_number := system.p(JtagDTMKey).idcodePartNum.U(16.W) + j.version := system.p(JtagDTMKey).idcodeVersion.U(4.W) + } } - Nil - } - Seq((peiTuples.map(_._1), peiTuples.flatMap(_._3), Some(harnessFn))) - } -}) -// DOC include end: WithSimAXIMem + Debug.connectDebugClockAndReset(Some(debug), debug_clock)(system.p) -class WithBlackBoxSimMem extends OverrideIOBinder({ - (system: CanHaveMasterAXI4MemPort) => { - implicit val p: Parameters = GetSystemParameters(system) - val peiTuples = AddIOCells.axi4(system.mem_axi4, system.memAXI4Node, "mem") - val harnessFn = (th: chipyard.TestHarness) => { - peiTuples.map { case (port, edge, ios) => - val memSize = p(ExtMem).get.master.size - val lineSize = p(CacheBlockBytes) - val mem = Module(new SimDRAM(memSize, lineSize, edge.bundle)) - mem.io.axi <> port - mem.io.clock := th.clock - mem.io.reset := th.reset + // Add IOCells for the DMI/JTAG/APB ports + val dmiTuple = debug.clockeddmi.map { d => + IOCell.generateIOFromSignal(d, "dmi", p(IOCellKey), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync) } - Nil - } - Seq((peiTuples.map(_._1), peiTuples.flatMap(_._3), Some(harnessFn))) + + val jtagTuple = debug.systemjtag.map { j => + IOCell.generateIOFromSignal(j.jtag, "jtag", p(IOCellKey), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync) + } + + val apbTuple = debug.apb.map { a => + IOCell.generateIOFromSignal(a, "apb", p(IOCellKey), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync) + } + + val allTuples = (dmiTuple ++ jtagTuple ++ apbTuple).toSeq + (allTuples.map(_._1).toSeq, allTuples.flatMap(_._2).toSeq) + }).getOrElse((Nil, Nil)) } }) -class WithSimAXIMMIO extends OverrideIOBinder({ +class WithSerialTLIOCells extends OverrideIOBinder({ + (system: CanHavePeripheryTLSerial) => system.serial_tl.map({ s => + val sys = system.asInstanceOf[BaseSubsystem] + val (port, cells) = IOCell.generateIOFromSignal(s.getWrappedValue, "serial_tl", sys.p(IOCellKey)) + (Seq(port), cells) + }).getOrElse((Nil, Nil)) +}) + + +class WithAXI4MemPunchthrough extends OverrideIOBinder({ + (system: CanHaveMasterAXI4MemPort) => { + val ports: Seq[ClockedIO[AXI4Bundle]] = system.mem_axi4.zipWithIndex.map({ case (m, i) => + val p = IO(new ClockedIO(DataMirror.internal.chiselTypeClone[AXI4Bundle](m))).suggestName(s"axi4_mem_${i}") + p.bits <> m + p.clock := BoreHelper("axi4_mem_clock", system.asInstanceOf[BaseSubsystem].mbus.module.clock) + p + }) + (ports, Nil) + } +}) + +class WithAXI4MMIOPunchthrough extends OverrideIOBinder({ (system: CanHaveMasterAXI4MMIOPort) => { - implicit val p: Parameters = GetSystemParameters(system) - val peiTuples = AddIOCells.axi4(system.mmio_axi4, system.mmioAXI4Node, "mmio_mem") - val harnessFn = (th: chipyard.TestHarness) => { - peiTuples.zipWithIndex.map { case ((port, edge, ios), i) => - val mmio_mem = LazyModule(new SimAXIMem(edge, size = 4096)) - Module(mmio_mem.module).suggestName(s"mmio_mem_${i}") - mmio_mem.io_axi4.head <> port - } - Nil - } - Seq((peiTuples.map(_._1), peiTuples.flatMap(_._3), Some(harnessFn))) + val ports: Seq[ClockedIO[AXI4Bundle]] = system.mmio_axi4.zipWithIndex.map({ case (m, i) => + val p = IO(new ClockedIO(DataMirror.internal.chiselTypeClone[AXI4Bundle](m))).suggestName(s"axi4_mmio_${i}") + p.bits <> m + p.clock := BoreHelper("axi4_mmio_clock", system.asInstanceOf[BaseSubsystem].mbus.module.clock) + p + }) + (ports, Nil) } }) +class WithL2FBusAXI4Punchthrough extends OverrideIOBinder({ + (system: CanHaveSlaveAXI4Port) => { + val ports: Seq[ClockedIO[AXI4Bundle]] = system.l2_frontend_bus_axi4.zipWithIndex.map({ case (m, i) => + val p = IO(new ClockedIO(Flipped(DataMirror.internal.chiselTypeClone[AXI4Bundle](m)))).suggestName(s"axi4_fbus_${i}") + m <> p.bits + p.clock := BoreHelper("axi4_fbus_clock", system.asInstanceOf[BaseSubsystem].fbus.module.clock) + p + }) + (ports, Nil) + } +}) + +class WithBlockDeviceIOPunchthrough extends OverrideIOBinder({ + (system: CanHavePeripheryBlockDevice) => { + val ports: Seq[ClockedIO[BlockDeviceIO]] = system.bdev.map({ bdev => + val p = IO(new ClockedIO(new BlockDeviceIO()(GetSystemParameters(system)))).suggestName("blockdev") + p <> bdev + p + }).toSeq + (ports, Nil) + } +}) + +class WithNICIOPunchthrough extends OverrideIOBinder({ + (system: CanHavePeripheryIceNIC) => { + val ports: Seq[ClockedIO[NICIOvonly]] = system.icenicOpt.map({ n => + val p = IO(new ClockedIO(new NICIOvonly)).suggestName("nic") + p <> n + p + }).toSeq + (ports, Nil) + } +}) + +class WithTraceGenSuccessPunchthrough extends OverrideIOBinder({ + (system: TraceGenSystemModuleImp) => { + val success: Bool = IO(Output(Bool())).suggestName("success") + success := system.success + (Seq(success), Nil) + } +}) + +class WithTraceIOPunchthrough extends OverrideIOBinder({ + (system: CanHaveTraceIOModuleImp) => { + val ports: Option[TraceOutputTop] = system.traceIO.map { t => + val trace = IO(DataMirror.internal.chiselTypeClone[TraceOutputTop](t)).suggestName("trace") + trace <> t + trace + } + (ports.toSeq, Nil) + } +}) + + class WithDontTouchPorts extends OverrideIOBinder({ - (system: DontTouch) => system.dontTouchPorts(); Nil + (system: DontTouch) => system.dontTouchPorts(); (Nil, Nil) }) -class WithTieOffInterrupts extends OverrideIOBinder({ - (system: HasExtInterruptsModuleImp) => { - val (port, ioCells) = IOCell.generateIOFromSignal(system.interrupts, Some("iocell_interrupts")) - port.suggestName("interrupts") - val harnessFn = (th: chipyard.TestHarness) => { port := 0.U; Nil } - Seq((Seq(port), ioCells, Some(harnessFn))) - } -}) - -class WithTieOffL2FBusAXI extends OverrideIOBinder({ - (system: CanHaveSlaveAXI4Port) => { - val peiTuples = AddIOCells.axi4(system.l2_frontend_bus_axi4, system.l2FrontendAXI4Node, "l2_fbus") - val harnessFn = (th: chipyard.TestHarness) => { - peiTuples.zipWithIndex.map { case ((port, edge, ios), i) => - port := DontCare // tieoff doesn't completely tie-off, for some reason - port.tieoff() - } - Nil - } - Seq((peiTuples.map(_._1), peiTuples.flatMap(_._3), Some(harnessFn))) - } -}) - -class WithTiedOffDebug extends OverrideIOBinder({ - (system: HasPeripheryDebugModuleImp) => { - val (psdPort, resetctrlOpt, debugPortOpt, ioCells) = - AddIOCells.debug(system.psd, system.resetctrl, system.debug)(system.p) - val harnessFn = (th: chipyard.TestHarness) => { - Debug.tieoffDebug(debugPortOpt, resetctrlOpt, Some(psdPort))(system.p) - // tieoffDebug doesn't actually tie everything off :/ - debugPortOpt.foreach { d => - d.clockeddmi.foreach({ cdmi => cdmi.dmi.req.bits := DontCare; cdmi.dmiClock := th.clock }) - d.dmactiveAck := DontCare - d.clock := th.clock - } - Nil - } - Seq((Seq(psdPort) ++ resetctrlOpt ++ debugPortOpt.toSeq, Nil, Some(harnessFn))) - } -}) - -class WithSimDebug extends OverrideIOBinder({ - (system: HasPeripheryDebugModuleImp) => { - val (psdPort, resetctrlPortOpt, debugPortOpt, ioCells) = - AddIOCells.debug(system.psd, system.resetctrl, system.debug)(system.p) - val harnessFn = (th: chipyard.TestHarness) => { - val dtm_success = Wire(Bool()) - Debug.connectDebug(debugPortOpt, resetctrlPortOpt, psdPort, th.clock, th.harnessReset, dtm_success)(system.p) - when (dtm_success) { th.success := true.B } - th.dutReset := th.harnessReset | debugPortOpt.map { debug => AsyncResetReg(debug.ndreset).asBool }.getOrElse(false.B) - Nil - } - Seq((Seq(psdPort) ++ debugPortOpt.toSeq, ioCells, Some(harnessFn))) - } -}) - -class WithTiedOffSerial extends OverrideIOBinder({ - (system: CanHavePeripherySerialModuleImp) => system.serial.map({ serial => - val (port, ioCells) = AddIOCells.serial(serial) - val harnessFn = (th: chipyard.TestHarness) => { - SerialAdapter.tieoff(port) - Nil - } - Seq((Seq(port), ioCells, Some(harnessFn))) - }).getOrElse(Nil) -}) - -class WithSimSerial extends OverrideIOBinder({ - (system: CanHavePeripherySerialModuleImp) => system.serial.map({ serial => - val (port, ioCells) = AddIOCells.serial(serial) - val harnessFn = (th: chipyard.TestHarness) => { - val ser_success = SerialAdapter.connectSimSerial(port, th.clock, th.harnessReset) - when (ser_success) { th.success := true.B } - Nil - } - Seq((Seq(port), ioCells, Some(harnessFn))) - }).getOrElse(Nil) -}) - -class WithTraceGenSuccessBinder extends OverrideIOBinder({ - (system: TraceGenSystemModuleImp) => { - val (successPort, ioCells) = IOCell.generateIOFromSignal(system.success, Some("iocell_success")) - successPort.suggestName("success") - val harnessFn = (th: chipyard.TestHarness) => { when (successPort) { th.success := true.B }; Nil } - Seq((Seq(successPort), ioCells, Some(harnessFn))) - } -}) - -class WithSimDromajoBridge extends ComposeIOBinder({ - (system: CanHaveTraceIOModuleImp) => { - system.traceIO match { case Some(t) => t.traces.map(tileTrace => SimDromajoBridge(tileTrace)(system.p)) } - Nil - } -}) - - -} /* end package object */ diff --git a/generators/chipyard/src/main/scala/Subsystem.scala b/generators/chipyard/src/main/scala/Subsystem.scala index 3ca5ab11..5dd6ac18 100644 --- a/generators/chipyard/src/main/scala/Subsystem.scala +++ b/generators/chipyard/src/main/scala/Subsystem.scala @@ -8,6 +8,7 @@ package chipyard import chisel3._ import chisel3.internal.sourceinfo.{SourceInfo} +import freechips.rocketchip.prci._ import freechips.rocketchip.config.{Field, Parameters} import freechips.rocketchip.devices.tilelink._ import freechips.rocketchip.devices.debug.{HasPeripheryDebug, HasPeripheryDebugModuleImp, ExportDebug} @@ -24,14 +25,13 @@ import freechips.rocketchip.amba.axi4._ import boom.common.{BoomTile} -import testchipip.{DromajoHelper, CanHavePeripherySerial, SerialKey} - +import testchipip.{DromajoHelper, CanHavePeripheryTLSerial, SerialTLKey} trait CanHaveHTIF { this: BaseSubsystem => // Advertise HTIF if system can communicate with fesvr if (this match { - case _: CanHavePeripherySerial if p(SerialKey) => true - case _: HasPeripheryDebug if p(ExportDebug).protocols.nonEmpty => true + case _: CanHavePeripheryTLSerial if p(SerialTLKey).nonEmpty => true + case _: HasPeripheryDebug if p(ExportDebug).dmi => true case _ => false }) { ResourceBinding { @@ -47,7 +47,6 @@ trait CanHaveHTIF { this: BaseSubsystem => } } - class ChipyardSubsystem(implicit p: Parameters) extends BaseSubsystem with HasTiles with CanHaveHTIF @@ -56,25 +55,17 @@ class ChipyardSubsystem(implicit p: Parameters) extends BaseSubsystem case r: RocketTile => r.module.core.rocketImpl.coreMonitorBundle case b: BoomTile => b.module.core.coreMonitorBundle }.toList + override lazy val module = new ChipyardSubsystemModuleImp(this) } - class ChipyardSubsystemModuleImp[+L <: ChipyardSubsystem](_outer: L) extends BaseSubsystemModuleImp(_outer) - with HasResetVectorWire with HasTilesModuleImp { - - for (i <- 0 until outer.tiles.size) { - val wire = tile_inputs(i) - wire.hartid := outer.hartIdList(i).U - wire.reset_vector := global_reset_vector - } - // create file with core params ElaborationArtefacts.add("""core.config""", outer.tiles.map(x => x.module.toString).mkString("\n")) // Generate C header with relevant information for Dromajo // This is included in the `dromajo_params.h` header file - DromajoHelper.addArtefacts() + DromajoHelper.addArtefacts(InSubsystem) } diff --git a/generators/chipyard/src/main/scala/System.scala b/generators/chipyard/src/main/scala/System.scala index b0ae8a44..bd20ddc7 100644 --- a/generators/chipyard/src/main/scala/System.scala +++ b/generators/chipyard/src/main/scala/System.scala @@ -26,8 +26,10 @@ class ChipyardSystem(implicit p: Parameters) extends ChipyardSubsystem with CanHaveMasterAXI4MemPort with CanHaveMasterAXI4MMIOPort with CanHaveSlaveAXI4Port - with HasPeripheryBootROM { + + val bootROM = p(BootROMLocated(location)).map { BootROM.attach(_, this, CBUS) } + val maskROMs = p(MaskROMLocated(location)).map { MaskROM.attach(_, this, CBUS) } override lazy val module = new ChipyardSystemModule(this) } @@ -37,5 +39,4 @@ class ChipyardSystem(implicit p: Parameters) extends ChipyardSubsystem class ChipyardSystemModule[+L <: ChipyardSystem](_outer: L) extends ChipyardSubsystemModuleImp(_outer) with HasRTCModuleImp with HasExtInterruptsModuleImp - with HasPeripheryBootROMModuleImp with DontTouch diff --git a/generators/chipyard/src/main/scala/TestHarness.scala b/generators/chipyard/src/main/scala/TestHarness.scala index a82d3a33..2faff565 100644 --- a/generators/chipyard/src/main/scala/TestHarness.scala +++ b/generators/chipyard/src/main/scala/TestHarness.scala @@ -1,37 +1,50 @@ package chipyard import chisel3._ - +import scala.collection.mutable.{ArrayBuffer} import freechips.rocketchip.diplomacy.{LazyModule} import freechips.rocketchip.config.{Field, Parameters} -import chipyard.iobinders.{TestHarnessFunction} -import chipyard.config.ConfigValName._ + +import chipyard.harness.{ApplyHarnessBinders, HarnessBinders} // ------------------------------- -// BOOM and/or Rocket Test Harness +// Chipyard Test Harness // ------------------------------- -case object BuildTop extends Field[Parameters => HasTestHarnessFunctions]((p: Parameters) => Module(new ChipTop()(p))) +case object BuildTop extends Field[Parameters => LazyModule]((p: Parameters) => new ChipTop()(p)) trait HasTestHarnessFunctions { - val harnessFunctions: Seq[TestHarnessFunction] + val lazySystem: LazyModule + val harnessFunctions = ArrayBuffer.empty[HasHarnessSignalReferences => Seq[Any]] + val portMap = scala.collection.mutable.Map[String, Seq[Data]]() } -class TestHarness(implicit val p: Parameters) extends Module { +trait HasHarnessSignalReferences { + def harnessClock: Clock + def harnessReset: Reset + def dutReset: Reset + def success: Bool +} + +class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSignalReferences { val io = IO(new Bundle { val success = Output(Bool()) }) - val dut = p(BuildTop)(p) + val lazyDut = LazyModule(p(BuildTop)(p)).suggestName("chiptop") + val dut = Module(lazyDut.module) io.success := false.B + val harnessClock = clock + val harnessReset = WireInit(reset) + val success = io.success + // dutReset assignment can be overridden via a harnessFunction, but by default it is just reset val dutReset = WireDefault(if (p(GlobalResetSchemeKey).pinIsAsync) reset.asAsyncReset else reset) - dut.harnessFunctions.foreach(_(this)) - - def success = io.success - def harnessReset = this.reset.asBool - + lazyDut match { case d: HasTestHarnessFunctions => + d.harnessFunctions.foreach(_(this)) + ApplyHarnessBinders(this, d.lazySystem, p(HarnessBinders), d.portMap.toMap) + } } diff --git a/generators/chipyard/src/main/scala/config/AbstractConfig.scala b/generators/chipyard/src/main/scala/config/AbstractConfig.scala index 22f64925..5b356c74 100644 --- a/generators/chipyard/src/main/scala/config/AbstractConfig.scala +++ b/generators/chipyard/src/main/scala/config/AbstractConfig.scala @@ -5,18 +5,45 @@ import freechips.rocketchip.config.{Config} // -------------- // Chipyard abstract ("base") configuration // NOTE: This configuration is NOT INSTANTIABLE, as it defines a empty system with no tiles +// +// The default set of IOBinders instantiate IOcells and ChipTop IOs for digital IO bundles. +// The default set of HarnessBinders instantiate TestHarness hardware for interacting with ChipTop IOs // -------------- class AbstractConfig extends Config( - new chipyard.iobinders.WithUARTAdapter ++ // display UART with a SimUARTAdapter - new chipyard.iobinders.WithTieOffInterrupts ++ // tie off top-level interrupts - new chipyard.iobinders.WithBlackBoxSimMem ++ // drive the master AXI4 memory with a blackbox DRAMSim model - new chipyard.iobinders.WithTiedOffDebug ++ // tie off debug (since we are using SimSerial for testing) - new chipyard.iobinders.WithSimSerial ++ // drive TSI with SimSerial for testing - new testchipip.WithTSI ++ // use testchipip serial offchip link + // The HarnessBinders control generation of hardware in the TestHarness + new chipyard.harness.WithUARTAdapter ++ // add UART adapter to display UART on stdout, if uart is present + new chipyard.harness.WithBlackBoxSimMem ++ // add SimDRAM DRAM model for axi4 backing memory, if axi4 mem is enabled + new chipyard.harness.WithSimSerial ++ // add external serial-adapter and RAM + new chipyard.harness.WithSimDebug ++ // add SimJTAG or SimDTM adapters if debug module is enabled + new chipyard.harness.WithGPIOTiedOff ++ // tie-off chiptop GPIOs, if GPIOs are present + new chipyard.harness.WithSimSPIFlashModel ++ // add simulated SPI flash memory, if SPI is enabled + new chipyard.harness.WithSimAXIMMIO ++ // add SimAXIMem for axi4 mmio port, if enabled + new chipyard.harness.WithTieOffInterrupts ++ // tie-off interrupt ports, if present + new chipyard.harness.WithTieOffL2FBusAXI ++ // tie-off external AXI4 master, if present + + // The IOBinders instantiate ChipTop IOs to match desired digital IOs + // IOCells are generated for "Chip-like" IOs, while simulation-only IOs are directly punched through + new chipyard.iobinders.WithAXI4MemPunchthrough ++ + new chipyard.iobinders.WithAXI4MMIOPunchthrough ++ + new chipyard.iobinders.WithL2FBusAXI4Punchthrough ++ + new chipyard.iobinders.WithBlockDeviceIOPunchthrough ++ + new chipyard.iobinders.WithNICIOPunchthrough ++ + new chipyard.iobinders.WithSerialTLIOCells ++ + new chipyard.iobinders.WithDebugIOCells ++ + new chipyard.iobinders.WithUARTIOCells ++ + new chipyard.iobinders.WithGPIOCells ++ + new chipyard.iobinders.WithUARTIOCells ++ + new chipyard.iobinders.WithSPIIOCells ++ + new chipyard.iobinders.WithTraceIOPunchthrough ++ + new chipyard.iobinders.WithExtInterruptIOCells ++ + + new testchipip.WithDefaultSerialTL ++ // use serialized tilelink port to external serialadapter/harnessRAM new chipyard.config.WithBootROM ++ // use default bootrom new chipyard.config.WithUART ++ // add a UART new chipyard.config.WithL2TLBs(1024) ++ // use L2 TLBs + new chipyard.config.WithNoSubsystemDrivenClocks ++ // drive the subsystem diplomatic clocks from ChipTop instead of using implicit clocks + new freechips.rocketchip.subsystem.WithJtagDTM ++ // set the debug module to expose a JTAG port new freechips.rocketchip.subsystem.WithNoMMIOPort ++ // no top-level MMIO master port (overrides default set in rocketchip) new freechips.rocketchip.subsystem.WithNoSlavePort ++ // no top-level MMIO slave port (overrides default set in rocketchip) new freechips.rocketchip.subsystem.WithInclusiveCache ++ // use Sifive L2 cache diff --git a/generators/chipyard/src/main/scala/config/ArianeConfigs.scala b/generators/chipyard/src/main/scala/config/ArianeConfigs.scala index 7bc985aa..6e75ac54 100644 --- a/generators/chipyard/src/main/scala/config/ArianeConfigs.scala +++ b/generators/chipyard/src/main/scala/config/ArianeConfigs.scala @@ -13,7 +13,7 @@ class ArianeConfig extends Config( new chipyard.config.AbstractConfig) class dmiArianeConfig extends Config( - new chipyard.iobinders.WithTiedOffSerial ++ // Tie off the serial port, override default instantiation of SimSerial - new chipyard.iobinders.WithSimDebug ++ // add SimDebug and use it to drive simulation, override default tie-off debug + new chipyard.harness.WithSerialAdapterTiedOff ++ // Tie off the serial port, override default instantiation of SimSerial + new chipyard.config.WithDMIDTM ++ // have debug module expose a clocked DMI port new ariane.WithNArianeCores(1) ++ // single Ariane core new chipyard.config.AbstractConfig) diff --git a/generators/chipyard/src/main/scala/config/BoomConfigs.scala b/generators/chipyard/src/main/scala/config/BoomConfigs.scala index 575e1f98..9e1f558a 100644 --- a/generators/chipyard/src/main/scala/config/BoomConfigs.scala +++ b/generators/chipyard/src/main/scala/config/BoomConfigs.scala @@ -33,13 +33,13 @@ class HwachaLargeBoomConfig extends Config( new chipyard.config.AbstractConfig) class LoopbackNICLargeBoomConfig extends Config( - new chipyard.iobinders.WithLoopbackNIC ++ // drive NIC IOs with loopback + new chipyard.harness.WithLoopbackNIC ++ // drive NIC IOs with loopback new icenet.WithIceNIC ++ // build a NIC new boom.common.WithNLargeBooms(1) ++ new chipyard.config.AbstractConfig) class DromajoBoomConfig extends Config( - new chipyard.iobinders.WithSimDromajoBridge ++ // attach Dromajo + new chipyard.harness.WithSimDromajoBridge ++ // attach Dromajo new chipyard.config.WithTraceIO ++ // enable the traceio new boom.common.WithNSmallBooms(1) ++ new chipyard.config.AbstractConfig) diff --git a/generators/chipyard/src/main/scala/config/RocketConfigs.scala b/generators/chipyard/src/main/scala/config/RocketConfigs.scala index 3bd4fce6..17a51662 100644 --- a/generators/chipyard/src/main/scala/config/RocketConfigs.scala +++ b/generators/chipyard/src/main/scala/config/RocketConfigs.scala @@ -12,29 +12,21 @@ class RocketConfig extends Config( class HwachaRocketConfig extends Config( new chipyard.config.WithHwachaTest ++ - new hwacha.DefaultHwachaConfig ++ // use Hwacha vector accelerator + new hwacha.DefaultHwachaConfig ++ // use Hwacha vector accelerator new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) // DOC include start: GemminiRocketConfig class GemminiRocketConfig extends Config( - new gemmini.DefaultGemminiConfig ++ // use Gemmini systolic array GEMM accelerator + new gemmini.DefaultGemminiConfig ++ // use Gemmini systolic array GEMM accelerator new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) // DOC include end: GemminiRocketConfig -// DOC include start: JtagRocket -class jtagRocketConfig extends Config( - new chipyard.iobinders.WithSimDebug ++ // add SimDebug, in addition to default SimSerial - new freechips.rocketchip.subsystem.WithJtagDTM ++ // sets DTM communication interface to JTAG - new freechips.rocketchip.subsystem.WithNBigCores(1) ++ - new chipyard.config.AbstractConfig) -// DOC include end: JtagRocket - // DOC include start: DmiRocket class dmiRocketConfig extends Config( - new chipyard.iobinders.WithTiedOffSerial ++ // tie-off serial, override default add SimSerial - new chipyard.iobinders.WithSimDebug ++ // add SimDebug, override default tie-off debug + new chipyard.harness.WithSerialAdapterTiedOff ++ // don't attach an external SimSerial + new chipyard.config.WithDMIDTM ++ // have debug module expose a clocked DMI port new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) // DOC include end: DmiRocket @@ -48,54 +40,53 @@ class GCDTLRocketConfig extends Config( // DOC include start: GCDAXI4BlackBoxRocketConfig class GCDAXI4BlackBoxRocketConfig extends Config( - new chipyard.example.WithGCD(useAXI4=true, useBlackBox=true) ++ // Use GCD blackboxed verilog, connect by AXI4->Tilelink + new chipyard.example.WithGCD(useAXI4=true, useBlackBox=true) ++ // Use GCD blackboxed verilog, connect by AXI4->Tilelink new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) // DOC include end: GCDAXI4BlackBoxRocketConfig class LargeSPIFlashROMRocketConfig extends Config( - new chipyard.iobinders.WithSimSPIFlashModel(true) ++ // add the SPI flash model in the harness (read-only) + new chipyard.harness.WithSimSPIFlashModel(true) ++ // add the SPI flash model in the harness (read-only) new chipyard.config.WithSPIFlash ++ // add the SPI flash controller new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) class SmallSPIFlashRocketConfig extends Config( - new chipyard.iobinders.WithSimSPIFlashModel(false) ++ // add the SPI flash model in the harness (writeable) + new chipyard.harness.WithSimSPIFlashModel(false) ++ // add the SPI flash model in the harness (writeable) new chipyard.config.WithSPIFlash(0x100000) ++ // add the SPI flash controller (1 MiB) new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) class SimAXIRocketConfig extends Config( - new chipyard.iobinders.WithSimAXIMem ++ // drive the master AXI4 memory with a SimAXIMem, a 1-cycle magic memory, instead of default SimDRAM + new chipyard.harness.WithSimAXIMem ++ // drive the master AXI4 memory with a SimAXIMem, a 1-cycle magic memory, instead of default SimDRAM new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) class SimBlockDeviceRocketConfig extends Config( - new chipyard.iobinders.WithSimBlockDevice ++ // drive block-device IOs with SimBlockDevice - new testchipip.WithBlockDevice ++ // add block-device module to peripherybus + new chipyard.harness.WithSimBlockDevice ++ // drive block-device IOs with SimBlockDevice + new testchipip.WithBlockDevice ++ // add block-device module to peripherybus new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) class BlockDeviceModelRocketConfig extends Config( - new chipyard.iobinders.WithBlockDeviceModel ++ // drive block-device IOs with a BlockDeviceModel - new testchipip.WithBlockDevice ++ // add block-device module to periphery bus + new chipyard.harness.WithBlockDeviceModel ++ // drive block-device IOs with a BlockDeviceModel + new testchipip.WithBlockDevice ++ // add block-device module to periphery bus new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) // DOC include start: GPIORocketConfig class GPIORocketConfig extends Config( - new chipyard.iobinders.WithGPIOTiedOff ++ // tie off GPIO inputs into the top - new chipyard.config.WithGPIO ++ // add GPIOs to the peripherybus + new chipyard.config.WithGPIO ++ // add GPIOs to the peripherybus new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) // DOC include end: GPIORocketConfig class QuadRocketConfig extends Config( - new freechips.rocketchip.subsystem.WithNBigCores(4) ++ // quad-core (4 RocketTiles) + new freechips.rocketchip.subsystem.WithNBigCores(4) ++ // quad-core (4 RocketTiles) new chipyard.config.AbstractConfig) class RV32RocketConfig extends Config( - new freechips.rocketchip.subsystem.WithRV32 ++ // set RocketTiles to be 32-bit + new freechips.rocketchip.subsystem.WithRV32 ++ // set RocketTiles to be 32-bit new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) @@ -113,14 +104,14 @@ class Sha3RocketConfig extends Config( // DOC include start: InitZeroRocketConfig class InitZeroRocketConfig extends Config( - new chipyard.example.WithInitZero(0x88000000L, 0x1000L) ++ // add InitZero + new chipyard.example.WithInitZero(0x88000000L, 0x1000L) ++ // add InitZero new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) // DOC include end: InitZeroRocketConfig class LoopbackNICRocketConfig extends Config( - new chipyard.iobinders.WithLoopbackNIC ++ // drive NIC IOs with loopback - new icenet.WithIceNIC ++ // add an IceNIC + new chipyard.harness.WithLoopbackNIC ++ // drive NIC IOs with loopback + new icenet.WithIceNIC ++ // add an IceNIC new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) @@ -135,8 +126,8 @@ class ScratchpadOnlyRocketConfig extends Config( // DOC include end: l1scratchpadrocket class L1ScratchpadRocketConfig extends Config( - new chipyard.config.WithRocketICacheScratchpad ++ // use rocket ICache scratchpad - new chipyard.config.WithRocketDCacheScratchpad ++ // use rocket DCache scratchpad + new chipyard.config.WithRocketICacheScratchpad ++ // use rocket ICache scratchpad + new chipyard.config.WithRocketDCacheScratchpad ++ // use rocket DCache scratchpad new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) @@ -150,37 +141,49 @@ class MbusScratchpadRocketConfig extends Config( // DOC include start: RingSystemBusRocket class RingSystemBusRocketConfig extends Config( - new testchipip.WithRingSystemBus ++ // Ring-topology system bus + new testchipip.WithRingSystemBus ++ // Ring-topology system bus new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) // DOC include end: RingSystemBusRocket class StreamingPassthroughRocketConfig extends Config( - new chipyard.example.WithStreamingPassthrough ++ // use top with tilelink-controlled streaming passthrough + new chipyard.example.WithStreamingPassthrough ++ // use top with tilelink-controlled streaming passthrough new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) // DOC include start: StreamingFIRRocketConfig class StreamingFIRRocketConfig extends Config ( - new chipyard.example.WithStreamingFIR ++ // use top with tilelink-controlled streaming FIR + new chipyard.example.WithStreamingFIR ++ // use top with tilelink-controlled streaming FIR new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) // DOC include end: StreamingFIRRocketConfig class SmallNVDLARocketConfig extends Config( - new nvidia.blocks.dla.WithNVDLA("small") ++ // add a small NVDLA + new nvidia.blocks.dla.WithNVDLA("small") ++ // add a small NVDLA new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) class LargeNVDLARocketConfig extends Config( - new nvidia.blocks.dla.WithNVDLA("large", true) ++ // add a large NVDLA with synth. rams + new nvidia.blocks.dla.WithNVDLA("large", true) ++ // add a large NVDLA with synth. rams new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) class MMIORocketConfig extends Config( - new chipyard.iobinders.WithTieOffL2FBusAXI ++ // Tie-off the incoming MMIO port - new chipyard.iobinders.WithSimAXIMMIO ++ // Attach a simulated memory to the outwards MMIO port - new freechips.rocketchip.subsystem.WithDefaultMMIOPort ++ // add default external master port + new freechips.rocketchip.subsystem.WithDefaultMMIOPort ++ // add default external master port new freechips.rocketchip.subsystem.WithDefaultSlavePort ++ // add default external slave port new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) + +// NOTE: This config doesn't work yet because SimWidgets in the TestHarness +// always get the TestHarness clock. The Tiles and Uncore receive the correct clocks +class DividedClockRocketConfig extends Config( + new chipyard.config.WithTileDividedClock ++ // Put the Tile on its own clock domain + new freechips.rocketchip.subsystem.WithRationalRocketTiles ++ // Add rational crossings between RocketTile and uncore + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new chipyard.config.AbstractConfig) + +class LBWIFRocketConfig extends Config( + new testchipip.WithSerialTLMem(isMainMemory=true) ++ // set lbwif memory base to DRAM_BASE, use as main memory + new freechips.rocketchip.subsystem.WithNoMemPort ++ // remove AXI4 backing memory + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new chipyard.config.AbstractConfig) diff --git a/generators/chipyard/src/main/scala/config/TracegenConfigs.scala b/generators/chipyard/src/main/scala/config/TracegenConfigs.scala index e8aeeb29..78cb6851 100644 --- a/generators/chipyard/src/main/scala/config/TracegenConfigs.scala +++ b/generators/chipyard/src/main/scala/config/TracegenConfigs.scala @@ -3,46 +3,37 @@ package chipyard import freechips.rocketchip.config.{Config} import freechips.rocketchip.rocket.{DCacheParams} -class TraceGenConfig extends Config( - new chipyard.iobinders.WithBlackBoxSimMem ++ - new chipyard.iobinders.WithTraceGenSuccessBinder ++ +class AbstractTraceGenConfig extends Config( + new chipyard.harness.WithBlackBoxSimMem ++ + new chipyard.harness.WithTraceGenSuccess ++ + new chipyard.iobinders.WithAXI4MemPunchthrough ++ + new chipyard.iobinders.WithTraceGenSuccessPunchthrough ++ new chipyard.config.WithTracegenSystem ++ - new tracegen.WithTraceGen()(List.fill(2) { DCacheParams(nMSHRs = 0, nSets = 16, nWays = 2) }) ++ + new chipyard.config.WithNoSubsystemDrivenClocks ++ new freechips.rocketchip.subsystem.WithCoherentBusTopology ++ new freechips.rocketchip.groundtest.GroundTestBaseConfig) + +class TraceGenConfig extends Config( + new tracegen.WithTraceGen()(List.fill(2) { DCacheParams(nMSHRs = 0, nSets = 16, nWays = 2) }) ++ + new AbstractTraceGenConfig) + class NonBlockingTraceGenConfig extends Config( - new chipyard.iobinders.WithBlackBoxSimMem ++ - new chipyard.iobinders.WithTraceGenSuccessBinder ++ - new chipyard.config.WithTracegenSystem ++ new tracegen.WithTraceGen()(List.fill(2) { DCacheParams(nMSHRs = 2, nSets = 16, nWays = 2) }) ++ - new freechips.rocketchip.subsystem.WithCoherentBusTopology ++ - new freechips.rocketchip.groundtest.GroundTestBaseConfig) + new AbstractTraceGenConfig) class BoomTraceGenConfig extends Config( - new chipyard.iobinders.WithBlackBoxSimMem ++ - new chipyard.iobinders.WithTraceGenSuccessBinder ++ - new chipyard.config.WithTracegenSystem ++ new tracegen.WithBoomTraceGen()(List.fill(2) { DCacheParams(nMSHRs = 8, nSets = 16, nWays = 2) }) ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ - new freechips.rocketchip.subsystem.WithCoherentBusTopology ++ - new freechips.rocketchip.groundtest.GroundTestBaseConfig) + new AbstractTraceGenConfig) class NonBlockingTraceGenL2Config extends Config( - new chipyard.iobinders.WithBlackBoxSimMem ++ - new chipyard.iobinders.WithTraceGenSuccessBinder ++ - new chipyard.config.WithTracegenSystem ++ new tracegen.WithL2TraceGen()(List.fill(2)(DCacheParams(nMSHRs = 2, nSets = 16, nWays = 4))) ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ - new freechips.rocketchip.subsystem.WithCoherentBusTopology ++ - new freechips.rocketchip.groundtest.GroundTestBaseConfig) + new AbstractTraceGenConfig) class NonBlockingTraceGenL2RingConfig extends Config( - new chipyard.iobinders.WithBlackBoxSimMem ++ - new chipyard.iobinders.WithTraceGenSuccessBinder ++ - new chipyard.config.WithTracegenSystem ++ new tracegen.WithL2TraceGen()(List.fill(2)(DCacheParams(nMSHRs = 2, nSets = 16, nWays = 4))) ++ new testchipip.WithRingSystemBus ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ - new freechips.rocketchip.subsystem.WithCoherentBusTopology ++ - new freechips.rocketchip.groundtest.GroundTestBaseConfig) + new AbstractTraceGenConfig) diff --git a/generators/chipyard/src/main/scala/config/TutorialConfigs.scala b/generators/chipyard/src/main/scala/config/TutorialConfigs.scala index 56e6362b..3c64958f 100644 --- a/generators/chipyard/src/main/scala/config/TutorialConfigs.scala +++ b/generators/chipyard/src/main/scala/config/TutorialConfigs.scala @@ -12,26 +12,16 @@ import freechips.rocketchip.config.{Config} // This file was originally developed for the cancelled ASPLOS-2020 // Chipyard tutorial. While the configs here work, the corresponding -// slideware has not yet been created +// slideware has not yet been created. // NOTE: Configs should be read bottom-up, since they are applied bottom-up +// NOTE: The TutorialConfigs build off of the AbstractConfig defined in AbstractConfig.scala +// Users should try to understand the functionality of the AbstractConfig before proceeding +// with the TutorialConfigs below + // Tutorial Phase 1: Configure the cores, caches class TutorialStarterConfig extends Config( - // IOBinders specify how to connect to IOs in our TestHarness - // These config fragments do not affect - new chipyard.iobinders.WithUARTAdapter ++ // Connect a SimUART adapter to display UART on stdout - new chipyard.iobinders.WithBlackBoxSimMem ++ // Connect simulated external memory - new chipyard.iobinders.WithTieOffInterrupts ++ // Do not simulate external interrupts - new chipyard.iobinders.WithTiedOffDebug ++ // Disconnect the debug module, since we use TSI for bring-up - new chipyard.iobinders.WithSimSerial ++ // Connect external SimSerial widget to drive TSI - - // Config fragments below this line affect hardware generation - // of the Top - new testchipip.WithTSI ++ // Add a TSI (Test Serial Interface) widget to bring-up the core - new chipyard.config.WithBootROM ++ // Use the Chipyard BootROM - new chipyard.config.WithUART ++ // Add a UART - // CUSTOMIZE THE CORE // Uncomment out one (or multiple) of the lines below, and choose // how many cores you want. @@ -42,29 +32,11 @@ class TutorialStarterConfig extends Config( // Uncomment this line, and specify a size if you want to have a L2 // new freechips.rocketchip.subsystem.WithInclusiveCache(nBanks=1, nWays=4, capacityKB=128) ++ - // For simpler designs, we want to minimize IOs on - // our Top. These config fragments remove unnecessary - // ports - new freechips.rocketchip.subsystem.WithNoMMIOPort ++ - new freechips.rocketchip.subsystem.WithNoSlavePort ++ - new freechips.rocketchip.subsystem.WithNExtTopInterrupts(0) ++ - new freechips.rocketchip.subsystem.WithCoherentBusTopology ++ // hierarchical buses including mbus+l2 - // BaseConfig configures "bare" rocketchip system - new freechips.rocketchip.system.BaseConfig + new chipyard.config.AbstractConfig ) - // Tutorial Phase 2: Integrate a TileLink or AXI4 MMIO device class TutorialMMIOConfig extends Config( - new chipyard.iobinders.WithUARTAdapter ++ - new chipyard.iobinders.WithBlackBoxSimMem ++ - new chipyard.iobinders.WithTieOffInterrupts ++ - new chipyard.iobinders.WithTiedOffDebug ++ - new chipyard.iobinders.WithSimSerial ++ - - new testchipip.WithTSI ++ - new chipyard.config.WithBootROM ++ - new chipyard.config.WithUART ++ // Attach either a TileLink or AXI4 version of GCD // Uncomment one of the below lines @@ -73,61 +45,26 @@ class TutorialMMIOConfig extends Config( // For this demonstration we assume the base system is a single-core Rocket, for fast elaboration new freechips.rocketchip.subsystem.WithNBigCores(1) ++ - new freechips.rocketchip.subsystem.WithInclusiveCache ++ - new freechips.rocketchip.subsystem.WithNoMMIOPort ++ - new freechips.rocketchip.subsystem.WithNoSlavePort ++ - new freechips.rocketchip.subsystem.WithNExtTopInterrupts(0) ++ - new freechips.rocketchip.subsystem.WithCoherentBusTopology ++ - new freechips.rocketchip.system.BaseConfig + new chipyard.config.AbstractConfig ) // Tutorial Phase 3: Integrate a SHA3 RoCC accelerator class TutorialSha3Config extends Config( - new chipyard.iobinders.WithUARTAdapter ++ - new chipyard.iobinders.WithBlackBoxSimMem ++ - new chipyard.iobinders.WithTieOffInterrupts ++ - new chipyard.iobinders.WithTiedOffDebug ++ - new chipyard.iobinders.WithSimSerial ++ - - new testchipip.WithTSI ++ - new chipyard.config.WithBootROM ++ - new chipyard.config.WithUART ++ - // Uncomment this line once you added SHA3 to the build.sbt, and cloned the SHA3 repo // new sha3.WithSha3Accel ++ // For this demonstration we assume the base system is a single-core Rocket, for fast elaboration new freechips.rocketchip.subsystem.WithNBigCores(1) ++ - new freechips.rocketchip.subsystem.WithInclusiveCache ++ - new freechips.rocketchip.subsystem.WithNoMMIOPort ++ - new freechips.rocketchip.subsystem.WithNoSlavePort ++ - new freechips.rocketchip.subsystem.WithNExtTopInterrupts(0) ++ - new freechips.rocketchip.subsystem.WithCoherentBusTopology ++ - new freechips.rocketchip.system.BaseConfig + new chipyard.config.AbstractConfig ) // Tutorial Phase 4: Integrate a Black-box verilog version of the SHA3 RoCC accelerator class TutorialSha3BlackBoxConfig extends Config( - new chipyard.iobinders.WithUARTAdapter ++ - new chipyard.iobinders.WithBlackBoxSimMem ++ - new chipyard.iobinders.WithTieOffInterrupts ++ - new chipyard.iobinders.WithTiedOffDebug ++ - new chipyard.iobinders.WithSimSerial ++ - - new testchipip.WithTSI ++ - new chipyard.config.WithBootROM ++ - new chipyard.config.WithUART ++ - // Uncomment these lines once SHA3 is integrated // new sha3.WithSha3BlackBox ++ // Specify we want the Black-box verilog version of Sha3 Ctrl // new sha3.WithSha3Accel ++ // For this demonstration we assume the base system is a single-core Rocket, for fast elaboration new freechips.rocketchip.subsystem.WithNBigCores(1) ++ - new freechips.rocketchip.subsystem.WithInclusiveCache ++ - new freechips.rocketchip.subsystem.WithNoMMIOPort ++ - new freechips.rocketchip.subsystem.WithNoSlavePort ++ - new freechips.rocketchip.subsystem.WithNExtTopInterrupts(0) ++ - new freechips.rocketchip.subsystem.WithCoherentBusTopology ++ - new freechips.rocketchip.system.BaseConfig + new chipyard.config.AbstractConfig ) diff --git a/generators/firechip/src/main/scala/BridgeBinders.scala b/generators/firechip/src/main/scala/BridgeBinders.scala index eba57451..4943e130 100644 --- a/generators/firechip/src/main/scala/BridgeBinders.scala +++ b/generators/firechip/src/main/scala/BridgeBinders.scala @@ -8,13 +8,13 @@ import chisel3.experimental.annotate import freechips.rocketchip.config.{Field, Config, Parameters} import freechips.rocketchip.diplomacy.{LazyModule} import freechips.rocketchip.devices.debug.{Debug, HasPeripheryDebugModuleImp} +import freechips.rocketchip.amba.axi4.{AXI4Bundle} import freechips.rocketchip.subsystem.{CanHaveMasterAXI4MemPort, HasExtInterruptsModuleImp, BaseSubsystem, HasTilesModuleImp} import freechips.rocketchip.tile.{RocketTile} -import sifive.blocks.devices.uart.HasPeripheryUARTModuleImp -import sifive.blocks.devices.gpio.{HasPeripheryGPIOModuleImp} +import sifive.blocks.devices.uart._ -import testchipip.{CanHavePeripherySerialModuleImp, CanHavePeripheryBlockDeviceModuleImp} -import icenet.CanHavePeripheryIceNICModuleImp +import testchipip._ +import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvonly} import junctions.{NastiKey, NastiParameters} import midas.models.{FASEDBridge, AXI4EdgeSummary, CompleteConfig} @@ -25,73 +25,119 @@ import tracegen.{TraceGenSystemModuleImp} import ariane.ArianeTile import boom.common.{BoomTile} - -import chipyard.iobinders.{IOBinders, OverrideIOBinder, ComposeIOBinder, GetSystemParameters} -import testchipip.{CanHaveTraceIOModuleImp} +import barstools.iocell.chisel._ +import chipyard.iobinders.{IOBinders, OverrideIOBinder, ComposeIOBinder, GetSystemParameters, IOCellKey} +import chipyard.{HasHarnessSignalReferences} +import chipyard.harness._ object MainMemoryConsts { val regionNamePrefix = "MainMemory" def globalName = s"${regionNamePrefix}_${NodeIdx()}" } -class WithSerialBridge extends OverrideIOBinder({ - (system: CanHavePeripherySerialModuleImp) => - system.serial.foreach(s => SerialBridge(system.clock, s, MainMemoryConsts.globalName)(system.p)); Nil +trait Unsupported { + require(false, "We do not support this IOCell type") +} + +class FireSimAnalogIOCell extends RawModule with AnalogIOCell with Unsupported { + val io = IO(new AnalogIOCellBundle) +} +class FireSimDigitalGPIOCell extends RawModule with DigitalGPIOCell with Unsupported { + val io = IO(new DigitalGPIOCellBundle) +} +class FireSimDigitalInIOCell extends RawModule with DigitalInIOCell { + val io = IO(new DigitalInIOCellBundle) + io.i := io.pad +} +class FireSimDigitalOutIOCell extends RawModule with DigitalOutIOCell { + val io = IO(new DigitalOutIOCellBundle) + io.pad := io.o +} + +case class FireSimIOCellParams() extends IOCellTypeParams { + def analog() = Module(new FireSimAnalogIOCell) + def gpio() = Module(new FireSimDigitalGPIOCell) + def input() = Module(new FireSimDigitalInIOCell) + def output() = Module(new FireSimDigitalOutIOCell) +} + +class WithFireSimIOCellModels extends Config((site, here, up) => { + case IOCellKey => FireSimIOCellParams() }) -class WithNICBridge extends OverrideIOBinder({ - (system: CanHavePeripheryIceNICModuleImp) => - system.net.foreach(n => NICBridge(system.clock, n)(system.p)); Nil +class WithSerialBridge extends OverrideHarnessBinder({ + (system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => { + ports.map { p => + val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, p, th.harnessReset) + withClockAndReset(p.clock, th.harnessReset) { + SerialBridge(p.clock, ram.module.io.tsi_ser, MainMemoryConsts.globalName)(GetSystemParameters(system)) + } + } + Nil + } }) -class WithUARTBridge extends OverrideIOBinder({ - (system: HasPeripheryUARTModuleImp) => - system.uart.foreach(u => UARTBridge(system.clock, u)(system.p)); Nil +class WithNICBridge extends OverrideHarnessBinder({ + (system: CanHavePeripheryIceNIC, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => { + val p: Parameters = GetSystemParameters(system) + ports.map { n => withClockAndReset(n.clock, th.harnessReset) { NICBridge(n.clock, n.bits)(p) } } + Nil + } }) -class WithBlockDeviceBridge extends OverrideIOBinder({ - (system: CanHavePeripheryBlockDeviceModuleImp) => - system.bdev.foreach(b => BlockDevBridge(system.clock, b, system.reset.toBool)(system.p)); Nil +class WithUARTBridge extends OverrideHarnessBinder({ + (system: HasPeripheryUARTModuleImp, th: HasHarnessSignalReferences, ports: Seq[UARTPortIO]) => + ports.map { p => UARTBridge(th.harnessClock, p)(system.p) }; Nil }) - -class WithFASEDBridge extends OverrideIOBinder({ - (system: CanHaveMasterAXI4MemPort) => { +class WithBlockDeviceBridge extends OverrideHarnessBinder({ + (system: CanHavePeripheryBlockDevice, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => { implicit val p: Parameters = GetSystemParameters(system) - (system.mem_axi4 zip system.memAXI4Node.in).foreach({ case (axi4, (_, edge)) => - val nastiKey = NastiParameters(axi4.r.bits.data.getWidth, - axi4.ar.bits.addr.getWidth, - axi4.ar.bits.id.getWidth) + ports.map { b => BlockDevBridge(b.clock, b.bits, th.harnessReset.toBool) } + Nil + } +}) + +class WithFASEDBridge extends OverrideHarnessBinder({ + (system: CanHaveMasterAXI4MemPort, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => { + implicit val p: Parameters = GetSystemParameters(system) + (ports zip system.memAXI4Node.edges.in).map { case (axi4, edge) => + val nastiKey = NastiParameters(axi4.bits.r.bits.data.getWidth, + axi4.bits.ar.bits.addr.getWidth, + axi4.bits.ar.bits.id.getWidth) system match { - case s: BaseSubsystem => FASEDBridge(s.module.clock, axi4, s.module.reset.toBool, + case s: BaseSubsystem => FASEDBridge(axi4.clock, axi4.bits, th.harnessReset.asBool, CompleteConfig(p(firesim.configs.MemModelKey), nastiKey, Some(AXI4EdgeSummary(edge)), Some(MainMemoryConsts.globalName))) case _ => throw new Exception("Attempting to attach FASED Bridge to misconfigured design") } - }) + } Nil } }) -class WithTracerVBridge extends ComposeIOBinder({ - (system: CanHaveTraceIOModuleImp) => - system.traceIO.foreach(_.traces.map(tileTrace => TracerVBridge(tileTrace)(system.p))); Nil -}) - - - -class WithDromajoBridge extends ComposeIOBinder({ - (system: CanHaveTraceIOModuleImp) => { - system.traceIO.foreach(_.traces.map(tileTrace => DromajoBridge(tileTrace)(system.p))); Nil +class WithTracerVBridge extends ComposeHarnessBinder({ + (system: CanHaveTraceIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[TraceOutputTop]) => { + ports.map { p => + p.traces.map( + tileTrace => withClockAndReset(tileTrace.clock, tileTrace.reset) { TracerVBridge(tileTrace)(system.p) } + ) + } + Nil } }) +class WithDromajoBridge extends ComposeHarnessBinder({ + (system: CanHaveTraceIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[TraceOutputTop]) => + ports.map { p => p.traces.map(tileTrace => DromajoBridge(tileTrace)(system.p)) }; Nil +}) -class WithTraceGenBridge extends OverrideIOBinder({ - (system: TraceGenSystemModuleImp) => - GroundTestBridge(system.clock, system.success)(system.p); Nil + +class WithTraceGenBridge extends OverrideHarnessBinder({ + (system: TraceGenSystemModuleImp, th: HasHarnessSignalReferences, ports: Seq[Bool]) => + ports.map { p => GroundTestBridge(th.harnessClock, p)(system.p) }; Nil }) class WithFireSimMultiCycleRegfile extends ComposeIOBinder({ @@ -105,52 +151,25 @@ class WithFireSimMultiCycleRegfile extends ComposeIOBinder({ val core = b.module.core core.iregfile match { case irf: boom.exu.RegisterFileSynthesizable => annotate(MemModelAnnotation(irf.regfile)) - case _ => Nil } if (core.fp_pipeline != null) core.fp_pipeline.fregfile match { case frf: boom.exu.RegisterFileSynthesizable => annotate(MemModelAnnotation(frf.regfile)) - case _ => Nil } } case _ => } - Nil + (Nil, Nil) } }) -class WithTiedOffSystemGPIO extends OverrideIOBinder({ - (system: HasPeripheryGPIOModuleImp) => - system.gpio.foreach(_.pins.foreach(_.i.ival := false.B)); Nil -}) - -class WithTiedOffSystemDebug extends OverrideIOBinder({ - (system: HasPeripheryDebugModuleImp) => { - Debug.tieoffDebug(system.debug, system.resetctrl, Some(system.psd))(system.p) - // tieoffDebug doesn't actually tie everything off :/ - system.debug.foreach { d => - d.clockeddmi.foreach({ cdmi => cdmi.dmi.req.bits := DontCare }) - d.dmactiveAck := DontCare - } - Nil - } -}) - -class WithTiedOffSystemInterrupts extends OverrideIOBinder({ - (system: HasExtInterruptsModuleImp) => - system.interrupts := 0.U; Nil -}) - - // Shorthand to register all of the provided bridges above class WithDefaultFireSimBridges extends Config( - new WithTiedOffSystemGPIO ++ - new WithTiedOffSystemDebug ++ - new WithTiedOffSystemInterrupts ++ new WithSerialBridge ++ new WithNICBridge ++ new WithUARTBridge ++ new WithBlockDeviceBridge ++ new WithFASEDBridge ++ new WithFireSimMultiCycleRegfile ++ - new WithTracerVBridge + new WithTracerVBridge ++ + new WithFireSimIOCellModels ) diff --git a/generators/firechip/src/main/scala/FireSim.scala b/generators/firechip/src/main/scala/FireSim.scala index a4cea5ec..d2ef4e60 100644 --- a/generators/firechip/src/main/scala/FireSim.scala +++ b/generators/firechip/src/main/scala/FireSim.scala @@ -3,14 +3,19 @@ package firesim.firesim import chisel3._ +import chisel3.experimental.{IO} +import freechips.rocketchip.prci._ +import freechips.rocketchip.subsystem.{BaseSubsystem, SubsystemDriveAsyncClockGroupsKey} import freechips.rocketchip.config.{Field, Config, Parameters} -import freechips.rocketchip.diplomacy.{LazyModule} +import freechips.rocketchip.diplomacy.{LazyModule, InModuleBody} +import freechips.rocketchip.util.{ResetCatchAndSync} -import midas.widgets.{Bridge, PeekPokeBridge, RationalClockBridge} +import midas.widgets.{Bridge, PeekPokeBridge, RationalClockBridge, RationalClock} -import chipyard.{BuildSystem} -import chipyard.iobinders.{IOBinders} +import chipyard._ +import chipyard.harness._ +import chipyard.iobinders._ // Determines the number of times to instantiate the DUT in the harness. // Subsumes legacy supernode support @@ -20,6 +25,16 @@ class WithNumNodes(n: Int) extends Config((pname, site, here) => { case NumNodes => n }) +// Note, the main prerequisite for supporting an additional clock domain in a +// FireSim simulation is to supply an additional clock parameter +// (RationalClock) to the clock bridge (RationalClockBridge). The bridge +// produces a vector of clocks, based on the provided parameter list, which you +// may use freely without further modifications to your target design. +case class FireSimClockParameters(additionalClocks: Seq[RationalClock]) { + def numClocks(): Int = additionalClocks.size + 1 +} +case object FireSimClockKey extends Field[FireSimClockParameters](FireSimClockParameters(Seq())) + // Hacky: Set before each node is generated. Ideally we'd give IO binders // accesses to the the Harness's parameters instance. We could then alter that. object NodeIdx { @@ -28,33 +43,130 @@ object NodeIdx { def apply(): Int = idx } -class FireSim(implicit val p: Parameters) extends RawModule { - freechips.rocketchip.util.property.cover.setPropLib(new midas.passes.FireSimPropertyLibrary()) - val clockBridge = Module(new RationalClockBridge) - val clock = clockBridge.io.clocks.head - val reset = WireInit(false.B) - withClockAndReset(clock, reset) { - // Instantiate multiple instances of the DUT to implement supernode - val targets = Seq.fill(p(NumNodes)) { - // It's not a RC bump without some hacks... - // Copy the AsyncClockGroupsKey to generate a fresh node on each - // instantiation of the dut, otherwise the initial instance will be - // reused across each node - import freechips.rocketchip.subsystem.AsyncClockGroupsKey - val lazyModule = p(BuildSystem)(p.alterPartial({ - case AsyncClockGroupsKey => p(AsyncClockGroupsKey).copy - })) - (lazyModule, Module(lazyModule.module)) +class WithFireSimSimpleClocks extends Config((site, here, up) => { + case ClockingSchemeKey => { chiptop: ChipTop => + implicit val p = chiptop.p + + val implicitClockSourceNode = ClockSourceNode(Seq(ClockSourceParameters())) + chiptop.implicitClockSinkNode := implicitClockSourceNode + + // Drive the diplomaticclock graph of the DigitalTop (if present) + val simpleClockGroupSourceNode = chiptop.lazySystem match { + case l: BaseSubsystem if (p(SubsystemDriveAsyncClockGroupsKey).isEmpty) => { + val n = ClockGroupSourceNode(Seq(ClockGroupSourceParameters())) + l.asyncClockGroupsNode := n + Some(n) + } + case _ => None } - val peekPokeBridge = PeekPokeBridge(clock, reset) - // A Seq of partial functions that will instantiate the right bridge only - // if that Mixin trait is present in the target's LazyModule class instance - // - // Apply each partial function to each DUT instance - for ((lazyModule, module) <- targets) { - p(IOBinders).values.foreach(f => f(lazyModule) ++ f(module)) - NodeIdx.increment() + InModuleBody { + val clock = IO(Input(Clock())).suggestName("clock") + val reset = IO(Input(Reset())).suggestName("reset") + + implicitClockSourceNode.out.unzip._1.map { o => + o.clock := clock + o.reset := reset + } + + simpleClockGroupSourceNode.map { n => n.out.unzip._1.map { out: ClockGroupBundle => + out.member.data.foreach { o => + o.clock := clock + o.reset := reset + } + }} + + chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => { + clock := th.harnessClock + reset := th.harnessReset + Nil + }) } } +}) + +class WithFireSimRationalTileDomain(multiplier: Int, divisor: Int) extends Config((site, here, up) => { + case FireSimClockKey => FireSimClockParameters(Seq(RationalClock("TileDomain", multiplier, divisor))) + case ClockingSchemeKey => { chiptop: ChipTop => + implicit val p = chiptop.p + + val implicitClockSourceNode = ClockSourceNode(Seq(ClockSourceParameters())) + chiptop.implicitClockSinkNode := implicitClockSourceNode + + // Drive the diplomaticclock graph of the DigitalTop (if present) + val simpleClockGroupSourceNode = chiptop.lazySystem match { + case l: BaseSubsystem if (p(SubsystemDriveAsyncClockGroupsKey).isEmpty) => { + val n = ClockGroupSourceNode(Seq(ClockGroupSourceParameters())) + l.asyncClockGroupsNode := n + Some(n) + } + case _ => None + } + + InModuleBody { + val uncore_clock = IO(Input(Clock())).suggestName("uncore_clock") + val tile_clock = IO(Input(Clock())).suggestName("tile_clock") + val reset = IO(Input(Reset())).suggestName("reset") + + implicitClockSourceNode.out.unzip._1.map { o => + o.clock := uncore_clock + o.reset := reset + } + + simpleClockGroupSourceNode.map { n => n.out.unzip._1.map { out: ClockGroupBundle => + out.member.elements.map { case (name, data) => + // This is mega hacks, how are you actually supposed to do this? + if (name.contains("core")) { + data.clock := tile_clock + data.reset := ResetCatchAndSync(tile_clock, reset.asBool) + } else { + data.clock := uncore_clock + data.reset := reset + } + } + }} + + chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => { + uncore_clock := th.harnessClock + reset := th.harnessReset + th match { + case f: FireSim => tile_clock := f.additionalClocks(0) + case _ => throw new Exception("FireSimMultiClock must be used with FireSim") + } + Nil + }) + } + } +}) + +class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessSignalReferences { + freechips.rocketchip.util.property.cover.setPropLib(new midas.passes.FireSimPropertyLibrary()) + val clockBridge = Module(new RationalClockBridge(p(FireSimClockKey).additionalClocks:_*)) + val harnessClock = clockBridge.io.clocks.head // This is the reference clock + val additionalClocks = clockBridge.io.clocks.tail + val harnessReset = WireInit(false.B) + val peekPokeBridge = PeekPokeBridge(harnessClock, harnessReset) + def dutReset = { require(false, "dutReset should not be used in Firesim"); false.B } + def success = { require(false, "success should not be used in Firesim"); false.B } + + // Instantiate multiple instances of the DUT to implement supernode + for (i <- 0 until p(NumNodes)) { + // It's not a RC bump without some hacks... + // Copy the AsyncClockGroupsKey to generate a fresh node on each + // instantiation of the dut, otherwise the initial instance will be + // reused across each node + import freechips.rocketchip.subsystem.AsyncClockGroupsKey + val lazyModule = LazyModule(p(BuildTop)(p.alterPartial({ + case AsyncClockGroupsKey => p(AsyncClockGroupsKey).copy + }))) + val module = Module(lazyModule.module) + lazyModule match { case d: HasTestHarnessFunctions => + require(d.harnessFunctions.size == 1, "There should only be 1 harness function to connect clock+reset") + d.harnessFunctions.foreach(_(this)) + ApplyHarnessBinders(this, d.lazySystem, p(HarnessBinders), d.portMap.toMap) + } + + + NodeIdx.increment() + } } diff --git a/generators/firechip/src/main/scala/FireSimMulticlockPOC.scala b/generators/firechip/src/main/scala/FireSimMulticlockPOC.scala deleted file mode 100644 index bf0e0e26..00000000 --- a/generators/firechip/src/main/scala/FireSimMulticlockPOC.scala +++ /dev/null @@ -1,107 +0,0 @@ -//See LICENSE for license details. - -package firesim.firesim - -import chisel3._ - -import freechips.rocketchip.config.{Field, Config, Parameters} -import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, RationalCrossing} -import freechips.rocketchip.subsystem._ -import freechips.rocketchip.util.{ResetCatchAndSync} - -import midas.widgets.{Bridge, PeekPokeBridge, RationalClockBridge, RationalClock} -import firesim.configs._ - -import boom.common.{WithRationalBoomTiles} - -import chipyard.{BuildSystem, DigitalTop, DigitalTopModule} -import chipyard.config.ConfigValName._ -import chipyard.iobinders.{IOBinders} - -// WIP! This file is a sketch of one means of defining a multiclock target-design -// that can be simulated in FireSim, pending a canonicalized form in Chipyard. -// -// Note, the main prerequisite for supporting an additional clock domain in a -// FireSim simulation is to supply an additional clock parameter -// (RationalClock) to the clock bridge (RationalClockBridge). The bridge -// produces a vector of clocks, based on the provided parameter list, which you -// may use freely without further modifications to your target design. - -case class FireSimClockParameters(additionalClocks: Seq[RationalClock]) { - def numClocks(): Int = additionalClocks.size + 1 -} -case object FireSimClockKey extends Field[FireSimClockParameters](FireSimClockParameters(Seq())) - -trait HasAdditionalClocks extends LazyModuleImp { - val clocks = IO(Vec(p(FireSimClockKey).numClocks, Input(Clock()))) -} - -// Presupposes only 1 or 2 clocks. -trait HasFireSimClockingImp extends HasAdditionalClocks { - val outer: HasTiles - val (tileClock, tileReset) = p(FireSimClockKey).additionalClocks.headOption match { - case Some(RationalClock(_, numer, denom)) if numer != denom => (clocks(1), ResetCatchAndSync(clocks(1), reset.toBool)) - case None => (clocks.head, reset) - } - - outer.tiles.foreach({ case tile => - tile.module.clock := tileClock - tile.module.reset := tileReset - }) -} - -// Config Fragment -class WithSingleRationalTileDomain(multiplier: Int, divisor: Int) extends Config( - new WithRationalRocketTiles ++ - new WithRationalBoomTiles ++ - new Config((site, here, up) => { - case FireSimClockKey => FireSimClockParameters(Seq(RationalClock("TileDomain", multiplier, divisor))) - }) -) - -class HalfRateUncore extends WithSingleRationalTileDomain(2,1) - -class WithFiresimMulticlockTop extends Config((site, here, up) => { - case BuildSystem => (p: Parameters) => LazyModule(new FiresimMulticlockTop()(p)).suggestName("system") -}) - -// Complete Config -class FireSimQuadRocketMulticlockConfig extends Config( - new HalfRateUncore ++ - new WithFiresimMulticlockTop ++ - new FireSimQuadRocketConfig) - -// Top Definition -class FiresimMulticlockTop(implicit p: Parameters) extends chipyard.DigitalTop -{ - override lazy val module = new FiresimMulticlockTopModule(this) -} - - -class FiresimMulticlockTopModule[+L <: DigitalTop](l: L) extends chipyard.DigitalTopModule(l) with HasFireSimClockingImp - -// Harness Definition -class FireSimMulticlockPOC(implicit val p: Parameters) extends RawModule { - freechips.rocketchip.util.property.cover.setPropLib(new midas.passes.FireSimPropertyLibrary()) - val clockBridge = Module(new RationalClockBridge(p(FireSimClockKey).additionalClocks:_*)) - val refClock = clockBridge.io.clocks.head - val reset = WireInit(false.B) - withClockAndReset(refClock, reset) { - // Instantiate multiple instances of the DUT to implement supernode - val targets = Seq.fill(p(NumNodes)) { - val lazyModule = p(BuildSystem)(p) - (lazyModule, Module(lazyModule.module)) - } - val peekPokeBridge = PeekPokeBridge(refClock, reset) - // A Seq of partial functions that will instantiate the right bridge only - // if that Mixin trait is present in the target's class instance - // - // Apply each partial function to each DUT instance - for ((lazyModule, module) <- targets) { - p(IOBinders).values.foreach(f => f(lazyModule) ++ f(module)) - } - targets.collect({ case (_, t: HasAdditionalClocks) => t.clocks := clockBridge.io.clocks }) - } -} - - diff --git a/generators/firechip/src/main/scala/TargetConfigs.scala b/generators/firechip/src/main/scala/TargetConfigs.scala index ebd5df43..678afccf 100644 --- a/generators/firechip/src/main/scala/TargetConfigs.scala +++ b/generators/firechip/src/main/scala/TargetConfigs.scala @@ -10,10 +10,10 @@ import freechips.rocketchip.tile._ import freechips.rocketchip.tilelink._ import freechips.rocketchip.rocket.DCacheParams import freechips.rocketchip.subsystem._ -import freechips.rocketchip.devices.tilelink.BootROMParams +import freechips.rocketchip.devices.tilelink.{BootROMLocated, BootROMParams} import freechips.rocketchip.devices.debug.{DebugModuleParams, DebugModuleKey} import freechips.rocketchip.diplomacy.LazyModule -import testchipip.{BlockDeviceKey, BlockDeviceConfig, SerialKey, TracePortKey, TracePortParams} +import testchipip.{BlockDeviceKey, BlockDeviceConfig, TracePortKey, TracePortParams} import sifive.blocks.devices.uart.{PeripheryUARTKey, UARTParams} import scala.math.{min, max} @@ -22,19 +22,18 @@ import testchipip.WithRingSystemBus import firesim.bridges._ import firesim.configs._ -import chipyard.config.ConfigValName._ class WithBootROM extends Config((site, here, up) => { - case BootROMParams => { + case BootROMLocated(x) => { val chipyardBootROM = new File(s"./generators/testchipip/bootrom/bootrom.rv${site(XLen)}.img") val firesimBootROM = new File(s"./target-rtl/chipyard/generators/testchipip/bootrom/bootrom.rv${site(XLen)}.img") - val bootROMPath = if (chipyardBootROM.exists()) { + val bootROMPath = if (chipyardBootROM.exists()) { chipyardBootROM.getAbsolutePath() } else { firesimBootROM.getAbsolutePath() } - BootROMParams(contentFileName = bootROMPath) + up(BootROMLocated(x), site).map(_.copy(contentFileName = bootROMPath)) } }) @@ -67,6 +66,8 @@ class WithNVDLASmall extends nvidia.blocks.dla.WithNVDLA("small") // Tweaks that are generally applied to all firesim configs class WithFireSimConfigTweaks extends Config( + // Required*: Uses FireSim ClockBridge and PeekPokeBridge to drive the system with a single clock/reset + new WithFireSimSimpleClocks ++ // Required*: When using FireSim-as-top to provide a correct path to the target bootrom source new WithBootROM ++ // Optional*: Removing this will require adjusting the UART baud rate and @@ -83,11 +84,13 @@ class WithFireSimConfigTweaks extends Config( // Required: Adds IO to attach SerialBridge. The SerialBridges is responsible // for signalling simulation termination under simulation success. This fragment can // be removed if you supply an auxiliary bridge that signals simulation termination - new testchipip.WithTSI ++ + new testchipip.WithDefaultSerialTL ++ // Optional: Removing this will require using an initramfs under linux new testchipip.WithBlockDevice ++ // Required*: Scale default baud rate with periphery bus frequency - new chipyard.config.WithUART(BigInt(3686400L)) + new chipyard.config.WithUART(BigInt(3686400L)) ++ + // Required: Do not support debug module w. JTAG until FIRRTL stops emitting @(posedge ~clock) + new chipyard.config.WithNoDebug ) /******************************************************************************* @@ -128,7 +131,7 @@ class FireSimSmallSystemConfig extends Config( new WithoutClockGating ++ new WithoutTLMonitors ++ new freechips.rocketchip.subsystem.WithExtMemSize(1 << 28) ++ - new testchipip.WithTSI ++ + new testchipip.WithDefaultSerialTL ++ new testchipip.WithBlockDevice ++ new chipyard.config.WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache(nWays = 2, capacityKB = 64) ++ @@ -186,3 +189,14 @@ class FireSimArianeConfig extends Config( new WithDefaultMemModel ++ new WithFireSimConfigTweaks ++ new chipyard.ArianeConfig) + +//********************************************************************************** +//* Multiclock Configurations +//*********************************************************************************/ +class FireSimMulticlockRocketConfig extends Config( + new WithFireSimRationalTileDomain(2, 1) ++ + new WithDefaultFireSimBridges ++ + new WithDefaultMemModel ++ + new WithFireSimConfigTweaks ++ + new chipyard.DividedClockRocketConfig) + diff --git a/generators/firechip/src/test/scala/ScalaTestSuite.scala b/generators/firechip/src/test/scala/ScalaTestSuite.scala index f92a7960..ea1627b7 100644 --- a/generators/firechip/src/test/scala/ScalaTestSuite.scala +++ b/generators/firechip/src/test/scala/ScalaTestSuite.scala @@ -106,8 +106,8 @@ class BoomF1Tests extends FireSimTestSuite("FireSim", "DDR3FRFCFSLLC4MB_FireSimL class RocketNICF1Tests extends FireSimTestSuite("FireSim", "WithNIC_DDR3FRFCFSLLC4MB_FireSimRocketConfig", "BaseF1Config") // Multiclock tests class RocketMulticlockF1Tests extends FireSimTestSuite( - "FireSimMulticlockPOC", - "FireSimQuadRocketMulticlockConfig", + "FireSim", + "FireSimMulticlockRocketConfig", "WithSynthAsserts_BaseF1Config") class ArianeF1Tests extends FireSimTestSuite("FireSim", "WithNIC_DDR3FRFCFSLLC4MB_FireSimArianeConfig", "BaseF1Config") diff --git a/generators/hwacha b/generators/hwacha index a989b697..e29b65db 160000 --- a/generators/hwacha +++ b/generators/hwacha @@ -1 +1 @@ -Subproject commit a989b69759137802b4c39e9ddebb90427455fb79 +Subproject commit e29b65db86e4486ebdfd4f39d1265df83a2d7d9d diff --git a/generators/icenet b/generators/icenet index 705ca506..277a9080 160000 --- a/generators/icenet +++ b/generators/icenet @@ -1 +1 @@ -Subproject commit 705ca50690383aa589dc560a5e7c152af04c46ad +Subproject commit 277a9080fe92afb25d942f3207252e0ddea1b864 diff --git a/generators/rocket-chip b/generators/rocket-chip index 653efa99..6eb1a3de 160000 --- a/generators/rocket-chip +++ b/generators/rocket-chip @@ -1 +1 @@ -Subproject commit 653efa99a27dc155bd4b4706a7e71c5c930f62b1 +Subproject commit 6eb1a3de082e27c752d9e4c1ae971c693cc192eb diff --git a/generators/testchipip b/generators/testchipip index 3366844f..bdca33ec 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit 3366844f50a7969f1997125c07ce8d00e5494cf0 +Subproject commit bdca33ec1684e6e00df2f5c9aebc0b41fb593585 diff --git a/generators/tracegen/src/main/scala/System.scala b/generators/tracegen/src/main/scala/System.scala index ca3572d7..83f6a5e4 100644 --- a/generators/tracegen/src/main/scala/System.scala +++ b/generators/tracegen/src/main/scala/System.scala @@ -12,6 +12,10 @@ class TraceGenSystem(implicit p: Parameters) extends BaseSubsystem with CanHaveMasterAXI4MemPort { def coreMonitorBundles = Nil + val tileStatusNodes = tiles.collect { + case t: GroundTestTile => t.statusNode.makeSink() + case t: BoomTraceGenTile => t.statusNode.makeSink() + } override lazy val module = new TraceGenSystemModuleImp(this) } @@ -20,12 +24,8 @@ class TraceGenSystemModuleImp(outer: TraceGenSystem) { val success = IO(Output(Bool())) - outer.tiles.zipWithIndex.map { case(t, i) => t.module.constants.hartid := i.U } + val status = dontTouch(DebugCombiner(outer.tileStatusNodes.map(_.bundle))) - val status = dontTouch(DebugCombiner(outer.tiles.collect { - case t: GroundTestTile => t.module.status - case t: BoomTraceGenTile => t.module.status - })) success := outer.tileCeaseSinkNode.in.head._1.asUInt.andR } diff --git a/generators/tracegen/src/main/scala/Tile.scala b/generators/tracegen/src/main/scala/Tile.scala index 1ddf0d84..5ff9af56 100644 --- a/generators/tracegen/src/main/scala/Tile.scala +++ b/generators/tracegen/src/main/scala/Tile.scala @@ -3,7 +3,7 @@ package tracegen import chisel3._ import chisel3.util._ import freechips.rocketchip.config.Parameters -import freechips.rocketchip.diplomacy.{SimpleDevice, LazyModule, SynchronousCrossing, ClockCrossingType} +import freechips.rocketchip.diplomacy.{SimpleDevice, LazyModule, SynchronousCrossing, ClockCrossingType, BundleBridgeSource} import freechips.rocketchip.groundtest._ import freechips.rocketchip.rocket._ import freechips.rocketchip.rocket.constants.{MemoryOpConstants} @@ -206,11 +206,13 @@ class BoomTraceGenTile private( val cpuDevice: SimpleDevice = new SimpleDevice("groundtest", Nil) val intOutwardNode: IntOutwardNode = IntIdentityNode() val slaveNode: TLInwardNode = TLIdentityNode() + val statusNode = BundleBridgeSource(() => new GroundTestStatus) val boom_params = p.alterMap(Map(TileKey -> BoomTileParams( dcache=params.dcache, - core=BoomCoreParams(nPMPs=0, numLdqEntries=32, numStqEntries=32, useVM=false)))) - val dcache = LazyModule(new BoomNonBlockingDCache(hartId)(boom_params)) + core=BoomCoreParams(nPMPs=0, numLdqEntries=16, numStqEntries=16, useVM=false)))) + val dcache = LazyModule(new BoomNonBlockingDCache(staticIdForMetadataUseOnly)(boom_params)) + val masterNode: TLOutwardNode = TLIdentityNode() := visibilityNode := dcache.node @@ -220,11 +222,11 @@ class BoomTraceGenTile private( class BoomTraceGenTileModuleImp(outer: BoomTraceGenTile) extends BaseTileModuleImp(outer){ - val status = IO(new GroundTestStatus) + val status = outer.statusNode.bundle val halt_and_catch_fire = None val tracegen = Module(new TraceGenerator(outer.params.traceParams)) - tracegen.io.hartid := constants.hartid + tracegen.io.hartid := outer.hartIdSinkNode.bundle val ptw = Module(new DummyPTW(1)) val lsu = Module(new LSU()(outer.boom_params, outer.dcache.module.edge)) diff --git a/generators/utilities/src/main/resources/csrc/emulator.cc b/generators/utilities/src/main/resources/csrc/emulator.cc index 27a8aa4a..5e0ea38b 100644 --- a/generators/utilities/src/main/resources/csrc/emulator.cc +++ b/generators/utilities/src/main/resources/csrc/emulator.cc @@ -1,11 +1,15 @@ // See LICENSE.SiFive for license details. // See LICENSE.Berkeley for license details. -#include "verilated.h" #if VM_TRACE #include +#if CY_FST_TRACE +#include "verilated_fst_c.h" +#else +#include "verilated.h" #include "verilated_vcd_c.h" -#endif +#endif // CY_FST_TRACE +#endif // VM_TRACE #include #include #include "remote_bitbang.h" @@ -110,9 +114,10 @@ int main(int argc, char** argv) uint64_t max_cycles = -1; int ret = 0; bool print_cycles = false; - // Port numbers are 16 bit unsigned integers. + // Port numbers are 16 bit unsigned integers. uint16_t rbb_port = 0; #if VM_TRACE + const char* vcdfile_name = NULL; FILE * vcdfile = NULL; uint64_t start = 0; #endif @@ -157,6 +162,7 @@ int main(int argc, char** argv) case 'o': opterr = 1; break; #if VM_TRACE case 'v': { + vcdfile_name = optarg; vcdfile = strcmp(optarg, "-") == 0 ? stdout : fopen(optarg, "w"); if (!vcdfile) { std::cerr << "Unable to open " << optarg << " for VCD write\n"; @@ -264,17 +270,20 @@ done_processing: #if VM_TRACE Verilated::traceEverOn(true); // Verilator must compute traced signals +#if CY_FST_TRACE + std::unique_ptr tfp(new VerilatedFstC); +#else std::unique_ptr vcdfd(new VerilatedVcdFILE(vcdfile)); std::unique_ptr tfp(new VerilatedVcdC(vcdfd.get())); - if (vcdfile) { +#endif // CY_FST_TRACE + if (vcdfile_name) { tile->trace(tfp.get(), 99); // Trace 99 levels of hierarchy - tfp->open(""); + tfp->open(vcdfile_name); } -#endif +#endif // VM_TRACE + // RocketChip currently only supports RBB port 0, so this needs to stay here jtag = new remote_bitbang_t(rbb_port); - dtm = new dtm_t(argc, argv); - tsi = new tsi_t(argc, argv); signal(SIGTERM, handle_sigterm); @@ -304,8 +313,7 @@ done_processing: tile->reset = 0; done_reset = true; - while (!dtm->done() && !jtag->done() && !tsi->done() && - !tile->io_success && trace_count < max_cycles) { + do { tile->clock = 0; tile->eval(); #if VM_TRACE @@ -322,6 +330,13 @@ done_processing: #endif trace_count++; } + // for verilator multithreading. need to do 1 loop before checking if + // tsi exists, since tsi is created by verilated thread on the first + // serial_tick. + while ((!dtm || !dtm->done()) && + (!jtag || !jtag->done()) && + (!tsi || !tsi->done()) && + !tile->io_success && trace_count < max_cycles); #if VM_TRACE if (tfp) @@ -330,17 +345,17 @@ done_processing: fclose(vcdfile); #endif - if (dtm->exit_code()) + if (dtm && 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()) + else if (tsi && 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()) + else if (jtag && 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(); diff --git a/scripts/build-toolchains.sh b/scripts/build-toolchains.sh index 62a2f74b..2685872e 100755 --- a/scripts/build-toolchains.sh +++ b/scripts/build-toolchains.sh @@ -6,8 +6,8 @@ set -e set -o pipefail -RDIR=$(pwd) -CHIPYARD_DIR="${CHIPYARD_DIR:-$(git rev-parse --show-toplevel)}" +DIR="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" +CHIPYARD_DIR="$(dirname "$DIR")" usage() { echo "usage: ${0} [OPTIONS] [riscv-tools | esp-tools | ec2fast]" @@ -134,18 +134,16 @@ SRCDIR="$(pwd)/toolchains" module_all qemu --prefix="${RISCV}" --target-list=ris git submodule update --init $CHIPYARD_DIR/tools/dromajo/dromajo-src make -C $CHIPYARD_DIR/tools/dromajo/dromajo-src/src -cd "$RDIR" - # create specific env.sh -{ - echo "# auto-generated by build-toolchains.sh" - echo "export CHIPYARD_TOOLCHAIN_SOURCED=1" - echo "export RISCV=$(printf '%q' "$RISCV")" - echo "export PATH=\${RISCV}/bin:\${PATH}" - echo "export LD_LIBRARY_PATH=\${RISCV}/lib\${LD_LIBRARY_PATH:+":\${LD_LIBRARY_PATH}"}" -} > env-$TOOLCHAIN.sh +cat > "$CHIPYARD_DIR/env-$TOOLCHAIN.sh" <> env.sh -echo "source \$( realpath \$(dirname "\${BASH_SOURCE[0]:-\${\(%\):-%x}}") )/env-$TOOLCHAIN.sh" >> env.sh +echo "source $(printf '%q' "$CHIPYARD_DIR/env-$TOOLCHAIN.sh")" >> env.sh echo "Toolchain Build Complete!" diff --git a/scripts/build-util.sh b/scripts/build-util.sh index 10a7cb7b..892b274d 100644 --- a/scripts/build-util.sh +++ b/scripts/build-util.sh @@ -15,7 +15,7 @@ case ${ncpu} in esac # Allow user to override MAKE -[ -n "${MAKE}" ] || MAKE=$(command -v gnumake || command -v gmake || command -v make) +[ -n "${MAKE:+x}" ] || MAKE=$(command -v gnumake || command -v gmake || command -v make) readonly MAKE diff --git a/scripts/init-submodules-no-riscv-tools-nolog.sh b/scripts/init-submodules-no-riscv-tools-nolog.sh index d91e89b9..cede5e47 100755 --- a/scripts/init-submodules-no-riscv-tools-nolog.sh +++ b/scripts/init-submodules-no-riscv-tools-nolog.sh @@ -17,10 +17,11 @@ if [ "$MINGIT" != "$(echo -e "$MINGIT\n$MYGIT" | sort -V | head -n1)" ]; then false fi -RDIR=$(git rev-parse --show-toplevel) +DIR="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" +CHIPYARD_DIR="$(dirname "$DIR")" # Ignore toolchain submodules -cd "$RDIR" +cd "$CHIPYARD_DIR" for name in toolchains/*-tools/*/ ; do git config submodule."${name%/}".update none done @@ -71,8 +72,11 @@ git config submodule.sims/firesim.update none git submodule update --init software/firemarshal # Configure firemarshal to know where our firesim installation is -if [ ! -f $RDIR/software/firemarshal/marshal-config.yaml ]; then - echo "firesim-dir: '../../sims/firesim/'" > $RDIR/software/firemarshal/marshal-config.yaml +if [ ! -f ./software/firemarshal/marshal-config.yaml ]; then + echo "firesim-dir: '../../sims/firesim/'" > ./software/firemarshal/marshal-config.yaml fi -echo "# line auto-generated by init-submodules-no-riscv-tools.sh" >> $RDIR/env.sh -echo "PATH=\$( realpath \$(dirname "\${BASH_SOURCE[0]:-\${\(%\):-%x}}") )/software/firemarshal:\$PATH" >> $RDIR/env.sh + +echo "# line auto-generated by init-submodules-no-riscv-tools.sh" >> env.sh +echo '__DIR="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"' >> env.sh +echo "PATH=\$__DIR/bin:\$PATH" >> env.sh +echo "PATH=\$__DIR/software/firemarshal:\$PATH" >> env.sh diff --git a/scripts/numa_prefix b/scripts/numa_prefix new file mode 100755 index 00000000..b9521cbd --- /dev/null +++ b/scripts/numa_prefix @@ -0,0 +1,76 @@ +#!/usr/bin/env python + +#============================================================================ +# - really simple script, which just prints out the numactl cmd to +# prefix before your actual command. it determines this based on free +# memory size attached to every node. +# - when you run this on a machine without `numactl`, the output is empty, +# so `$(numa_prefix) ` turns in to ` `. +# - when the machine has `numactl` installed, regardless of the socket-count +# on the machine, the resulting command is: +# `numactl -m -C -- ` +# - example output from `numactl -H` on a 2 socket machine: +# available: 2 nodes (0-1) +# node 0 cpus: 0 2 4 6 8 10 12 14 16 18 20 22 +# node 0 size: 131026 MB +# node 0 free: 7934 MB +# node 1 cpus: 1 3 5 7 9 11 13 15 17 19 21 23 +# node 1 size: 65536 MB +# node 1 free: 429 MB +# node distances: +# node 0 1 +# 0: 10 20 +# 1: 20 10 +#============================================================================ + +import subprocess +import re +import sys + +which_proc = subprocess.Popen(["which", "numactl"], stdout=subprocess.PIPE) +out, err = which_proc.communicate() + +if out != "": + numactl_proc = subprocess.Popen(["numactl", "-H"], stdout=subprocess.PIPE) + out, err = numactl_proc.communicate() + + lines = out.split("\n") + line_idx = 0 + + head_line = lines[line_idx] + line_idx += 1 + node_match = re.match(r"^ *available: +(\d+) nodes", head_line) + if node_match: + avail_nodes = node_match.group(1) + best_node_id = "" + best_cpus = "" + best_free_size = 0 + + # loop through available nodes, selecting the node with the most free mem + for i in avail_nodes: + cpu_line = lines[line_idx] + # mem. size unused. skip and use mem. free + mem_free_line = lines[line_idx + 2] + line_idx += 3 + + cpu_match = re.match(r"^ *node (\d+) cpus: (\d.*\d)$", cpu_line) + if cpu_match: + node_id = cpu_match.group(1) + cpus = cpu_match.group(2).replace(" ", ",") + + mem_free_match = re.match(r"^ *node " + node_id + " free: (\d+) \S+$", mem_free_line) + if mem_free_match: + free_size = mem_free_match.group(1) + if int(free_size) > int(best_free_size): + best_node_id = node_id + best_cpus = cpus + best_free_size = free_size + else: + sys.exit("[ERROR] Malformed mem free line: " + mem_free_line) + + else: + sys.exit("[ERROR] Malformed cpus line: " + cpu_line) + + sys.stdout.write("numactl -m " + best_node_id + " -C " + best_cpus + " --") + else: + sys.exit("[ERROR] Malformed head line: " + head_line) diff --git a/scripts/smartelf2hex.sh b/scripts/smartelf2hex.sh index 782977ff..dd035690 100755 --- a/scripts/smartelf2hex.sh +++ b/scripts/smartelf2hex.sh @@ -8,7 +8,9 @@ binary=$1 segments=`readelf --segments --wide $binary` entry_hex=`echo -e "$segments" | grep "Entry point" | cut -f3 -d' ' | sed 's/0x//' | tr [:lower:] [:upper:]` entry_dec=`bc <<< "ibase=16;$entry_hex"` -length_hex=`echo "$segments" | grep LOAD | tail -n 1 | tr -s [:space:] | cut -f4,6 -d' '` +length_hex=`echo "$segments" | grep "LOAD\|TLS" | tail -n 1 | tr -s [:space:] | cut -f4,6 -d' '` length_dec=`echo $length_hex | tr -d x | tr [:lower:] [:upper:] | tr ' ' + | sed 's/^/ibase=16;/' | sed "s/$/-$entry_hex/" | bc` power_2_length=`echo "x=l($length_dec)/l(2); scale=0; 2^((x+1)/1)" | bc -l` -elf2hex 64 $power_2_length $binary $entry_dec +width=64 +depth=$((power_2_length / width)) +elf2hex $width $depth $binary $entry_dec diff --git a/scripts/ubuntu-req.sh b/scripts/ubuntu-req.sh index f72c48f4..a4697174 100755 --- a/scripts/ubuntu-req.sh +++ b/scripts/ubuntu-req.sh @@ -24,4 +24,4 @@ sudo apt-get install -y device-tree-compiler git clone http://git.veripool.org/git/verilator cd verilator git checkout v4.034 -autoconf && ./configure && make -j16 && sudo make install +autoconf && ./configure && make -j$(nproc) && sudo make install diff --git a/sims/common-sim-flags.mk b/sims/common-sim-flags.mk new file mode 100644 index 00000000..766dd0d3 --- /dev/null +++ b/sims/common-sim-flags.mk @@ -0,0 +1,23 @@ +#---------------------------------------------------------------------------------------- +# common gcc configuration/optimization +#---------------------------------------------------------------------------------------- +SIM_OPT_CXXFLAGS := -O3 + +SIM_CXXFLAGS = \ + $(CXXFLAGS) \ + $(SIM_OPT_CXXFLAGS) \ + -std=c++11 \ + -I$(RISCV)/include \ + -I$(dramsim_dir) \ + -I$(build_dir) \ + $(EXTRA_SIM_CXXFLAGS) + +SIM_LDFLAGS = \ + $(LDFLAGS) \ + -L$(RISCV)/lib \ + -Wl,-rpath,$(RISCV)/lib \ + -L$(sim_dir) \ + -L$(dramsim_dir) \ + -lfesvr \ + -ldramsim \ + $(EXTRA_SIM_LDFLAGS) diff --git a/sims/firesim b/sims/firesim index b13e7529..3dbe8aee 160000 --- a/sims/firesim +++ b/sims/firesim @@ -1 +1 @@ -Subproject commit b13e75296c44b1f3fa987d15df6a595668842dfe +Subproject commit 3dbe8aee3f917079e7319391bac5d23d2ba5e6de diff --git a/sims/vcs/Makefile b/sims/vcs/Makefile index 14ebae59..2c44ae6e 100644 --- a/sims/vcs/Makefile +++ b/sims/vcs/Makefile @@ -41,16 +41,24 @@ include $(base_dir)/common.mk ######################################################################################### VCS = vcs -full64 -VCS_OPTS = -notice -line $(VCS_CC_OPTS) $(VCS_NONCC_OPTS) $(VCS_DEFINE_OPTS) $(EXTRA_SIM_SOURCES) +VCS_OPTS = $(VCS_CC_OPTS) $(VCS_NONCC_OPTS) $(PREPROC_DEFINES) + +######################################################################################### +# vcs build paths +######################################################################################### +model_dir = $(build_dir)/$(long_name) +model_dir_debug = $(build_dir)/$(long_name).debug ######################################################################################### # vcs simulator rules ######################################################################################### $(sim): $(sim_vsrcs) $(sim_common_files) $(dramsim_lib) $(EXTRA_SIM_REQS) - rm -rf csrc && $(VCS) $(VCS_OPTS) -o $@ + rm -rf $(model_dir) + $(VCS) $(VCS_OPTS) $(EXTRA_SIM_SOURCES) -o $@ -Mdir=$(model_dir) $(sim_debug): $(sim_vsrcs) $(sim_common_files) $(dramsim_lib) $(EXTRA_SIM_REQS) - rm -rf csrc && $(VCS) $(VCS_OPTS) -o $@ \ + rm -rf $(model_dir_debug) + $(VCS) $(VCS_OPTS) $(EXTRA_SIM_SOURCES) -o $@ -Mdir=$(model_dir_debug) \ +define+DEBUG ######################################################################################### @@ -61,8 +69,14 @@ $(output_dir)/%.vpd: $(output_dir)/% $(sim_debug) (set -o pipefail && $(sim_debug) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(VERBOSE_FLAGS) +vcdplusfile=$@ $(PERMISSIVE_OFF) $< >(spike-dasm > $<.out) | tee $<.log) ######################################################################################### -# general cleanup rule +# general cleanup rules ######################################################################################### -.PHONY: clean +.PHONY: clean clean-sim clean-sim-debug clean: - rm -rf $(gen_dir) csrc $(sim_prefix)-* ucli.key vc_hdrs.h + rm -rf $(gen_dir) $(sim_prefix)-* ucli.key + +clean-sim: + rm -rf $(model_dir) $(build_dir)/vc_hdrs.h $(sim) $(sim).daidir ucli.key + +clean-sim-debug: + rm -rf $(model_dir_debug) $(build_dir)/vc_hdrs.h $(sim_debug) $(sim_debug).daidir ucli.key diff --git a/sims/verilator/Makefile b/sims/verilator/Makefile index f093fa2d..8c51098f 100644 --- a/sims/verilator/Makefile +++ b/sims/verilator/Makefile @@ -22,7 +22,7 @@ include $(base_dir)/variables.mk sim_name = verilator ######################################################################################### -# vcs simulator types and rules +# verilator simulator types and rules ######################################################################################### sim_prefix = simulator sim = $(sim_dir)/$(sim_prefix)-$(MODEL_PACKAGE)-$(CONFIG) @@ -47,35 +47,53 @@ debug: $(sim_debug) include $(base_dir)/common.mk ######################################################################################### -# verilator binary and flags +# verilator-specific user-interface variables and commands +######################################################################################### +HELP_COMPILATION_VARIABLES += \ +" VERILATOR_PROFILE = 'none' if no verilator profiling (default)" \ +" 'all' if full verilator runtime profiling" \ +" 'threads' if runtime thread profiling only" \ +" VERILATOR_THREADS = how many threads the simulator will use (default 1)" \ +" VERILATOR_FST_MODE = enable FST waveform instead of VCD. use with debug build" + +######################################################################################### +# verilator/cxx binary and flags ######################################################################################### VERILATOR := verilator --cc --exe -CXXFLAGS := \ - $(CXXFLAGS) -O1 -std=c++11 \ - -I$(RISCV)/include \ - -I$(dramsim_dir) \ - -D__STDC_FORMAT_MACROS \ - $(EXTRA_SIM_CC_FLAGS) +#---------------------------------------------------------------------------------------- +# user configs +#---------------------------------------------------------------------------------------- +VERILATOR_PROFILE ?= none +RUNTIME_PROFILING_CFLAGS := $(if $(filter $(VERILATOR_PROFILE),all),-g -pg,) +RUNTIME_PROFILING_VFLAGS := $(if $(filter $(VERILATOR_PROFILE),all),\ + --prof-threads --prof-cfuncs,\ + $(if $(filter $(VERILATOR_PROFILE),threads),\ + --prof-threads,)) -LDFLAGS := \ - $(LDFLAGS) \ - -L$(sim_dir) \ - -lpthread +VERILATOR_THREADS ?= 1 +RUNTIME_THREADS := --threads $(VERILATOR_THREADS) --threads-dpi all -VERILATOR_CC_OPTS = \ +VERILATOR_FST_MODE ?= 0 +TRACING_OPTS := $(if $(filter $(VERILATOR_FST_MODE),0),\ + --trace,--trace-fst --trace-threads 1) +TRACING_CFLAGS := $(if $(filter $(VERILATOR_FST_MODE),0),,-DCY_FST_TRACE) + +#---------------------------------------------------------------------------------------- +# verilation configuration/optimization +#---------------------------------------------------------------------------------------- +# we initially had --noassert for performance, but several modules use +# assertions, including dramsim, so we enable --assert by default +VERILATOR_OPT_FLAGS := \ -O3 \ - -CFLAGS "$(CXXFLAGS) -DTEST_HARNESS=V$(VLOG_MODEL) -DVERILATOR" \ - -CFLAGS "-I$(build_dir) -include $(build_dir)/$(long_name).plusArgs -include $(build_dir)/verilator.h" \ - -LDFLAGS "$(LDFLAGS)" \ - $(RISCV)/lib/libfesvr.a \ - $(dramsim_lib) + --x-assign fast \ + --x-initial fast \ + --output-split 10000 \ + --output-split-cfuncs 100 -# default flags added for ariane -ARIANE_VERILATOR_FLAGS = \ +# default flags added for external IP (ariane/NVDLA) +VERILOG_IP_VERILATOR_FLAGS := \ --unroll-count 256 \ - -Werror-PINMISSING \ - -Werror-IMPLICIT \ -Wno-PINCONNECTEMPTY \ -Wno-ASSIGNDLY \ -Wno-DECLFILENAME \ @@ -85,29 +103,66 @@ ARIANE_VERILATOR_FLAGS = \ -Wno-style \ -Wall -# normal flags used for chipyard builds (that are incompatible with ariane) -CHIPYARD_VERILATOR_FLAGS = \ +# normal flags used for chipyard builds (that are incompatible with vlog ip aka ariane/NVDLA) +CHIPYARD_VERILATOR_FLAGS := \ --assert +# options dependent on whether external IP (ariane/NVDLA) or just chipyard is used +# NOTE: defer the evaluation of this until it is used! +PLATFORM_OPTS = $(shell \ + if grep -qiP "module\s+(Ariane|NVDLA)" $(build_dir)/*.*v; \ + then echo "$(VERILOG_IP_VERILATOR_FLAGS)"; \ + else echo "$(CHIPYARD_VERILATOR_FLAGS)"; fi) + # Use --timescale to approximate timescale behavior of pre-4.034 TIMESCALE_OPTS := $(shell verilator --version | perl -lne 'if (/(\d.\d+)/ && $$1 >= 4.034) { print "--timescale 1ns/1ps"; }') -VERILATOR_NONCC_OPTS = \ - $(TIMESCALE_OPTS) \ - --top-module $(VLOG_MODEL) \ - --vpi \ - -Wno-fatal \ - $(shell if ! grep -iq "module.*ariane" $(build_dir)/*.*v; then echo "$(CHIPYARD_VERILATOR_FLAGS)"; else echo "$(ARIANE_VERILATOR_FLAGS)"; fi) \ - --output-split 10000 \ - --output-split-cfuncs 100 \ - --max-num-width 1048576 \ - -f $(sim_common_files) \ - $(sim_vsrcs) -VERILATOR_DEFINES = \ +# see: https://github.com/ucb-bar/riscv-mini/issues/31 +MAX_WIDTH_OPTS = $(shell verilator --version | perl -lne 'if (/(\d.\d+)/ && $$1 > 4.016) { print "--max-num-width 1048576"; }') + +PREPROC_DEFINES := \ +define+PRINTF_COND=\$$c\(\"verbose\",\"\&\&\"\,\"done_reset\"\) \ +define+STOP_COND=\$$c\(\"done_reset\"\) -VERILATOR_OPTS = $(VERILATOR_CC_OPTS) $(VERILATOR_NONCC_OPTS) $(VERILATOR_DEFINES) $(EXTRA_SIM_SOURCES) +VERILATOR_NONCC_OPTS = \ + $(RUNTIME_PROFILING_VFLAGS) \ + $(RUNTIME_THREADS) \ + $(VERILATOR_OPT_FLAGS) \ + $(PLATFORM_OPTS) \ + -Wno-fatal \ + $(TIMESCALE_OPTS) \ + $(MAX_WIDTH_OPTS) \ + $(PREPROC_DEFINES) \ + --top-module $(VLOG_MODEL) \ + --vpi \ + -f $(sim_common_files) \ + $(sim_vsrcs) + +#---------------------------------------------------------------------------------------- +# gcc configuration/optimization +#---------------------------------------------------------------------------------------- +include $(base_dir)/sims/common-sim-flags.mk + +VERILATOR_CXXFLAGS = \ + $(SIM_CXXFLAGS) \ + $(RUNTIME_PROFILING_CFLAGS) \ + $(TRACING_CFLAGS) \ + -D__STDC_FORMAT_MACROS \ + -DTEST_HARNESS=V$(VLOG_MODEL) \ + -DVERILATOR \ + -include $(build_dir)/$(long_name).plusArgs \ + -include $(build_dir)/verilator.h + +VERILATOR_LDFLAGS = $(SIM_LDFLAGS) + +VERILATOR_CC_OPTS = \ + -CFLAGS "$(VERILATOR_CXXFLAGS)" \ + -LDFLAGS "$(VERILATOR_LDFLAGS)" + +#---------------------------------------------------------------------------------------- +# full verilator+gcc opts +#---------------------------------------------------------------------------------------- +VERILATOR_OPTS = $(VERILATOR_CC_OPTS) $(VERILATOR_NONCC_OPTS) ######################################################################################### # verilator build paths and file names @@ -127,13 +182,13 @@ model_mk_debug = $(model_dir_debug)/V$(VLOG_MODEL).mk $(model_mk): $(sim_vsrcs) $(sim_common_files) $(EXTRA_SIM_REQS) rm -rf $(model_dir) mkdir -p $(model_dir) - $(VERILATOR) $(VERILATOR_OPTS) -o $(sim) -Mdir $(model_dir) -CFLAGS "-include $(model_header)" + $(VERILATOR) $(VERILATOR_OPTS) $(EXTRA_SIM_SOURCES) -o $(sim) -Mdir $(model_dir) -CFLAGS "-include $(model_header)" touch $@ $(model_mk_debug): $(sim_vsrcs) $(sim_common_files) $(EXTRA_SIM_REQS) rm -rf $(model_dir_debug) mkdir -p $(model_dir_debug) - $(VERILATOR) $(VERILATOR_OPTS) -o $(sim_debug) --trace -Mdir $(model_dir_debug) -CFLAGS "-include $(model_header_debug)" + $(VERILATOR) $(VERILATOR_OPTS) $(EXTRA_SIM_SOURCES) -o $(sim_debug) $(TRACING_OPTS) -Mdir $(model_dir_debug) -CFLAGS "-include $(model_header_debug)" touch $@ ######################################################################################### @@ -152,11 +207,17 @@ $(sim_debug): $(model_mk_debug) $(dramsim_lib) $(output_dir)/%.vpd: $(output_dir)/% $(sim_debug) rm -f $@.vcd && mkfifo $@.vcd vcd2vpd $@.vcd $@ > /dev/null & - (set -o pipefail && $(sim_debug) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(SEED_FLAG) $(VERBOSE_FLAGS) -v$@.vcd $(PERMISSIVE_OFF) $< >(spike-dasm > $<.out) | tee $<.log) + (set -o pipefail && $(NUMA_PREFIX) $(sim_debug) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(SEED_FLAG) $(VERBOSE_FLAGS) -v$@.vcd $(PERMISSIVE_OFF) $< >(spike-dasm > $<.out) | tee $<.log) ######################################################################################### -# general cleanup rule +# general cleanup rules ######################################################################################### -.PHONY: clean +.PHONY: clean clean-sim clean-sim-debug clean: rm -rf $(gen_dir) $(sim_prefix)-* + +clean-sim: + rm -rf $(model_dir) $(sim) + +clean-sim-debug: + rm -rf $(model_dir_debug) $(sim_debug) diff --git a/toolchains/esp-tools/riscv-isa-sim b/toolchains/esp-tools/riscv-isa-sim index a1ff6b03..fa94e84d 160000 --- a/toolchains/esp-tools/riscv-isa-sim +++ b/toolchains/esp-tools/riscv-isa-sim @@ -1 +1 @@ -Subproject commit a1ff6b03f7f630a06327798238256973568e3837 +Subproject commit fa94e84d4ff3e23ba909a63376b294e444234752 diff --git a/toolchains/esp-tools/riscv-tests b/toolchains/esp-tools/riscv-tests index f1370d05..e116930c 160000 --- a/toolchains/esp-tools/riscv-tests +++ b/toolchains/esp-tools/riscv-tests @@ -1 +1 @@ -Subproject commit f1370d054389fc83974fc820985b5c51693b8f9d +Subproject commit e116930c7d4a30fc2a1378417089a089e9e4cad0 diff --git a/toolchains/riscv-tools/riscv-isa-sim b/toolchains/riscv-tools/riscv-isa-sim index 8d860c19..acd953af 160000 --- a/toolchains/riscv-tools/riscv-isa-sim +++ b/toolchains/riscv-tools/riscv-isa-sim @@ -1 +1 @@ -Subproject commit 8d860c190640e19e0f23a21d2479b4a36d13d342 +Subproject commit acd953afd2f52d64e2264c2c7c713dc0ad614406 diff --git a/toolchains/riscv-tools/riscv-openocd b/toolchains/riscv-tools/riscv-openocd index 7c82a7b9..cbb15587 160000 --- a/toolchains/riscv-tools/riscv-openocd +++ b/toolchains/riscv-tools/riscv-openocd @@ -1 +1 @@ -Subproject commit 7c82a7b9d5b7d8b71e0a66826705ec141db718c3 +Subproject commit cbb15587dc782ac8ade7ae252e7b760cfba4a178 diff --git a/toolchains/riscv-tools/riscv-tests b/toolchains/riscv-tools/riscv-tests index 249796ce..19bfdab4 160000 --- a/toolchains/riscv-tools/riscv-tests +++ b/toolchains/riscv-tools/riscv-tests @@ -1 +1 @@ -Subproject commit 249796cec94d75ff10ca034153e206a319e87158 +Subproject commit 19bfdab48c2a6da4a2c67d5779757da7b073811d diff --git a/tools/barstools b/tools/barstools index aa1c90c4..4a5c75fc 160000 --- a/tools/barstools +++ b/tools/barstools @@ -1 +1 @@ -Subproject commit aa1c90c4ccb73c2c379550f3296892cc81e8a195 +Subproject commit 4a5c75fcf85f03af858f1d7db04303d4b0733de7 diff --git a/tools/chisel3 b/tools/chisel3 index 21ea734d..cc2971fe 160000 --- a/tools/chisel3 +++ b/tools/chisel3 @@ -1 +1 @@ -Subproject commit 21ea734d809395962a8d3195a76377f6e44308f3 +Subproject commit cc2971feb15d4bc8cb4a8138b5a095ccbc92dcc3 diff --git a/tools/dromajo/dromajo.mk b/tools/dromajo/dromajo.mk index 067faa2f..2069b394 100644 --- a/tools/dromajo/dromajo.mk +++ b/tools/dromajo/dromajo.mk @@ -49,7 +49,7 @@ ifdef ENABLE_DROMAJO EXTRA_SIM_FLAGS += $(DROMAJO_FLAGS) # CC flags needed for all simulations -EXTRA_SIM_CC_FLAGS += -I$(DROMAJO_DIR) +EXTRA_SIM_CXXFLAGS += -I$(DROMAJO_DIR) # sourced needed for simulation EXTRA_SIM_SOURCES += $(DROMAJO_LIB) diff --git a/tools/firrtl b/tools/firrtl index 7c6f58d9..c07da8a5 160000 --- a/tools/firrtl +++ b/tools/firrtl @@ -1 +1 @@ -Subproject commit 7c6f58d986e67b3d0662a4cd6654a68f9cc52cf9 +Subproject commit c07da8a581789b88f7e6ffc98c8e810565034ad9 diff --git a/variables.mk b/variables.mk index d7eccb49..b187a23d 100644 --- a/variables.mk +++ b/variables.mk @@ -1,23 +1,51 @@ ######################################################################################### # makefile variables shared across multiple makefiles +# - to use the help text, your Makefile should have a 'help' target that just +# prints all the HELP_LINES ######################################################################################### +HELP_COMPILATION_VARIABLES = +HELP_PROJECT_VARIABLES = \ +" SUB_PROJECT = use the specific subproject default variables [$(SUB_PROJECT)]" \ +" SBT_PROJECT = the SBT project that you should find the classes/packages in [$(SBT_PROJECT)]" \ +" MODEL = the top level module of the project in Chisel (normally the harness) [$(MODEL)]" \ +" VLOG_MODEL = the top level module of the project in Firrtl/Verilog (normally the harness) [$(VLOG_MODEL)]" \ +" MODEL_PACKAGE = the scala package to find the MODEL in [$(MODEL_PACKAGE)]" \ +" CONFIG = the configuration class to give the parameters for the project [$(CONFIG)]" \ +" CONFIG_PACKAGE = the scala package to find the CONFIG class [$(CONFIG_PACKAGE)]" \ +" GENERATOR_PACKAGE = the scala package to find the Generator class in [$(GENERATOR_PACKAGE)]" \ +" TB = testbench wrapper over the TestHarness needed to simulate in a verilog simulator [$(TB)]" \ +" TOP = top level module of the project (normally the module instantiated by the harness) [$(TOP)]" -######################################################################################### -# variables to invoke the generator -# descriptions: -# SBT_PROJECT = the SBT project that you should find the classes/packages in -# MODEL = the top level module of the project in Chisel (normally the harness) -# VLOG_MODEL = the top level module of the project in Firrtl/Verilog (normally the harness) -# MODEL_PACKAGE = the scala package to find the MODEL in -# CONFIG = the configuration class to give the parameters for the project -# CONFIG_PACKAGE = the scala package to find the CONFIG class -# GENERATOR_PACKAGE = the scala package to find the Generator class in -# TB = wrapper over the TestHarness needed to simulate in a verilog simulator -# TOP = top level module of the project (normally the module instantiated by the harness) -# -# project specific: -# SUB_PROJECT = use the specific subproject default variables -######################################################################################### +HELP_SIMULATION_VARIABLES = \ +" BINARY = riscv elf binary that the simulator will run when using the run-binary* targets" \ +" VERBOSE_FLAGS = flags used when doing verbose simulation [$(VERBOSE_FLAGS)]" + +# include default simulation rules +HELP_COMMANDS = \ +" help = display this help" \ +" default = compiles non-debug simulator [./$(shell basename $(sim))]" \ +" debug = compiles debug simulator [./$(shell basename $(sim_debug))]" \ +" clean = remove all debug/non-debug simulators and intermediate files" \ +" clean-sim = removes non-debug simulator and simulator-generated files" \ +" clean-sim-debug = removes debug simulator and simulator-generated files" + +HELP_LINES = "" \ + " design specifier variables:" \ + " ---------------------------" \ + $(HELP_PROJECT_VARIABLES) \ + "" \ + " compilation variables:" \ + " ----------------------" \ + $(HELP_COMPILATION_VARIABLES) \ + "" \ + " simulation variables:" \ + " ---------------------" \ + $(HELP_SIMULATION_VARIABLES) \ + "" \ + " some useful general commands:" \ + " -----------------------------" \ + $(HELP_COMMANDS) \ + "" ######################################################################################### # subproject overrides @@ -140,7 +168,7 @@ override SCALA_BUILDTOOL_DEPS += $(BLOOP_CONFIG_DIR)/TIMESTAMP # 1) the sed removes a leading {file:} that sometimes needs to be # provided to SBT when a project but not for bloop. # 2) Generally, one could could pass '--' to indicate all remaining arguments are -# destined for the scala Main, however a bug in Bloop's argument parsing causes the +# destined for the scala Main, however a bug in Bloop's argument parsing causes the # --nailgun-port argument to be lost in this case. Workaround this by prefixing # every main-destined argument with "--args" define run_scala_main diff --git a/vcs.mk b/vcs.mk index 93e75c19..c3ba6da6 100644 --- a/vcs.mk +++ b/vcs.mk @@ -11,15 +11,23 @@ endif CLOCK_PERIOD ?= 1.0 RESET_DELAY ?= 777.7 +#---------------------------------------------------------------------------------------- +# gcc configuration/optimization +#---------------------------------------------------------------------------------------- +include $(base_dir)/sims/common-sim-flags.mk + +VCS_CXXFLAGS = $(SIM_CXXFLAGS) +VCS_LDFLAGS = $(SIM_LDFLAGS) + +# vcs requires LDFLAGS to not include library names (i.e. -l needs to be separate) VCS_CC_OPTS = \ - -CC "-I$(RISCV)/include" \ - -CC "-I$(dramsim_dir)" \ - -CC "-std=c++11" \ - -CC "$(EXTRA_SIM_CC_FLAGS)" + -CFLAGS "$(VCS_CXXFLAGS)" \ + -LDFLAGS "$(filter-out -l%,$(VCS_LDFLAGS))" \ + $(filter -l%,$(VCS_LDFLAGS)) VCS_NONCC_OPTS = \ - $(dramsim_lib) \ - $(RISCV)/lib/libfesvr.a \ + -notice \ + -line \ +lint=all,noVCDE,noONGS,noUI \ -error=PCWM-L \ -error=noZMMCM \ @@ -27,7 +35,6 @@ VCS_NONCC_OPTS = \ -quiet \ -q \ +rad \ - +v2k \ +vcs+lic+wait \ +vc+list \ -f $(sim_common_files) \ @@ -35,10 +42,9 @@ VCS_NONCC_OPTS = \ +v2k +verilog2001ext+.v95+.vt+.vp +libext+.v \ -debug_pp \ +incdir+$(build_dir) \ - $(sim_vsrcs) \ - +libext+.v + $(sim_vsrcs) -VCS_DEFINE_OPTS = \ +PREPROC_DEFINES = \ +define+VCS \ +define+CLOCK_PERIOD=$(CLOCK_PERIOD) \ +define+RESET_DELAY=$(RESET_DELAY) \ diff --git a/vlsi/Makefile b/vlsi/Makefile index a9e3d3a5..0e1989dd 100644 --- a/vlsi/Makefile +++ b/vlsi/Makefile @@ -34,7 +34,7 @@ INPUT_CONFS ?= $(if $(filter $(tech_name),nangate45),\ example-asap7.yml) HAMMER_EXEC ?= example-vlsi VLSI_TOP ?= $(TOP) -VLSI_HARNESS_DUT_NAME ?= dut +VLSI_HARNESS_DUT_NAME ?= chiptop VLSI_OBJ_DIR ?= $(vlsi_dir)/build ifneq ($(CUSTOM_VLOG),) OBJ_DIR ?= $(VLSI_OBJ_DIR)/custom-$(VLSI_TOP) @@ -115,15 +115,20 @@ $(SIM_CONF): $(VLSI_RTL) $(HARNESS_FILE) $(HARNESS_SMEMS_FILE) $(sim_common_file done echo " options_meta: 'append'" >> $@ echo " defines:" >> $@ - for x in $(subst +define+,,$(VCS_DEFINE_OPTS)); do \ + for x in $(subst +define+,,$(PREPROC_DEFINES)); do \ echo ' - "'$$x'"' >> $@; \ done echo " defines_meta: 'append'" >> $@ - echo " compiler_opts:" >> $@ - for x in $(filter-out "",$(filter-out -CC,$(VCS_CC_OPTS))); do \ + echo " compiler_cc_opts:" >> $@ + for x in $(filter-out "",$(VCS_CXXFLAGS)); do \ echo ' - "'$$x'"' >> $@; \ done - echo " compiler_opts_meta: 'append'" >> $@ + echo " compiler_cc_opts_meta: 'append'" >> $@ + echo " compiler_ld_opts:" >> $@ + for x in $(filter-out "",$(VCS_LDFLAGS)); do \ + echo ' - "'$$x'"' >> $@; \ + done + echo " compiler_ld_opts_meta: 'append'" >> $@ echo " execution_flags_prepend: ['$(PERMISSIVE_ON)']" >> $@ echo " execution_flags_append: ['$(PERMISSIVE_OFF)']" >> $@ echo " execution_flags:" >> $@ diff --git a/vlsi/hammer b/vlsi/hammer index cbc907df..bed4d340 160000 --- a/vlsi/hammer +++ b/vlsi/hammer @@ -1 +1 @@ -Subproject commit cbc907dfe8005a8d72f1b2fb7b414ad9dbfe14b1 +Subproject commit bed4d34094fa4c72db37a0066050c475eb5e37b2 diff --git a/vlsi/hammer-synopsys-plugins b/vlsi/hammer-synopsys-plugins index e5ec0da8..f8a79222 160000 --- a/vlsi/hammer-synopsys-plugins +++ b/vlsi/hammer-synopsys-plugins @@ -1 +1 @@ -Subproject commit e5ec0da8ad471b075de62989001b282e537416d0 +Subproject commit f8a7922220c70b6905b37ab30bda6c791b594792