diff --git a/.gitignore b/.gitignore index 0f5f7329..324b418a 100644 --- a/.gitignore +++ b/.gitignore @@ -43,5 +43,11 @@ sw/kernel_pulp/bin/ sw/kernel_pulp/headers_bin/ *.wlf +*.fst +*.vcd +*.out *.dbg verilator/build*/ + +# scripts/run_regression.py worktrees and results +.regression/ diff --git a/Bender.lock b/Bender.lock index 70ab582b..7c9e92bd 100644 --- a/Bender.lock +++ b/Bender.lock @@ -87,7 +87,7 @@ packages: Git: https://github.com/pulp-platform/cv32e40x.git dependencies: [] event_unit_flex: - revision: 763c3b9977970f656326c70a96debfb2ac0f85b2 + revision: d0d2b0e664dbd8dab6960f1e0cd77adb884fa0eb version: null source: Git: https://github.com/pulp-platform/event_unit_flex.git @@ -242,7 +242,7 @@ packages: dependencies: - tech_cells_generic spatz: - revision: 9380883fd36a4794d7f31e2c22e3fed3202aeb81 + revision: 3228a9077cb33b4ee235029e8fcace52ed327334 version: null source: Git: https://github.com/pulp-platform/spatz.git diff --git a/Bender.yml b/Bender.yml index 609c1380..230dc9b4 100644 --- a/Bender.yml +++ b/Bender.yml @@ -11,6 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# SPDX-License-Identifier: Apache-2.0 # # Author: Victor Isachi # Luca Balboni @@ -27,7 +28,7 @@ dependencies: redmule : { git: "https://github.com/pulp-platform/redmule.git" , rev: 2.2.0 } cv32e40x : { git: "https://github.com/pulp-platform/cv32e40x.git" , rev: a90101211048ba1a16cedbe4db963ab6e12569d7 } # branch: vi/redmule_scaleup cv32e40p : { git: "https://github.com/FondazioneChipsIT/cv32e40p.git" , rev: 193270df33f76f2728a364bd2d9b1865e0b7e4f9 } # branch: lb/PulpClusterCV32OHWFPU-divsqrt - spatz : { git: "https://github.com/pulp-platform/spatz.git" , rev: 9380883fd36a4794d7f31e2c22e3fed3202aeb81 } # branch: lb/magia-spatz_cc + spatz : { git: "https://github.com/pulp-platform/spatz.git" , rev: 3228a9077cb33b4ee235029e8fcace52ed327334 } # branch: lb/magia-spatz_cc idma : { git: "https://github.com/FondazioneChipsIT/iDMA.git" , rev: 26ac2cd1c535851b14c9c508762203a180961cad } # branch: cc/mcast_magia hwpe-stream : { git: "https://github.com/pulp-platform/hwpe-stream.git" , version: 1.6 } hwpe-ctrl : { git: "https://github.com/pulp-platform/hwpe-ctrl.git" , version: 3.1.1 } @@ -43,23 +44,18 @@ dependencies: tech_cells_generic: { git: "https://github.com/pulp-platform/tech_cells_generic.git", version: 0.2.11 } fractal_sync : { git: "https://github.com/VictorIsachi/fractal_sync" , rev: df8e21b7e2b0e2d3198bf44a60b4ca67c334bcc2 } # branch: main floo_noc : { git: "https://github.com/FondazioneChipsIT/FlooNoC.git" , rev: f3db5e76a5461f590e743e2583f1607ecbabc24e } # branch: cc/row-major - event_unit_flex : { git: "https://github.com/pulp-platform/event_unit_flex.git" , rev: 763c3b9977970f656326c70a96debfb2ac0f85b2 } + event_unit_flex : { git: "https://github.com/pulp-platform/event_unit_flex.git" , rev: d0d2b0e664dbd8dab6960f1e0cd77adb884fa0eb } # branch: lb/eu-two-outstanding export_include_dirs: - hw/include sources: - # MAGIA standalone tile - - target: all(magia_dv, standalone_tile) - defines: - CORE_TRACES: ~ - files: - # NoC - - target/sim/src/tile/floo_axi_nw_mesh_1x2_pkg.sv + # Tile content (magia_isle), shared by every build + - files: # MAGIA Packages - hw/mesh/magia_pkg.sv - hw/tile/magia_tile_pkg.sv - # MAGIA Tile + # MAGIA Tile content - hw/tile/converters/cv32e40p_data2obi.sv - hw/tile/converters/cv32e40x_data2obi.sv - hw/tile/converters/cv32e40p_obi2data.sv @@ -92,15 +88,29 @@ sources: - hw/tile/obi_slave_fsync.sv - hw/tile/obi_slave_ctrl_spatz.sv - hw/tile/obi_slave_ctrl_cluster.sv - - hw/tile/tile_csr.sv - hw/tile/spatz_bootrom.sv - hw/tile/spatz_cc_wrapper.sv - - hw/tile/core_data_demux_eu_direct.sv + - hw/tile/core_data_demux.sv - hw/tile/eu_direct_cut.sv - hw/tile/magia_tile_icache_wrap.sv - hw/tile/magia_redmule_wrap.sv - hw/tile/collective_gen.sv - hw/tile/obi_slave_ctrl_coll.sv + - hw/tile/ctrl_demux.sv + - hw/tile/magia_cluster_wrap.sv + - hw/tile/magia_isle.sv + + - target: all(cv32e40x_bhv, not(verilator)) + files: + - target/verilator/src/cv32e40x_rvfi_sim_trace.sv + - target/verilator/src/cv32e40x_wrapper.sv + + # MAGIA standalone tile + - target: all(magia_dv, standalone_tile) + files: + # NoC + - target/sim/src/tile/floo_axi_nw_mesh_1x2_pkg.sv + # MAGIA Tile - hw/tile/magia_tile.sv # MAGIA DV - target/sim/src/tile/magia_tile_tb_pkg.sv @@ -112,8 +122,6 @@ sources: # MAGIA - target: all(magia_dv, not(standalone_tile)) - defines: - CORE_TRACES: ~ files: # NoC - hw/mesh/noc/floo_axi_nw_mesh_2x2_noc.sv @@ -122,51 +130,8 @@ sources: - hw/mesh/noc/floo_axi_nw_mesh_16x16_noc.sv - hw/mesh/noc/floo_axi_nw_mesh_32x32_noc.sv # MAGIA Packages - - hw/mesh/magia_pkg.sv - - hw/tile/magia_tile_pkg.sv - hw/mesh/noc/magia_noc_pkg.sv # MAGIA Tile - - hw/tile/converters/cv32e40p_data2obi.sv - - hw/tile/converters/cv32e40x_data2obi.sv - - hw/tile/converters/cv32e40p_obi2data.sv - - hw/tile/converters/cv32e40x_obi2data.sv - - hw/tile/converters/instr2obi.sv - - hw/tile/converters/obi2instr.sv - - hw/tile/converters/instr2cache.sv - - hw/tile/converters/cache2instr.sv - - hw/tile/converters/obi2hci.sv - - hw/tile/converters/hci2obi.sv - - hw/tile/converters/xif_if2struct.sv - - hw/tile/converters/obi2hwpe_ctrl.sv - - hw/tile/converters/tcdm2hci.sv - - hw/tile/converters/tcdm2obi.sv - - hw/tile/converters/tcdm2hci_atomic.sv - - hw/tile/converters/reqrsp2obi.sv - - hw/tile/converters/tcdm64_to_dual_hci32.sv - - hw/tile/converters/tcdm64_to_dual_tcdm32.sv - - hw/tile/converters/tcdm64_to_dual_hci32_atomic.sv - - hw/tile/converters/reqrsp64_to_obi32.sv - - hw/tile/xbar_periph_bus_if.sv - - hw/tile/cluster_event_map.sv - - hw/tile/magia_event_unit.sv - - hw/tile/obi_demux_addr.sv - - hw/tile/l1_spm.sv - - hw/tile/local_interconnect.sv - - hw/tile/idma_axi_obi_transfer_ch.sv - - hw/tile/idma_obi_ctrl_decoder.sv - - hw/tile/idma_ctrl_mm.sv - - hw/tile/obi_slave_fsync.sv - - hw/tile/obi_slave_ctrl_spatz.sv - - hw/tile/obi_slave_ctrl_cluster.sv - - hw/tile/tile_csr.sv - - hw/tile/spatz_bootrom.sv - - hw/tile/spatz_cc_wrapper.sv - - hw/tile/core_data_demux_eu_direct.sv - - hw/tile/eu_direct_cut.sv - - hw/tile/magia_tile_icache_wrap.sv - - hw/tile/magia_redmule_wrap.sv - - hw/tile/collective_gen.sv - - hw/tile/obi_slave_ctrl_coll.sv - hw/tile/magia_tile.sv - target: all(magia_dv, not(standalone_tile), verilator) @@ -203,51 +168,8 @@ sources: - hw/mesh/noc/floo_axi_nw_mesh_16x16_noc.sv - hw/mesh/noc/floo_axi_nw_mesh_32x32_noc.sv # MAGIA Packages - - hw/mesh/magia_pkg.sv - - hw/tile/magia_tile_pkg.sv - hw/mesh/noc/magia_noc_pkg.sv # MAGIA Tile - - hw/tile/converters/cv32e40p_data2obi.sv - - hw/tile/converters/cv32e40x_data2obi.sv - - hw/tile/converters/cv32e40p_obi2data.sv - - hw/tile/converters/cv32e40x_obi2data.sv - - hw/tile/converters/instr2obi.sv - - hw/tile/converters/obi2instr.sv - - hw/tile/converters/instr2cache.sv - - hw/tile/converters/cache2instr.sv - - hw/tile/converters/obi2hci.sv - - hw/tile/converters/hci2obi.sv - - hw/tile/converters/xif_if2struct.sv - - hw/tile/converters/obi2hwpe_ctrl.sv - - hw/tile/converters/tcdm2hci.sv - - hw/tile/converters/tcdm2obi.sv - - hw/tile/converters/tcdm2hci_atomic.sv - - hw/tile/converters/reqrsp2obi.sv - - hw/tile/converters/tcdm64_to_dual_hci32.sv - - hw/tile/converters/tcdm64_to_dual_tcdm32.sv - - hw/tile/converters/tcdm64_to_dual_hci32_atomic.sv - - hw/tile/converters/reqrsp64_to_obi32.sv - - hw/tile/xbar_periph_bus_if.sv - - hw/tile/cluster_event_map.sv - - hw/tile/magia_event_unit.sv - - hw/tile/obi_demux_addr.sv - - hw/tile/l1_spm.sv - - hw/tile/local_interconnect.sv - - hw/tile/idma_axi_obi_transfer_ch.sv - - hw/tile/idma_obi_ctrl_decoder.sv - - hw/tile/idma_ctrl_mm.sv - - hw/tile/obi_slave_fsync.sv - - hw/tile/obi_slave_ctrl_spatz.sv - - hw/tile/obi_slave_ctrl_cluster.sv - - hw/tile/tile_csr.sv - - hw/tile/spatz_bootrom.sv - - hw/tile/spatz_cc_wrapper.sv - - hw/tile/core_data_demux_eu_direct.sv - - hw/tile/eu_direct_cut.sv - - hw/tile/magia_tile_icache_wrap.sv - - hw/tile/magia_redmule_wrap.sv - - hw/tile/collective_gen.sv - - hw/tile/obi_slave_ctrl_coll.sv - hw/tile/magia_tile.sv # MAGIA - hw/mesh/magia.sv diff --git a/Makefile b/Makefile index 5a5ba8a8..a90e5726 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ # Copyright (C) 2023-2024 ETH Zurich and University of Bologna # -# Licensed under the Solderpad Hardware License, Version 0.51 -# (the "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -# SPDX-License-Identifier: SHL-0.51 +# SPDX-License-Identifier: Apache-2.0 # # Authors: Yvan Tortorella # Victor Isachi @@ -43,6 +43,8 @@ XLEN ?= 32 zfinx := 1 cluster_zfinx := 1 +# FractalSync network in the mesh and in every tile +fsync ?= 1 PULP_XTEN_BASE := xcvalu_xcvbi_xcvbitmanip_xcvhwlp_xcvmac_xcvmem_xcvsimd_xcvelw @@ -96,8 +98,9 @@ compile_flag ?= -suppress 2583 -suppress 13314 -suppress 3009 questa_compile_flag += -t 1ns -suppress 3009 questa_opt_flag += -suppress 3009 -debugdb +acc questa_opt_fast_flag += -suppress 3009 -O5 -permissive -questa_run_flag += -t 1ns -debugDB -suppress 3009 -questa_run_fast_flag += -t 1ns -suppress 3009 -permissive +# TODO: drop -suppress 8386 once FlooNoC casts logic to collect_op_e in floo_nw_chimney +questa_run_flag += -t 1ns -debugDB -suppress 3009 -suppress 8386 +questa_run_fast_flag += -t 1ns -suppress 3009 -suppress 8386 -permissive INI_PATH = sim/modelsim.ini WORK_PATH = $(BUILD_DIR) @@ -191,6 +194,8 @@ _AUTO_TASKS := $(shell grep -oP '\b(?!SPATZ_)[A-Z][A-Z0-9_]*_TASK\b' $(_SPATZ_SR SPATZ_TASKS := $(filter-out $(PULP_TASKS),$(_AUTO_TASKS)) # Setup build object dirs +# Spatz/PULP artifacts and generated headers are named after the bare test name +TEST_NAME = $(notdir $(test)) TEST_BUILD_DIR = $(TEST_DIR)/$(if $(TEST_SUBDIR),$(TEST_SUBDIR)/)$(test) CRT=$(TEST_BUILD_DIR)/build/crt0.o OBJ=$(TEST_BUILD_DIR)/build/verif.o @@ -198,8 +203,8 @@ BIN=$(TEST_BUILD_DIR)/build/verif DUMP=$(TEST_BUILD_DIR)/build/verif.dump ODUMP=$(TEST_BUILD_DIR)/build/verif.objdump # PULP cluster disassembly with global (runtime) addresses (only when PULP_TASKS set) -PULP_ELF=$(PULP_SW_DIR)/bin/$(test)_pulp_task_bin.elf -PULP_DUMP_GLOBAL=$(TEST_BUILD_DIR)/build/$(test)_pulp_task_global.dump +PULP_ELF=$(PULP_SW_DIR)/bin/$(TEST_NAME)_pulp_task_bin.elf +PULP_DUMP_GLOBAL=$(TEST_BUILD_DIR)/build/$(TEST_NAME)_pulp_task_global.dump ITB=$(TEST_BUILD_DIR)/build/verif.itb STIM_INSTR=$(TEST_BUILD_DIR)/build/stim_instr.txt STIM_DATA=$(TEST_BUILD_DIR)/build/stim_data.txt @@ -221,7 +226,7 @@ $(STIM_INSTR) $(STIM_DATA): $(BIN) spatz-header: @if [ -n "$(SPATZ_TASKS)" ]; then \ echo "[SPATZ] Auto-detected tasks: $(SPATZ_TASKS)"; \ - $(MAKE) -C $(SPATZ_SW_DIR) task="$(SPATZ_TASKS)" TEST_NAME=$(test) SPATZ_RVD=$(SPATZ_RVD) SPATZ_VLEN=$(SPATZ_VLEN) SPATZ_N_IPU=$(SPATZ_N_IPU) SPATZ_N_FPU=$(SPATZ_N_FPU) SPATZ_XDIVSQRT=$(SPATZ_XDIVSQRT) SPATZ_XDMA=$(SPATZ_XDMA) SPATZ_RVF=$(SPATZ_RVF) SPATZ_RVV=$(SPATZ_RVV) all; \ + $(MAKE) -C $(SPATZ_SW_DIR) task="$(SPATZ_TASKS)" TEST_NAME=$(TEST_NAME) SPATZ_RVD=$(SPATZ_RVD) SPATZ_VLEN=$(SPATZ_VLEN) SPATZ_N_IPU=$(SPATZ_N_IPU) SPATZ_N_FPU=$(SPATZ_N_FPU) SPATZ_XDIVSQRT=$(SPATZ_XDIVSQRT) SPATZ_XDMA=$(SPATZ_XDMA) SPATZ_RVF=$(SPATZ_RVF) SPATZ_RVV=$(SPATZ_RVV) all; \ else \ echo "[SPATZ] No Spatz tasks detected - skipping Spatz compilation"; \ fi @@ -234,7 +239,7 @@ spatz-header: pulp-header: @if [ -n "$(PULP_TASKS)" ]; then \ echo "[PULP] Auto-detected tasks: $(PULP_TASKS)"; \ - $(MAKE) -C $(PULP_SW_DIR) TEST_NAME=$(test) task="$(PULP_TASKS)" PULP_TASK_DIR=$(ROOT_DIR)/$(PULP_TASK_DIR_PATH) core=CV32E40P zfinx=$(cluster_zfinx) all; \ + $(MAKE) -C $(PULP_SW_DIR) TEST_NAME=$(TEST_NAME) task="$(PULP_TASKS)" PULP_TASK_DIR=$(ROOT_DIR)/$(PULP_TASK_DIR_PATH) core=CV32E40P zfinx=$(cluster_zfinx) all; \ else \ echo "[PULP] No pulp_task/ directory — skipping PULP cluster compilation"; \ fi @@ -296,12 +301,29 @@ else all: $(STIM_INSTR) $(STIM_DATA) dis objdump itb endif -# Run the simulation -run: $(CRT) +# Core-trace setup and sorting, shared by run and verilate-run ifneq ($(PULP_TASKS),) - @rm -rf $(TEST_BUILD_DIR)/traces $(TEST_BUILD_DIR)/trace_core_*.log - @bash $(ROOT_DIR)/scripts/setup_traces.sh $(TEST_BUILD_DIR) $(num_clusters) +define sim-traces-setup +@rm -rf $(TEST_BUILD_DIR)/traces $(TEST_BUILD_DIR)/trace_core_*.log +@bash $(ROOT_DIR)/scripts/setup_traces.sh $(TEST_BUILD_DIR) $(num_clusters) +endef +define sim-traces-sort +@bash $(ROOT_DIR)/scripts/sort_traces.sh $(TEST_BUILD_DIR) $(num_clusters) +endef +else +sim-traces-setup := +define sim-traces-sort +@for f in $(TEST_BUILD_DIR)/trace_core_*.log; do \ + [ -f "$$f" ] || continue; \ + hartid=$$(printf '%d' "0x$$(basename $$f .log | sed 's/trace_core_//')"); \ + [ $$hartid -ge $$(( 2 * $(num_clusters) )) ] && rm -f "$$f" || true; \ +done +endef endif + +# Run the simulation +run: $(CRT) + $(sim-traces-setup) ifeq ($(gui), 0) cd $(TEST_BUILD_DIR); \ $(QUESTA) vsim -c vopt_tb $(questa_run_fast_flag) -l transcript \ @@ -329,15 +351,7 @@ else ) \ +itb_file=$(itb_file) endif -ifneq ($(PULP_TASKS),) - @bash $(ROOT_DIR)/scripts/sort_traces.sh $(TEST_BUILD_DIR) $(num_clusters) -else - @for f in $(TEST_BUILD_DIR)/trace_core_*.log; do \ - [ -f "$$f" ] || continue; \ - hartid=$$(printf '%d' "0x$$(basename $$f .log | sed 's/trace_core_//')"); \ - [ $$hartid -ge $$(( 2 * $(num_clusters) )) ] && rm -f "$$f" || true; \ - done -endif + $(sim-traces-sort) # Download bender bender: @@ -370,6 +384,11 @@ ifeq ($(zfinx),1) endif bender_defs += -D ZFINX_CLUSTER=$(cluster_zfinx) +ifeq ($(fsync),1) + bender_defs += -D MAGIA_FSYNC + common_defs += -D MAGIA_FSYNC +endif + bender_targs += -t rtl bender_targs += -t test bender_targs += -t cv32e40p_include_tracer @@ -426,7 +445,7 @@ update-ips: --vlog-arg="$(compile_flag)" \ --vcom-arg="-pedanticerrors" \ $(bender_targs) $(bender_defs) \ - $(sim_targs) $(sim_deps) \ + $(sim_targs) $(sim_defs) \ > ${compile_script} vsim-scripts: @@ -436,7 +455,7 @@ vsim-scripts: --vlog-arg="$(compile_flag)" \ --vcom-arg="-pedanticerrors" \ $(bender_targs) $(bender_defs) \ - $(sim_targs) $(sim_deps) \ + $(sim_targs) $(sim_defs) \ > ${compile_script} synth-ips: @@ -465,16 +484,16 @@ sdk: clean-sdk: rm -rf $(SW)/pulp-sdk +# Only this test: other tests can build in parallel clean: rm -rf $(TEST_BUILD_DIR)/build - @if [ -d "$(SPATZ_SW_DIR)" ]; then \ - echo "[CLEAN] Cleaning Spatz..."; \ - $(MAKE) -C $(SPATZ_SW_DIR) clean; \ - fi - @if [ -d "$(PULP_SW_DIR)" ]; then \ - echo "[CLEAN] Cleaning PULP cluster..."; \ - $(MAKE) -C $(PULP_SW_DIR) clean; \ - fi + $(MAKE) -C $(SPATZ_SW_DIR) clean-test TEST_NAME=$(TEST_NAME) + $(MAKE) -C $(PULP_SW_DIR) clean-test TEST_NAME=$(TEST_NAME) + +# Spatz and PULP artifacts of every test +clean-sw-all: + $(MAKE) -C $(SPATZ_SW_DIR) clean + $(MAKE) -C $(PULP_SW_DIR) clean dis: $(OBJDUMP) -d -S $(BIN) > $(DUMP) @@ -558,7 +577,7 @@ hw-all: hw-clean hw-lib hw-compile hw-opt # Nonfree components MAGIA_NONFREE_REMOTE ?= $(GITLAB_UNIBO_SSH_STRING)/magia/nonfree.git MAGIA_NONFREE_DIR ?= nonfree -MAGIA_NONFREE_COMMIT ?= b092ba31b925b64120891195dac3c49f0a14db5d +MAGIA_NONFREE_COMMIT ?= 5d887bcdf505c0949fa05dcd1b8e6ce3199b912c MAGIA_NONFREE_DEPS ?= 1 .PHONY: magia-nonfree-init diff --git a/README.md b/README.md index eab7bdcc..01ff0f9e 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,9 @@ The following *optional* parameters can be specified: `gui`: **0**|**1** (**Default**: 0). 0 simulation without GUI; 1 simulation with GUI. -`core`: **CV32E40P**|**CV32E40X** (**Default**: CV32E40P). Control and cluster cores type. +`core`: **CV32E40P**|**CV32E40X** (**Default**: CV32E40P). Control core type; the cluster cores are always CV32E40P. + +`fsync`: **0**|**1** (**Default**: 1). 1 builds the FractalSync network (`MAGIA_FSYNC`). **Instructions to build HW/SW and run simulations**: @@ -53,10 +55,6 @@ Remember to export the bender binary to your `PATH` variable. ```bash make vsim-scripts > vsim-scripts.log ``` -**4\*)** Apply FlooNoC *patch* - **currently FlooNoC requires this step but should not need it in the future** (`MAGIA` folder): -```bash -make floonoc-patch -``` **5)** *Build* the hardware (`MAGIA` folder): ```bash make build-hw > build-hw.log @@ -86,19 +84,20 @@ make run test=fsync_test MAGIA can also be simulated with [Verilator](https://verilator.org) instead of QuestaSim. The flow is independent of the `vsim` one above: it has its own -targets, its own build directory (`verilator/build`), and needs no +targets, its own build directories under `verilator/`, and needs no `build-hw`/`vsim-scripts` step. -Verilator builds the mesh **hierarchically**: the tile is compiled once into a -separate library (`magia_tile_hier`) and instantiated 16 times, instead of -being flattened 16 times over. This is what keeps the build tractable, and it -is why the flow requires `mesh_dv=1` — there is no single-tile Verilator -target at this time. +`mesh_dv` picks the model, as in the Questa flow: + +- `mesh_dv=1` builds the mesh (`magia_tb`) **hierarchically**: the tile is + compiled once into a separate library (`magia_tile_hier`) and instantiated + for every tile, instead of being flattened. This keeps the build tractable. +- `mesh_dv=0` builds the standalone tile (`magia_tile_tb`). The following *optional* parameters can be specified: -`core`: **CV32E40P** (**Default**: CV32E40P). CV32E40X is not supported by this -flow. +`core`: **CV32E40P**|**CV32E40X** (**Default**: CV32E40P). Each core and each +`mesh_dv` has its own build directory, so the models can be built side by side. `VERILATOR_JOBS`: **N** (**Default**: 4). Parallelism used to *build* the model. Unrelated to simulation speed. @@ -119,8 +118,8 @@ make verilate core=CV32E40P mesh_dv=1 VERILATOR_JOBS=16 make verilate-run core=CV32E40P mesh_dv=1 test=inter_l1_test ``` Step **1** is *required at least once*: `verilate-run` compiles the test but -never the model — it runs the `Vmagia_tb` that is already in -`verilator/build/obj_dir`, and errors out if there is none. +never the model — it runs the model already built for that `mesh_dv` and +`core`, and errors out if there is none. **After changing the RTL, re-run `make verilate` yourself**, or you will keep simulating the old model. **Full example**: @@ -134,6 +133,16 @@ Other targets: `verilate-gen` (code generation only), `verilate-build` (native compile only), `verilate-check-hierarchy` (asserts the model really links the tile library instead of inlining it), and `clean-verilate`. +#### Single tile + +`mesh_dv=0` builds the standalone tile (`magia_tile_tb`) in its own build +directory, and runs the same tile tests as the Questa flow (`make run mesh_dv=0`): + +```bash +make verilate core=CV32E40P mesh_dv=0 VERILATOR_JOBS=16 +make verilate-run core=CV32E40P mesh_dv=0 test=hello_world +``` + #### Waveforms (FST) The model is **always** built with tracing compiled in, so no rebuild is needed @@ -147,10 +156,8 @@ make verilate-run core=CV32E40P mesh_dv=1 test=inter_l1_test VERILATOR_FST=dump. The file is written in the test's build directory. Waveforms include the internals of every tile. -**Let the simulation reach `$finish`.** A run killed before it gets there -leaves the FST unclosed, and an unclosed FST is not a file you can keep: the hierarchy is still sitting in a `.fst.hier` -companion, so the dump reads only in place and loses every signal name the -moment it is moved. +`Ctrl-C` (or `SIGTERM`) stops the run at the next time step and still closes +the FST, so an interrupted run leaves a waveform you can open. #### Multithreaded simulation (experimental) @@ -177,15 +184,17 @@ To change the thread count, re-run `make verilate` with the new value. ![](doc/MAGIA.png) ### Tile -The central piece of the architecture is the MAGIA tile containing a GeMM accelerator, a Vector Processor, a DMA engine, a PULP cluster of 8 RISC-V cores, a multi-banked L1 SPM, an Event Unit, and a lightweight control core. The L1 features interleaved memory banks that compose the Tightly-Coupled Data Memory (TCDM). Each tile has access to the global L2 and to a subset of other tiles' L1, accessing the latter via on-chip remote direct memory access (RDMA). Inter-tile and global communication is carried out through AXI-based narrow (32-bit) and wide (256-bit) NoC channels in [FlooNoC](https://github.com/pulp-platform/FlooNoC). External tiles and the core access the L1 through an OpenBus Interface ([OBI](https://github.com/pulp-platform/obi)) XBAR. +The central piece of the architecture is the MAGIA tile containing a GeMM accelerator, a Vector Processor, a DMA engine, a PULP cluster of RISC-V cores, a multi-banked L1 SPM, an Event Unit, and a lightweight control core. The L1 features interleaved memory banks that compose the Tightly-Coupled Data Memory (TCDM). Each tile has access to the global L2 and to a subset of other tiles' L1, accessing the latter via on-chip remote direct memory access (RDMA). Inter-tile and global communication is carried out through AXI-based narrow (32-bit) and wide (256-bit) NoC channels in [FlooNoC](https://github.com/pulp-platform/FlooNoC). External tiles and the core access the L1 through an OpenBus Interface ([OBI](https://github.com/pulp-platform/obi)) XBAR. -Each tile is controlled by a [CV32E40P](https://github.com/pulp-platform/cv32e40p) main core. Control of iDMA, RedMulE, FractalSync, Spatz CC, and the PULP cluster follows a memory-mapped model, with the Event Unit handling event aggregation for system control. +Each tile is controlled by a [CV32E40P](https://github.com/pulp-platform/cv32e40p) or [CV32E40X](https://github.com/openhwgroup/cv32e40x) main core (`core=`). Control of iDMA, RedMulE, FractalSync, Spatz CC, and the PULP cluster follows a memory-mapped model, with the Event Unit handling event aggregation for system control. + +`magia_tile` wraps `magia_isle` (cores, accelerators, L1, crossbars and Event Unit) with the FlooNoC network interface and router. What a tile contains is set by its `TileCfg` (`magia_tile_cfg_t` in `hw/mesh/magia_pkg.sv`). #### PULP Cluster -Each tile embeds a cluster of 8 [CV32E40P](https://github.com/pulp-platform/cv32e40p) cores. Cluster cores share a Snitch instruction cache with an AXI refill path to L2, and each core has its own OBI master port into the tile crossbar for data accesses (L1, accelerator registers, PULP_CTRL). Cluster cores receive interrupts exclusively from the tile CSR (`PULP_CTRL`) — they are not connected to the Event Unit. The main core dispatches tasks to the cluster via the `PULP_CTRL` register block (`0x1740`), which provides: binary entry point (`PULP_BINARY`), per-core MEI dispatch (`PULP_START`), task function pointer (`PULP_TASKBIN`), data pointer (`PULP_DATA`), completion quorum (`PULP_NB_CORES_TO_WAIT`), and readiness/done handshake registers (`PULP_READY`, `PULP_DONE`). When the done quorum is reached, the tile CSR raises EU bit 12 on the main core's Event Unit, allowing the main core to sleep in WFE until the cluster finishes. +Each tile embeds a cluster of `TileCfg.Cluster.NumCores` (8 by default) [CV32E40P](https://github.com/pulp-platform/cv32e40p) cores. Cluster cores share a Snitch instruction cache with an AXI refill path to L2, each core reaches the tile's L1 through its own HCI port and everything else (accelerator registers, PULP_CTRL, remote memory) through its own OBI master port into the tile crossbar. Cluster cores receive interrupts exclusively from the tile CSR (`PULP_CTRL`) — they are not connected to the Event Unit. The main core dispatches tasks to the cluster via the `PULP_CTRL` register block (`0x1740`), which provides: binary entry point (`PULP_BINARY`), per-core MEI dispatch (`PULP_START`), task function pointer (`PULP_TASKBIN`), data pointer (`PULP_DATA`), completion quorum (`PULP_NB_CORES_TO_WAIT`), and readiness/done handshake registers (`PULP_READY`, `PULP_DONE`). When the done quorum is reached, the tile CSR raises EU bit 12 on the main core's Event Unit, allowing the main core to sleep in WFE until the cluster finishes. ### Mesh -Replicating the MAGIA tile, we scale up to a homogeneous two-dimensional (2D) mesh of compute tiles. The NoC allows access to the global west-side L2 through row-side interfaces, while tiles exchange traffic through FlooNoC router. The mesh uses XY routing and carries both AXI narrow channels (32-bit) and AXI wide channels (256-bit), with protocol conversion handled by per-tile Network Interfaces (NIs). +Replicating the MAGIA tile, we scale up to a two-dimensional (2D) mesh of compute tiles. Each tile takes its `TileCfg` from the `TILE_CFGS` parameter of `magia` (`HOMO_TILE_CFGS` by default). The NoC allows access to the global west-side L2 through row-side interfaces, while tiles exchange traffic through FlooNoC router. The mesh uses XY routing and carries both AXI narrow channels (32-bit) and AXI wide channels (256-bit), with protocol conversion handled by per-tile Network Interfaces (NIs). Rendez-vous among tiles are managed through the FractalSync (FS) mechanism and the dedicated network. @@ -255,44 +264,46 @@ This map reflects the RTL memory-mapped layout defined in `hw/tile/magia_tile_pk - `tile_base = mhartid * 0x0010_0000` -Per-tile local map (offset from `tile_base`, starts at `0x0000_0000`): - -| Region | Local Range | Global Range (`tile_base + offset`) | -|-------------------|-------------------------|--------------------------------------| -| *RedMulE CTRL* | `0x0000_0100-0x0000_01FF` | `tile_base + 0x0000_0100 ... 0x0000_01FF` | -| *iDMA CTRL* | `0x0000_0200-0x0000_05FF` | `tile_base + 0x0000_0200 ... 0x0000_05FF` | -| *FractalSync CTRL*| `0x0000_0600-0x0000_06FF` | `tile_base + 0x0000_0600 ... 0x0000_06FF` | -| *Event Unit* | `0x0000_0700-0x0000_16FF` | `tile_base + 0x0000_0700 ... 0x0000_16FF` | -| *Spatz CTRL* | `0x0000_1700-0x0000_173F` | `tile_base + 0x0000_1700 ... 0x0000_173F` | -| *PULP CTRL* | `0x0000_1740-0x0000_17FF` | `tile_base + 0x0000_1740 ... 0x0000_17FF` | -| *Collective CTRL* | `0x0000_1800-0x0000_18FF` | `tile_base + 0x0000_1800 ... 0x0000_18FF` | -| *Reserved* | `0x0000_0000-0x0000_FFFF` | `tile_base + 0x0000_0000 ... 0x0000_FFFF` | -| *Stack* | `0x0001_0000-0x0001_FFFF` | `tile_base + 0x0001_0000 ... 0x0001_FFFF` | -| *L1 SPM* | `0x0002_0000-0x000F_FFFF` | `tile_base + 0x0002_0000 ... 0x000F_FFFF` | +Private map: the same range in every tile, each tile maps it to its own copy: + +| Region | Range | +|-------------------|---------------------------| +| *RedMulE CTRL* | `0x0000_0100-0x0000_01FF` | +| *iDMA CTRL* | `0x0000_0200-0x0000_05FF` | +| *FractalSync CTRL*| `0x0000_0600-0x0000_06FF` | +| *Event Unit* | `0x0000_0700-0x0000_16FF` | +| *Spatz CTRL* | `0x0000_1700-0x0000_173F` | +| *PULP CTRL* | `0x0000_1740-0x0000_17FF` | +| *Collective CTRL* | `0x0000_1800-0x0000_18FF` | +| *Reserved* | `0x0000_1900-0x0000_FFFF` | +| *Stack* | `0x0001_0000-0x0001_FFFF` | +| *Spatz BootROM* | `0x1000_0000-0x1000_00FF` | Shared/global map: -| Region | Range | Notes | -|-------------------|-------------------------|-------| -| *Spatz BootROM* | `0x1000_0000-0x1000_00FF` | Tile AXI xbar bootrom target | +| Region | Range | Notes | +|-------------------|---------------------------|-------| +| *L1 SPM* | `tile_base + 0x0002_0000 ... 0x000F_FFFF` | Reachable by every tile | | *L2* | `0xC000_0000-0xFFFF_FFFF` | Global L2 window | | *Instructions* | `0xCC00_0000-0xCC00_7FFF` | Instruction sub-region inside L2 | +An access to an unmapped address of the peripheral window gets an OBI error, and in simulation it stops the test. + Software/test utility addresses (used by SW runtime and testbench VIP): | Region | Address | Notes | |-------------------|--------------------------------------------|-------| | *Test End* | `0xCCFF_0000` | Exit code location used by SW runtime/tests | -| *String (utoa)* | `tile_base + 0x0000_1800` | String scratch location (`RESERVED_START + STR_OFFSET`) | +| *String (utoa)* | `0x0000_1900` | String scratch location (`RESERVED_START + STR_OFFSET`) | | *Print (stderr)* | `0xFFFF_0000` | Memory-mapped stderr sink in simulation VIP | | *Print (stdio)* | `0xFFFF_0004` | Memory-mapped stdio sink in simulation VIP | -| *Synch.* | `tile_base + 0x0000_F000` | Derived from `RESERVED_START + SYNC_OFFSET` | +| *Synch.* | `tile_base + 0x000F_F000` | Top 4 KiB of L1 (`L1_BASE + SYNC_OFFSET`) | ## 🖥️ Programming model The flow is memory-mapped (MM): software configures and starts accelerators by writing control registers in each tile address space. - Execution model: SPMD over tiles, with `mhartid` selecting `tile_base = mhartid * 0x0010_0000`. -- Control path: CV32E40P accesses RedMulE, iDMA, FractalSync, Event Unit, and Spatz control registers via MMIO. +- Control path: the control core (CV32E40P or CV32E40X) accesses RedMulE, iDMA, FractalSync, Event Unit, and Spatz control registers via MMIO. - Data path: iDMA moves data between L1 and external memory, while compute engines consume/produce data in L1. - Synchronization: Event Unit and FractalSync provide interrupt/event and barrier mechanisms for inter-tile coordination. @@ -336,10 +347,10 @@ The PULP cluster uses a bare-metal dynamic dispatch model. The cluster binary is **Dispatch flow** (`sw/utils/cluster_utils.h`, `sw/utils/magia_pulp_utils.h`): -1. `cluster_boot(binary_start)` — writes `PULP_BINARY`, asserts `CLK_EN`, polls `PULP_READY` until all 8 cores have armed their dispatcher loop. +1. `cluster_boot(binary_start)` — writes `PULP_BINARY`, asserts `CLK_EN`, polls `PULP_READY` until all cluster cores have armed their dispatcher loop. 2. `cluster_arm_done_event()` — clears the CV32 Event Unit buffer and enables only EU bit 12 (cluster-done), avoiding spurious wakeups from stale RedMulE/iDMA events. 3. `cluster_dispatch_task(task_addr, core_mask)` — writes `NB_CORES_TO_WAIT`, `TASKBIN`, then `PULP_START = core_mask`, which fires a per-core MEI to each selected core. Returns once all selected cores have ACK'd (i.e., `PULP_START` self-clears). -4. `cluster_wait_done_eu()` — CV32 sleeps in `cv.elw` until EU bit 12 fires (PULP_DONE quorum reached). +4. `cluster_wait_done_eu()` — the control core sleeps on a blocking Event Unit load (`cv.elw` on CV32E40P, `lw` on CV32E40X) until EU bit 12 fires (PULP_DONE quorum reached). 5. `cluster_stop()` — de-asserts `CLK_EN` to gate the cluster clock. Each cluster core runs a dispatcher loop that waits in `WFI` for the MEI, reads `PULP_TASKBIN`/`PULP_DATA` from the trap handler, calls the task function, writes `PULP_DONE`, and re-enters `WFI`. @@ -354,15 +365,15 @@ Cluster task sources live under `sw/tests//pulp_task/`. A test directory c **RTL/TB** : The `N_TILES_X` and `N_TILES_Y` parameters in `hw/mesh/magia_pkg.sv` specifie the number of tiles and allows the derivation of the appropriate data and syncrhonization networks. -## 🧪Local testing (semi-automatic) -To facilitate the functional verification, the [`bwruntests.py`](scripts/bwruntests.py) Python script can be used to locally run the same tests executed by the CI in an automated fashion. The two available sets of tests are defined in [`tile_tests.yml`](sw/tests/tile_tests.yml) and [`mesh_tests`](sw/tests/mesh_tests.yml). - -The Python script is supposed to be invoked from the main directory of this repository as follows: +## 🧪Local testing +The [`run_regression.py`](scripts/run_regression.py) Python script builds the hardware and software and runs the tests listed in [`tests.yml`](sw/tests/tests.yml), for Questa and Verilator. It is invoked from the main directory of this repository: ```sh -python3 scripts/bwruntests.py -y [test_file.yml] +scripts/run_regression.py --sim questa --core CV32E40P --fsync on --test general/hello_mesh # one test +scripts/run_regression.py --sim all --core all --fsync all --test all # everything +scripts/run_regression.py --sim all --core all --fsync all --test all --list # plan only ``` -Differently from the CI flow, **the RTL must be MANUALLY compiled** with the correct `mesh_dv` flag depending on the target to be tested, i.e. single tile or full mesh. For a faster execution `fast_sim=1` is suggested. +`scripts/run_regression.py -h` lists every option. ## 🔏 License MAGIA is an open-source project with a permissive license. All `software` sources are licensed under the Apache License 2.0 ([`LICENSE.APACHE`](LICENSE.APACHE)). All `hardware` sources are licensed under the Solderpad Hardware License 0.51 ([`LICENSE.SHL`](LICENSE.SHL)). diff --git a/bender_profile.mk b/bender_profile.mk index 693593b1..7d5e342e 100644 --- a/bender_profile.mk +++ b/bender_profile.mk @@ -26,6 +26,9 @@ profile_targs += -t magia_tile_test profile_targs += -t magia_dv +# Core traces in DV builds +profile_defs += -D CORE_TRACES + profile_defs += -D PROFILE_SENTINEL # profile_defs += -D PROFILE_SYNC # profile_defs += -D PROFILE_DETAILED \ No newline at end of file diff --git a/bender_sim.mk b/bender_sim.mk index 0d2ab4fd..658a548d 100644 --- a/bender_sim.mk +++ b/bender_sim.mk @@ -24,4 +24,7 @@ endif sim_targs += -t magia_tile_test -sim_targs += -t magia_dv \ No newline at end of file +sim_targs += -t magia_dv + +# Core traces in DV builds +sim_defs += -D CORE_TRACES \ No newline at end of file diff --git a/hw/include/alias.svh b/hw/include/alias.svh index 217bd801..d6a7d514 100644 --- a/hw/include/alias.svh +++ b/hw/include/alias.svh @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. diff --git a/hw/mesh/magia.sv b/hw/mesh/magia.sv index 6e54db47..37a6e21b 100644 --- a/hw/mesh/magia.sv +++ b/hw/mesh/magia.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -19,10 +19,6 @@ * MAGIA */ -`ifndef VERILATOR -`include "fractal_sync/assign.svh" -`endif - module magia import magia_pkg::*; import magia_tile_pkg::*; @@ -31,12 +27,8 @@ module magia parameter int unsigned N_TILES_Y = magia_pkg::N_TILES_Y, // Number of Tile rowns parameter int unsigned N_TILES_X = magia_pkg::N_TILES_X, // Number of Tile columns parameter int unsigned N_TILES = magia_pkg::N_TILES, // Number of Tiles in the Mesh - parameter int unsigned N_MEM_BANKS = magia_pkg::N_MEM_BANKS, // Number of TCDM banks (1 extra bank for missaligned accesses) per Tile - parameter int unsigned N_WORDS_BANK = magia_pkg::N_WORDS_BANK, // Number of words per TCDM bank - - parameter int unsigned TILE_FSYNC_AGGR_W = magia_pkg::TILE_FSYNC_AGGR_W, // Width of the FractalSync aggr of the Tile - FS network link - parameter int unsigned TILE_FSYNC_LVL_W = magia_pkg::TILE_FSYNC_LVL_W, // Width of the FractalSync lvl of the Tile - FS network link - parameter int unsigned TILE_FSYNC_ID_W = magia_pkg::TILE_FSYNC_ID_W // Width of the FractalSync id of the Tile - FS network link + // By Default is used the Homogeneous Mesh + parameter magia_pkg::magia_tile_cfg_t [N_TILES-1:0] TILE_CFGS = magia_pkg::HOMO_TILE_CFGS )( input logic clk_i, input logic rst_ni, @@ -81,6 +73,17 @@ module magia `endif ); +/*******************************************************/ +/** Configuration Checks Beginning **/ +/*******************************************************/ +`ifndef SYNTHESIS + if (N_TILES_X != N_TILES_Y) begin : gen_square_mesh_check + $fatal(1, "magia: only square meshes are supported, got %0dx%0d tiles", N_TILES_X, N_TILES_Y); + end +`endif + +/*******************************************************/ +/** Configuration Checks End **/ /*******************************************************/ /** Internal Signal Definitions Beginning **/ /*******************************************************/ @@ -101,52 +104,26 @@ module magia floo_rsp_t [N_TILES-1:0] tile_west_rsp_in, tile_west_rsp_out; floo_wide_t [N_TILES-1:0] tile_west_wide_in, tile_west_wide_out; - magia_tile_pkg::ht_tile_fsync_req_t ht_tile_fsync_req[N_TILES][1]; // Single link CU-FSync interface - magia_tile_pkg::ht_tile_fsync_rsp_t ht_tile_fsync_rsp[N_TILES][1]; // Single link CU-FSync interface +`ifdef MAGIA_FSYNC + // Tile side of the 1D FractalSync links: tile ports bind to these + magia_tile_pkg::ht_tile_fsync_req_t [N_TILES-1:0] ht_fsync_req; + magia_tile_pkg::ht_tile_fsync_rsp_t [N_TILES-1:0] ht_fsync_rsp; + magia_tile_pkg::vt_tile_fsync_req_t [N_TILES-1:0] vt_fsync_req; + magia_tile_pkg::vt_tile_fsync_rsp_t [N_TILES-1:0] vt_fsync_rsp; + + // Tile links of the FractalSync tree (single link per tile) + magia_tile_pkg::ht_tile_fsync_req_t ht_tile_fsync_req[N_TILES][1]; + magia_tile_pkg::ht_tile_fsync_rsp_t ht_tile_fsync_rsp[N_TILES][1]; magia_tile_pkg::hn_tile_fsync_req_t hn_tile_fsync_req[N_TILES]; magia_tile_pkg::hn_tile_fsync_rsp_t hn_tile_fsync_rsp[N_TILES]; - magia_tile_pkg::vt_tile_fsync_req_t vt_tile_fsync_req[N_TILES][1]; // Single link CU-FSync interface - magia_tile_pkg::vt_tile_fsync_rsp_t vt_tile_fsync_rsp[N_TILES][1]; // Single link CU-FSync interface + magia_tile_pkg::vt_tile_fsync_req_t vt_tile_fsync_req[N_TILES][1]; + magia_tile_pkg::vt_tile_fsync_rsp_t vt_tile_fsync_rsp[N_TILES][1]; magia_tile_pkg::vn_tile_fsync_req_t vn_tile_fsync_req[N_TILES]; magia_tile_pkg::vn_tile_fsync_rsp_t vn_tile_fsync_rsp[N_TILES]; - - magia_pkg::h_root_fsync_req_t h_root_fsync_req[1][1]; // Single node, single link root node out interface - magia_pkg::h_root_fsync_rsp_t h_root_fsync_rsp[1][1]; // Single node, single link root node out interface - magia_pkg::v_root_fsync_req_t v_root_fsync_req[1][1]; // Single node, single link root node out interface - magia_pkg::v_root_fsync_rsp_t v_root_fsync_rsp[1][1]; // Single node, single link root node out interface +`endif /*******************************************************/ /** Internal Signal Definitions End **/ -`ifndef VERILATOR -/*******************************************************/ -/** Interface Definitions Beginning **/ -/*******************************************************/ - - fractal_sync_if #(.AGGR_WIDTH(TILE_FSYNC_AGGR_W), .LVL_WIDTH(TILE_FSYNC_LVL_W), .ID_WIDTH(TILE_FSYNC_ID_W)) ht_fsync_if[N_TILES](); - fractal_sync_if #(.AGGR_WIDTH(magia_tile_pkg::FSYNC_NBR_AGGR_W), .LVL_WIDTH(magia_tile_pkg::FSYNC_NBR_LVL_W), .ID_WIDTH(magia_tile_pkg::FSYNC_NBR_ID_W)) hn_fsync_if[N_TILES](); - fractal_sync_if #(.AGGR_WIDTH(TILE_FSYNC_AGGR_W), .LVL_WIDTH(TILE_FSYNC_LVL_W), .ID_WIDTH(TILE_FSYNC_ID_W)) vt_fsync_if[N_TILES](); - fractal_sync_if #(.AGGR_WIDTH(magia_tile_pkg::FSYNC_NBR_AGGR_W), .LVL_WIDTH(magia_tile_pkg::FSYNC_NBR_LVL_W), .ID_WIDTH(magia_tile_pkg::FSYNC_NBR_ID_W)) vn_fsync_if[N_TILES](); - -/*******************************************************/ -/** Interface Definitions End **/ -/*******************************************************/ -/** Interface Assignments Beginning **/ -/*******************************************************/ - - for (genvar i = 0; i < N_TILES; i++) begin: gen_fsync_if_assign - `FSYNC_ASSIGN_I2S_REQ(ht_fsync_if[i], ht_tile_fsync_req[i][0]) - `FSYNC_ASSIGN_S2I_RSP(ht_tile_fsync_rsp[i][0], ht_fsync_if[i]) - `FSYNC_ASSIGN_I2S_REQ(hn_fsync_if[i], hn_tile_fsync_req[i]) - `FSYNC_ASSIGN_S2I_RSP(hn_tile_fsync_rsp[i], hn_fsync_if[i]) - `FSYNC_ASSIGN_I2S_REQ(vt_fsync_if[i], vt_tile_fsync_req[i][0]) - `FSYNC_ASSIGN_S2I_RSP(vt_tile_fsync_rsp[i][0], vt_fsync_if[i]) - `FSYNC_ASSIGN_I2S_REQ(vn_fsync_if[i], vn_tile_fsync_req[i]) - `FSYNC_ASSIGN_S2I_RSP(vn_tile_fsync_rsp[i], vn_fsync_if[i]) - end - -/*******************************************************/ -/** Interface Assignments End **/ -`endif /*******************************************************/ /** Hardwired Signals Beginning **/ /*******************************************************/ @@ -155,14 +132,14 @@ module magia assign mhartid[i] = i; end - assign h_root_fsync_rsp[0][0].wake = 1'b0; - assign h_root_fsync_rsp[0][0].sig.lvl = '0; - assign h_root_fsync_rsp[0][0].sig.id = '0; - assign h_root_fsync_rsp[0][0].error = 1'b0; - assign v_root_fsync_rsp[0][0].wake = 1'b0; - assign v_root_fsync_rsp[0][0].sig.lvl = '0; - assign v_root_fsync_rsp[0][0].sig.id = '0; - assign v_root_fsync_rsp[0][0].error = 1'b0; +`ifdef MAGIA_FSYNC + for (genvar i = 0; i < N_TILES; i++) begin: gen_fsync_links + assign ht_tile_fsync_req[i][0] = ht_fsync_req[i]; + assign ht_fsync_rsp[i] = ht_tile_fsync_rsp[i][0]; + assign vt_tile_fsync_req[i][0] = vt_fsync_req[i]; + assign vt_fsync_rsp[i] = vt_tile_fsync_rsp[i][0]; + end +`endif /*******************************************************/ /** Hardwired Signals End **/ @@ -174,19 +151,11 @@ module magia for (genvar j = 0; j < N_TILES_X; j++) begin: gen_x_tile `ifdef VERILATOR magia_tile_hier #( - .N_MEM_BANKS ( N_MEM_BANKS ), - .N_WORDS_BANK ( N_WORDS_BANK ) + .TileCfg ( TILE_CFGS[i*N_TILES_X+j] ) ) i_magia_tile ( `else magia_tile #( - .N_MEM_BANKS ( N_MEM_BANKS ), - .N_WORDS_BANK ( N_WORDS_BANK ), - - .CORE_ISA ( ), - .CORE_A ( ), - .CORE_B ( ), - .CORE_M ( ), - .ERROR_CAP ( ) + .TileCfg ( TILE_CFGS[i*N_TILES_X+j] ) ) i_magia_tile ( `endif .clk_i , @@ -223,20 +192,15 @@ module magia .x_id_i ( {{(32-$clog2(N_TILES_X+1)){1'b0}}, CollectiveSam[i*N_TILES_X+j].idx.id.x} ), .y_id_i ( {{(32-$clog2(N_TILES_Y)){1'b0}}, CollectiveSam[i*N_TILES_X+j].idx.id.y} ), -`ifdef VERILATOR - .ht_fsync_req_o ( ht_tile_fsync_req[i*N_TILES_X+j][0] ), - .ht_fsync_rsp_i ( ht_tile_fsync_rsp[i*N_TILES_X+j][0] ), +`ifdef MAGIA_FSYNC + .ht_fsync_req_o ( ht_fsync_req[i*N_TILES_X+j] ), + .ht_fsync_rsp_i ( ht_fsync_rsp[i*N_TILES_X+j] ), .hn_fsync_req_o ( hn_tile_fsync_req[i*N_TILES_X+j] ), .hn_fsync_rsp_i ( hn_tile_fsync_rsp[i*N_TILES_X+j] ), - .vt_fsync_req_o ( vt_tile_fsync_req[i*N_TILES_X+j][0] ), - .vt_fsync_rsp_i ( vt_tile_fsync_rsp[i*N_TILES_X+j][0] ), + .vt_fsync_req_o ( vt_fsync_req[i*N_TILES_X+j] ), + .vt_fsync_rsp_i ( vt_fsync_rsp[i*N_TILES_X+j] ), .vn_fsync_req_o ( vn_tile_fsync_req[i*N_TILES_X+j] ), .vn_fsync_rsp_i ( vn_tile_fsync_rsp[i*N_TILES_X+j] ), -`else - .ht_fsync_if_o ( ht_fsync_if[i*N_TILES_X+j] ), - .hn_fsync_if_o ( hn_fsync_if[i*N_TILES_X+j] ), - .vt_fsync_if_o ( vt_fsync_if[i*N_TILES_X+j] ), - .vn_fsync_if_o ( vn_fsync_if[i*N_TILES_X+j] ), `endif .scan_cg_en_i , @@ -272,18 +236,9 @@ module magia , .observe_o ( tile_observe_o[i*N_TILES_X+j] ) `endif ); - `ifdef CORE_TRACES - `ifdef CV32E40X -`ifndef VERILATOR - localparam string core_trace_file_name = $sformatf("%s%0d", "log_file_", i*N_TILES_X+j); - defparam i_magia_tile.i_cv32e40x_ctrl_core.rvfi_i.tracer_i.LOGFILE_PATH_PLUSARG = core_trace_file_name; -`endif - `endif - // Note: cv32e40p tracer generates its own filename: trace_core_{cluster_id}_{core_id}.log - `endif - if (i == 0) begin - if (j == 0) begin // T-L corner + if (i == 0) begin : gen_first_row + if (j == 0) begin : gen_top_left assign tile_north_req_in[i*N_TILES_X+j] = '0; assign tile_north_rsp_in[i*N_TILES_X+j] = '0; assign tile_north_wide_in[i*N_TILES_X+j] = '0; @@ -299,7 +254,7 @@ module magia assign tile_east_req_in[i*N_TILES_X+j] = tile_west_req_out[i*N_TILES_X+j+1]; assign tile_east_rsp_in[i*N_TILES_X+j] = tile_west_rsp_out[i*N_TILES_X+j+1]; assign tile_east_wide_in[i*N_TILES_X+j] = tile_west_wide_out[i*N_TILES_X+j+1]; - end else if (j == N_TILES_X-1) begin // T-R corner + end else if (j == N_TILES_X-1) begin : gen_top_right assign tile_north_req_in[i*N_TILES_X+j] = '0; assign tile_north_rsp_in[i*N_TILES_X+j] = '0; assign tile_north_wide_in[i*N_TILES_X+j] = '0; @@ -312,7 +267,7 @@ module magia assign tile_east_req_in[i*N_TILES_X+j] = '0; assign tile_east_rsp_in[i*N_TILES_X+j] = '0; assign tile_east_wide_in[i*N_TILES_X+j] = '0; - end else if ((j > 0) && (j < (N_TILES_X-1))) begin // First row without corners + end else if ((j > 0) && (j < (N_TILES_X-1))) begin : gen_top_edge assign tile_north_req_in[i*N_TILES_X+j] = '0; assign tile_north_rsp_in[i*N_TILES_X+j] = '0; assign tile_north_wide_in[i*N_TILES_X+j] = '0; @@ -326,8 +281,8 @@ module magia assign tile_east_rsp_in[i*N_TILES_X+j] = tile_west_rsp_out[i*N_TILES_X+j+1]; assign tile_east_wide_in[i*N_TILES_X+j] = tile_west_wide_out[i*N_TILES_X+j+1]; end - end else if (i == N_TILES_Y-1) begin - if (j == 0) begin // B-L corner + end else if (i == N_TILES_Y-1) begin : gen_last_row + if (j == 0) begin : gen_bottom_left assign tile_north_req_in[i*N_TILES_X+j] = tile_south_req_out[(i-1)*N_TILES_X+j]; assign tile_north_rsp_in[i*N_TILES_X+j] = tile_south_rsp_out[(i-1)*N_TILES_X+j]; assign tile_north_wide_in[i*N_TILES_X+j] = tile_south_wide_out[(i-1)*N_TILES_X+j]; @@ -343,7 +298,7 @@ module magia assign tile_east_req_in[i*N_TILES_X+j] = tile_west_req_out[i*N_TILES_X+j+1]; assign tile_east_rsp_in[i*N_TILES_X+j] = tile_west_rsp_out[i*N_TILES_X+j+1]; assign tile_east_wide_in[i*N_TILES_X+j] = tile_west_wide_out[i*N_TILES_X+j+1]; - end else if (j == N_TILES_X-1) begin // B-R corner + end else if (j == N_TILES_X-1) begin : gen_bottom_right assign tile_north_req_in[i*N_TILES_X+j] = tile_south_req_out[(i-1)*N_TILES_X+j]; assign tile_north_rsp_in[i*N_TILES_X+j] = tile_south_rsp_out[(i-1)*N_TILES_X+j]; assign tile_north_wide_in[i*N_TILES_X+j] = tile_south_wide_out[(i-1)*N_TILES_X+j]; @@ -356,7 +311,7 @@ module magia assign tile_east_req_in[i*N_TILES_X+j] = '0; assign tile_east_rsp_in[i*N_TILES_X+j] = '0; assign tile_east_wide_in[i*N_TILES_X+j] = '0; - end else if ((j > 0) && (j < (N_TILES_X-1))) begin // Last row without corners + end else if ((j > 0) && (j < (N_TILES_X-1))) begin : gen_bottom_edge assign tile_north_req_in[i*N_TILES_X+j] = tile_south_req_out[(i-1)*N_TILES_X+j]; assign tile_north_rsp_in[i*N_TILES_X+j] = tile_south_rsp_out[(i-1)*N_TILES_X+j]; assign tile_north_wide_in[i*N_TILES_X+j] = tile_south_wide_out[(i-1)*N_TILES_X+j]; @@ -370,7 +325,7 @@ module magia assign tile_east_rsp_in[i*N_TILES_X+j] = tile_west_rsp_out[i*N_TILES_X+j+1]; assign tile_east_wide_in[i*N_TILES_X+j] = tile_west_wide_out[i*N_TILES_X+j+1]; end - end else if (j == 0 && i != 0 && i != N_TILES_Y-1) begin // First column + end else if (j == 0 && i != 0 && i != N_TILES_Y-1) begin : gen_left_edge assign tile_north_req_in[i*N_TILES_X+j] = tile_south_req_out[(i-1)*N_TILES_X+j]; assign tile_north_rsp_in[i*N_TILES_X+j] = tile_south_rsp_out[(i-1)*N_TILES_X+j]; assign tile_north_wide_in[i*N_TILES_X+j] = tile_south_wide_out[(i-1)*N_TILES_X+j]; @@ -386,7 +341,7 @@ module magia assign tile_east_req_in[i*N_TILES_X+j] = tile_west_req_out[i*N_TILES_X+j+1]; assign tile_east_rsp_in[i*N_TILES_X+j] = tile_west_rsp_out[i*N_TILES_X+j+1]; assign tile_east_wide_in[i*N_TILES_X+j] = tile_west_wide_out[i*N_TILES_X+j+1]; - end else if (j == N_TILES_X-1 && i != 0 && i != N_TILES_Y-1) begin // Last column + end else if (j == N_TILES_X-1 && i != 0 && i != N_TILES_Y-1) begin : gen_right_edge assign tile_north_req_in[i*N_TILES_X+j] = tile_south_req_out[(i-1)*N_TILES_X+j]; assign tile_north_rsp_in[i*N_TILES_X+j] = tile_south_rsp_out[(i-1)*N_TILES_X+j]; assign tile_north_wide_in[i*N_TILES_X+j] = tile_south_wide_out[(i-1)*N_TILES_X+j]; @@ -399,7 +354,7 @@ module magia assign tile_east_req_in[i*N_TILES_X+j] = '0; assign tile_east_rsp_in[i*N_TILES_X+j] = '0; assign tile_east_wide_in[i*N_TILES_X+j] = '0; - end else begin // Central tiles + end else begin : gen_center assign tile_north_req_in[i*N_TILES_X+j] = tile_south_req_out[(i-1)*N_TILES_X+j]; assign tile_north_rsp_in[i*N_TILES_X+j] = tile_south_rsp_out[(i-1)*N_TILES_X+j]; assign tile_north_wide_in[i*N_TILES_X+j] = tile_south_wide_out[(i-1)*N_TILES_X+j]; @@ -422,6 +377,21 @@ module magia /** FractalSync Network Beginning **/ /*******************************************************/ +`ifdef MAGIA_FSYNC + magia_pkg::h_root_fsync_req_t h_root_fsync_req[1][1]; // Single node, single link root node out interface + magia_pkg::h_root_fsync_rsp_t h_root_fsync_rsp[1][1]; // Single node, single link root node out interface + magia_pkg::v_root_fsync_req_t v_root_fsync_req[1][1]; // Single node, single link root node out interface + magia_pkg::v_root_fsync_rsp_t v_root_fsync_rsp[1][1]; // Single node, single link root node out interface + + assign h_root_fsync_rsp[0][0].wake = 1'b0; + assign h_root_fsync_rsp[0][0].sig.lvl = '0; + assign h_root_fsync_rsp[0][0].sig.id = '0; + assign h_root_fsync_rsp[0][0].error = 1'b0; + assign v_root_fsync_rsp[0][0].wake = 1'b0; + assign v_root_fsync_rsp[0][0].sig.lvl = '0; + assign v_root_fsync_rsp[0][0].sig.id = '0; + assign v_root_fsync_rsp[0][0].error = 1'b0; + if ((N_TILES_Y == 2) && (N_TILES_X == 2)) begin: gen_2x2_fsync fractal_sync_2x2 i_mesh_fsync ( .clk_i , @@ -507,7 +477,13 @@ module magia .v_2d_fsync_req_o ( v_root_fsync_req ), .v_2d_fsync_rsp_i ( v_root_fsync_rsp ) ); - end else $fatal(1,"Unsupported Mesh configuration"); + end else begin: gen_unsupported_fsync +`ifndef SYNTHESIS + $fatal(1,"FractalSync: unsupported mesh size %0dx%0d (supported: 2, 4, 8, 16, 32)", + N_TILES_X, N_TILES_Y); +`endif + end +`endif /*******************************************************/ /** FractalSync Network End **/ diff --git a/hw/mesh/magia_pkg.sv b/hw/mesh/magia_pkg.sv index 06a8bf6f..d3dfdfc5 100644 --- a/hw/mesh/magia_pkg.sv +++ b/hw/mesh/magia_pkg.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -46,6 +46,236 @@ package magia_pkg; localparam int unsigned COLLECTIVE_OP_W = 4; // Collective operation encoding (0: Unicast, 1: Multicast) localparam int unsigned USR_W = ADDR_W+COLLECTIVE_OP_W; // The User Width encodes the collective operation + // FractalSync is mesh-wide: MAGIA_FSYNC (make fsync=1) enables it in the mesh and in every tile +`ifdef MAGIA_FSYNC + localparam bit MagiaEnFractalSync = 1'b1; +`else + localparam bit MagiaEnFractalSync = 1'b0; +`endif + + // Tile configuration + + typedef struct packed { + int unsigned NumBanks; // Number of TCDM banks + int unsigned NumWordsBank; // Number of words per TCDM bank + } l1_cfg_t; + + typedef struct packed { + cv32e40x_pkg::rv32_e ISA; // Base integer ISA (RV32I/RV32E) + cv32e40x_pkg::a_ext_e A; // Atomic extension + cv32e40x_pkg::b_ext_e B; // Bit-manipulation extension + cv32e40x_pkg::m_ext_e M; // Multiply/divide extension + } ctrl_core_cfg_t; + + typedef struct packed { + idma_pkg::error_cap_e ErrorCap; // iDMA error handling capability + } idma_cfg_t; + + typedef struct packed { + int unsigned Height; // Systolic array height + int unsigned Width; // Systolic array width + int unsigned NumPipeRegs; // Pipeline registers in the systolic array + } redmule_cfg_t; + + typedef struct packed { + bit RVD; // Double-precision vector support (drives 64-bit TCDM) + bit RVF; // Single-precision FP support + bit RVV; // Vector extension support + int unsigned NumIPU; // Number of integer processing units + int unsigned NumFPU; // Number of FP processing units + bit XDivSqrt; // FP division/sqrt enable + bit XDMA; // DMA inside the Spatz CC + int unsigned ICacheL0LineCount; // private L0 tier lines, per core + int unsigned ICacheLineWidth; // cache line width in bits (both tiers) + int unsigned ICacheLineCount; // shared-tier set count + int unsigned ICacheWays; // shared-tier set associativity + } spatz_cfg_t; + + typedef struct packed { + int unsigned NumCores; // Number of cv32e40p cluster cores + int unsigned IcachePrivateSize; // private L0 tier size in bytes, per core + int unsigned IcacheSharedSize; // shared tier size in bytes (whole cluster) + int unsigned IcacheNumWays; // shared-tier set associativity + int unsigned IcacheLineWidth; // cache line width in bits (both tiers) + } cluster_cfg_t; + + typedef struct packed { + l1_cfg_t L1; // L1 scratchpad (TCDM) geometry + ctrl_core_cfg_t CtrlCore; // Control core (cv32e40x) ISA extensions + idma_cfg_t IDma; // iDMA parameters + bit EnRedMule; // RedMulE HWPE: engine + HCI HWPE port + OBI control port + bit EnSpatzCC; // Spatz CC: core complex + bootrom + dedicated I$ + HCI/OBI master ports + bit EnCluster; // PULP cluster: cv32e40p cores + shared I$ + OBI master ports + bit EnCollective; // Narrow collectives: control registers + collective_gen on the narrow master port + redmule_cfg_t RedMule; // RedMulE parameters (valid iff EnRedMule) + spatz_cfg_t Spatz; // Spatz CC parameters (valid iff EnSpatzCC) + cluster_cfg_t Cluster; // PULP cluster parameters (valid iff EnCluster) + } magia_tile_cfg_t; + + // Default parameter sets + + localparam l1_cfg_t MagiaL1DefaultCfg = '{ + NumBanks: N_MEM_BANKS, + NumWordsBank: N_WORDS_BANK + }; + + localparam ctrl_core_cfg_t MagiaCtrlCoreDefaultCfg = '{ + ISA: cv32e40x_pkg::RV32I, + A: cv32e40x_pkg::A, + B: cv32e40x_pkg::ZBA_ZBB_ZBC_ZBS, + M: cv32e40x_pkg::M + }; + + localparam idma_cfg_t MagiaIDmaDefaultCfg = '{ + ErrorCap: idma_pkg::NO_ERROR_HANDLING + }; + + localparam redmule_cfg_t MagiaRedMuleDefaultCfg = '{ + Height: 8, + Width: 8, + NumPipeRegs: 1 + }; + + // Derived from the MAGIA Makefile (Reflects on spatz_pkg.sv in spatz_cluster dep) +`ifdef SPATZ_RVD + localparam bit MagiaSpatzRVD = `SPATZ_RVD; +`else + localparam bit MagiaSpatzRVD = 1'b0; +`endif +`ifdef SPATZ_RVF + localparam bit MagiaSpatzRVF = `SPATZ_RVF; +`else + localparam bit MagiaSpatzRVF = 1'b1; +`endif +`ifdef SPATZ_RVV + localparam bit MagiaSpatzRVV = `SPATZ_RVV; +`else + localparam bit MagiaSpatzRVV = 1'b1; +`endif +`ifdef SPATZ_N_IPU + localparam int unsigned MagiaSpatzNumIPU = `SPATZ_N_IPU; +`else + localparam int unsigned MagiaSpatzNumIPU = 1; +`endif +`ifdef SPATZ_N_FPU + localparam int unsigned MagiaSpatzNumFPU = `SPATZ_N_FPU; +`else + localparam int unsigned MagiaSpatzNumFPU = 4; +`endif +`ifdef SPATZ_XDIVSQRT + localparam bit MagiaSpatzXDivSqrt = `SPATZ_XDIVSQRT; +`else + localparam bit MagiaSpatzXDivSqrt = 1'b0; +`endif +`ifdef SPATZ_XDMA + localparam bit MagiaSpatzXDMA = `SPATZ_XDMA; +`else + localparam bit MagiaSpatzXDMA = 1'b0; +`endif + + localparam spatz_cfg_t MagiaSpatzDefaultCfg = '{ + RVD: MagiaSpatzRVD, + RVF: MagiaSpatzRVF, + RVV: MagiaSpatzRVV, + NumIPU: MagiaSpatzNumIPU, + NumFPU: MagiaSpatzNumFPU, + XDivSqrt: MagiaSpatzXDivSqrt, + XDMA: MagiaSpatzXDMA, + ICacheL0LineCount: 8, + ICacheLineWidth: 256, + ICacheLineCount: 32, + ICacheWays: 2 + }; + + localparam cluster_cfg_t MagiaClusterDefaultCfg = '{ + NumCores: 8, + IcachePrivateSize: 512, + IcacheSharedSize: 4*1024, + IcacheNumWays: 4, + IcacheLineWidth: 256 + }; + + // All accelerators enabled (full tile) + localparam magia_tile_cfg_t MagiaTileDefaultCfg = '{ + L1: MagiaL1DefaultCfg, + CtrlCore: MagiaCtrlCoreDefaultCfg, + IDma: MagiaIDmaDefaultCfg, + EnRedMule: 1'b1, + EnSpatzCC: 1'b1, + EnCluster: 1'b1, + EnCollective: 1'b1, + RedMule: MagiaRedMuleDefaultCfg, + Spatz: MagiaSpatzDefaultCfg, + Cluster: MagiaClusterDefaultCfg + }; + + // RedMulE-only tile + localparam magia_tile_cfg_t MagiaTileRedMuleCfg = '{ + L1: MagiaL1DefaultCfg, + CtrlCore: MagiaCtrlCoreDefaultCfg, + IDma: MagiaIDmaDefaultCfg, + EnRedMule: 1'b1, + EnSpatzCC: 1'b0, + EnCluster: 1'b0, + EnCollective: 1'b1, + RedMule: MagiaRedMuleDefaultCfg, + Spatz: MagiaSpatzDefaultCfg, + Cluster: MagiaClusterDefaultCfg + }; + + // SpatzCC-only tile + localparam magia_tile_cfg_t MagiaTileSpatzCfg = '{ + L1: MagiaL1DefaultCfg, + CtrlCore: MagiaCtrlCoreDefaultCfg, + IDma: MagiaIDmaDefaultCfg, + EnRedMule: 1'b0, + EnSpatzCC: 1'b1, + EnCluster: 1'b0, + EnCollective: 1'b1, + RedMule: MagiaRedMuleDefaultCfg, + Spatz: MagiaSpatzDefaultCfg, + Cluster: MagiaClusterDefaultCfg + }; + + // PulpCluster-only tile + localparam magia_tile_cfg_t MagiaTileClusterCfg = '{ + L1: MagiaL1DefaultCfg, + CtrlCore: MagiaCtrlCoreDefaultCfg, + IDma: MagiaIDmaDefaultCfg, + EnRedMule: 1'b0, + EnSpatzCC: 1'b0, + EnCluster: 1'b1, + EnCollective: 1'b1, + RedMule: MagiaRedMuleDefaultCfg, + Spatz: MagiaSpatzDefaultCfg, + Cluster: MagiaClusterDefaultCfg + }; + + localparam magia_tile_cfg_t [N_TILES-1:0] HOMO_TILE_CFGS = '{ + // Default Homogeneus Mesh + default: MagiaTileDefaultCfg + }; + + + // Supported square meshes (2x2, 4x4, 8x8, 16x16, 32x32) have equal + // numbers of full, RedMulE-only, Spatz-only and cluster-only tiles: + + function automatic magia_tile_cfg_t [N_TILES-1:0] gen_hetero_tile_cfgs(); + magia_tile_cfg_t [N_TILES-1:0] cfgs; + for (int unsigned i = 0; i < N_TILES; i++) begin + unique case ((i * 4) / N_TILES) + 0: cfgs[i] = MagiaTileDefaultCfg; + 1: cfgs[i] = MagiaTileRedMuleCfg; + 2: cfgs[i] = MagiaTileSpatzCfg; + 3: cfgs[i] = MagiaTileClusterCfg; + default: cfgs[i] = MagiaTileDefaultCfg; + endcase + end + return cfgs; + endfunction + + localparam magia_tile_cfg_t [N_TILES-1:0] HETERO_TILE_CFGS = gen_hetero_tile_cfgs(); + // Parameters used by the NoC parameter int unsigned AXI_NOC_ID_W = 6; // AXI NoC ID Width: matches slave side id_width (6 bits) parameter int unsigned AXI_NOC_U_W = USR_W; @@ -55,9 +285,10 @@ package magia_pkg; parameter int unsigned L2_U_W = USR_W; // Parameter used for the Fractal Sync network + parameter int unsigned FSYNC_LVL_MIN = 2; // Smallest FSYNC_LVL keeping the widths below legal parameter int unsigned FSYNC_LVL = (N_TILES_X == N_TILES_Y) ? $clog2(N_TILES) : - -1; // Number of levels of the Fractal Sync tree + FSYNC_LVL_MIN; // Number of levels of the Fractal Sync tree parameter int unsigned ROOT_FSYNC_AGGR_W = 1; // Aggregate width of the Fractal Sync Root tree out interface parameter int unsigned TILE_FSYNC_AGGR_W = ROOT_FSYNC_AGGR_W+FSYNC_LVL; // Aggregate width of the Fractal Sync interface (CU-FSync interface) parameter int unsigned TILE_FSYNC_LVL_W = $clog2(TILE_FSYNC_AGGR_W-1); // Level width of the Fractal Sync interface (CU-FSync interface) diff --git a/hw/mesh/noc/magia_noc_pkg.sv b/hw/mesh/noc/magia_noc_pkg.sv index a28349a9..573f1a4a 100644 --- a/hw/mesh/noc/magia_noc_pkg.sv +++ b/hw/mesh/noc/magia_noc_pkg.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -74,7 +74,7 @@ package magia_noc_pkg; function automatic sam_rule_t[SamNumRules-1:0] gen_sam_table(int unsigned num_tiles); sam_rule_t[SamNumRules-1:0] Sam; - case (num_tiles) + unique case (num_tiles) 32'd4: begin Sam = floo_axi_nw_mesh_2x2_noc_pkg::Sam; end @@ -90,6 +90,9 @@ package magia_noc_pkg; 32'd1024: begin Sam = floo_axi_nw_mesh_32x32_noc_pkg::Sam; end + default: begin + Sam = '0; + end endcase return Sam; @@ -99,7 +102,7 @@ package magia_noc_pkg; function automatic collective_sam_rule_t[SamNumRules-1:0] gen_collective_sam_table(int unsigned num_tiles); collective_sam_rule_t[SamNumRules-1:0] CollectiveSam; - case (num_tiles) + unique case (num_tiles) 32'd4: begin CollectiveSam = floo_axi_nw_mesh_2x2_noc_pkg::CollectiveSam; end @@ -115,6 +118,9 @@ package magia_noc_pkg; 32'd1024: begin CollectiveSam = floo_axi_nw_mesh_32x32_noc_pkg::Sam; end + default: begin + CollectiveSam = '0; + end endcase return CollectiveSam; @@ -128,7 +134,7 @@ package magia_noc_pkg; function automatic route_cfg_t gen_route_config(int unsigned num_tiles); route_cfg_t RouteCfg; - case (num_tiles) + unique case (num_tiles) 32'd4: begin RouteCfg = floo_axi_nw_mesh_2x2_noc_pkg::RouteCfg; end @@ -144,6 +150,9 @@ package magia_noc_pkg; 32'd1024: begin RouteCfg = floo_axi_nw_mesh_32x32_noc_pkg::RouteCfg; end + default: begin + RouteCfg = '0; + end endcase return RouteCfg; diff --git a/hw/tile/cluster_event_map.sv b/hw/tile/cluster_event_map.sv index f32f32eb..99601dac 100644 --- a/hw/tile/cluster_event_map.sv +++ b/hw/tile/cluster_event_map.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. diff --git a/hw/tile/collective_gen.sv b/hw/tile/collective_gen.sv index 825d4e14..3453fe38 100644 --- a/hw/tile/collective_gen.sv +++ b/hw/tile/collective_gen.sv @@ -5,15 +5,15 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * SPDX-License-Identifier: SHL-0.51 - * Authors: Carlotta Chiarini + * Authors: Carlotta Chiarini, Fondazione Chips-IT * Collective Generator diff --git a/hw/tile/converters/cache2instr.sv b/hw/tile/converters/cache2instr.sv index 39ea003c..594a61d2 100644 --- a/hw/tile/converters/cache2instr.sv +++ b/hw/tile/converters/cache2instr.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. diff --git a/hw/tile/converters/cv32e40p_data2obi.sv b/hw/tile/converters/cv32e40p_data2obi.sv index be33970c..d3dd3799 100644 --- a/hw/tile/converters/cv32e40p_data2obi.sv +++ b/hw/tile/converters/cv32e40p_data2obi.sv @@ -5,17 +5,17 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * SPDX-License-Identifier: SHL-0.51 * * Authors: Victor Isachi - * Luca Balboni + * Luca Balboni, Fondazione Chips-IT * * CV32E40P Core Data - OBI REQ Converter */ diff --git a/hw/tile/converters/cv32e40p_obi2data.sv b/hw/tile/converters/cv32e40p_obi2data.sv index 1c318593..22608862 100644 --- a/hw/tile/converters/cv32e40p_obi2data.sv +++ b/hw/tile/converters/cv32e40p_obi2data.sv @@ -5,17 +5,17 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * SPDX-License-Identifier: SHL-0.51 * * Authors: Victor Isachi - * Luca Balboni + * Luca Balboni, Fondazione Chips-IT * * OBI - CV32E40P Core Data RSP Converter * diff --git a/hw/tile/converters/cv32e40x_data2obi.sv b/hw/tile/converters/cv32e40x_data2obi.sv index 522bd6cb..dc64c058 100644 --- a/hw/tile/converters/cv32e40x_data2obi.sv +++ b/hw/tile/converters/cv32e40x_data2obi.sv @@ -5,17 +5,17 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * SPDX-License-Identifier: SHL-0.51 * * Authors: Victor Isachi - * Luca Balboni + * Luca Balboni, Fondazione Chips-IT * * CV32E40X Core Data - OBI REQ Converter * diff --git a/hw/tile/converters/cv32e40x_obi2data.sv b/hw/tile/converters/cv32e40x_obi2data.sv index e99f6b1d..6bd0146d 100644 --- a/hw/tile/converters/cv32e40x_obi2data.sv +++ b/hw/tile/converters/cv32e40x_obi2data.sv @@ -5,17 +5,17 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * SPDX-License-Identifier: SHL-0.51 * * Authors: Victor Isachi - * Luca Balboni + * Luca Balboni, Fondazione Chips-IT * * OBI - CV32E40X Core Data RSP Converter * diff --git a/hw/tile/converters/hci2obi.sv b/hw/tile/converters/hci2obi.sv index a25c5544..b5587afb 100644 --- a/hw/tile/converters/hci2obi.sv +++ b/hw/tile/converters/hci2obi.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -20,20 +20,21 @@ */ module hci2obi_rsp #( - parameter type hci_rsp_t = logic, - parameter type obi_rsp_t = logic + parameter type hci_rsp_t = magia_tile_pkg::core_hci_data_rsp_t, + parameter type obi_rsp_t = magia_tile_pkg::core_obi_data_rsp_t )( input hci_rsp_t hci_rsp_i, output obi_rsp_t obi_rsp_o ); - assign obi_rsp_o.gnt = hci_rsp_i.gnt; - assign obi_rsp_o.rvalid = hci_rsp_i.r_valid; - assign obi_rsp_o.r.rdata = hci_rsp_i.r_data; - assign obi_rsp_o.r.rid = hci_rsp_i.r_id; - assign obi_rsp_o.r.err = hci_rsp_i.r_opc; - assign obi_rsp_o.r.r_optional.ruser = '0; - assign obi_rsp_o.r.r_optional.exokay = 1'b0; - assign obi_rsp_o.r.r_optional.rchk = '0; + // Default zero covers the parity fields of integrity OBI types + always_comb begin + obi_rsp_o = '0; + obi_rsp_o.gnt = hci_rsp_i.gnt; + obi_rsp_o.rvalid = hci_rsp_i.r_valid; + obi_rsp_o.r.rdata = hci_rsp_i.r_data; + obi_rsp_o.r.rid = hci_rsp_i.r_id[$bits(obi_rsp_o.r.rid)-1:0]; // Only the low ID bits travel back on OBI + obi_rsp_o.r.err = hci_rsp_i.r_opc; + end endmodule: hci2obi_rsp diff --git a/hw/tile/converters/instr2cache.sv b/hw/tile/converters/instr2cache.sv index ab0264ce..c6479739 100644 --- a/hw/tile/converters/instr2cache.sv +++ b/hw/tile/converters/instr2cache.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. diff --git a/hw/tile/converters/instr2obi.sv b/hw/tile/converters/instr2obi.sv index 35051c1e..a986fe7d 100644 --- a/hw/tile/converters/instr2obi.sv +++ b/hw/tile/converters/instr2obi.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. diff --git a/hw/tile/converters/obi2hci.sv b/hw/tile/converters/obi2hci.sv index f7b265f3..82662458 100644 --- a/hw/tile/converters/obi2hci.sv +++ b/hw/tile/converters/obi2hci.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -20,8 +20,8 @@ */ module obi2hci_req #( - parameter type obi_req_t = logic, - parameter type hci_req_t = logic + parameter type obi_req_t = magia_tile_pkg::core_obi_data_req_t, + parameter type hci_req_t = magia_tile_pkg::core_hci_data_req_t )( input obi_req_t obi_req_i, output hci_req_t hci_req_o diff --git a/hw/tile/converters/obi2hwpe_ctrl.sv b/hw/tile/converters/obi2hwpe_ctrl.sv index ebefc8ea..1d056121 100644 --- a/hw/tile/converters/obi2hwpe_ctrl.sv +++ b/hw/tile/converters/obi2hwpe_ctrl.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. diff --git a/hw/tile/converters/obi2instr.sv b/hw/tile/converters/obi2instr.sv index d8d06535..1b2f2fb5 100644 --- a/hw/tile/converters/obi2instr.sv +++ b/hw/tile/converters/obi2instr.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. diff --git a/hw/tile/converters/reqrsp2obi.sv b/hw/tile/converters/reqrsp2obi.sv index ff4b5bd3..74b4ac44 100644 --- a/hw/tile/converters/reqrsp2obi.sv +++ b/hw/tile/converters/reqrsp2obi.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -22,25 +22,21 @@ module reqrsp2obi import reqrsp_pkg::*; #( - parameter obi_pkg::obi_cfg_t ObiCfg = obi_pkg::ObiDefaultConfig, - parameter type obi_req_t = logic, - parameter type obi_rsp_t = logic, - parameter type reqrsp_req_t = logic, - parameter type reqrsp_rsp_t = logic + parameter obi_pkg::obi_cfg_t ObiCfg = obi_pkg::ObiDefaultConfig ) ( - input logic clk_i, - input logic rst_ni, + input logic clk_i, + input logic rst_ni, - input reqrsp_req_t reqrsp_req_i, - output reqrsp_rsp_t reqrsp_rsp_o, + input magia_tile_pkg::spatz_reqrsp_req_t reqrsp_req_i, + output magia_tile_pkg::spatz_reqrsp_rsp_t reqrsp_rsp_o, - output obi_req_t obi_req_o, - input obi_rsp_t obi_rsp_i + output magia_tile_pkg::core_obi_data_req_t obi_req_o, + input magia_tile_pkg::core_obi_data_rsp_t obi_rsp_i ); // Convert reqrsp AMO to OBI ATOP encoding function automatic logic [5:0] amo_to_atop(reqrsp_pkg::amo_op_e amo); - case (amo) + unique case (amo) reqrsp_pkg::AMONone: return 6'h00; reqrsp_pkg::AMOSwap: return 6'h21; reqrsp_pkg::AMOAdd: return 6'h20; @@ -65,7 +61,7 @@ module reqrsp2obi assign amo_detected = (reqrsp_req_i.q.amo != reqrsp_pkg::AMONone); assign obi_req_o.req = reqrsp_req_i.q_valid; assign obi_req_o.a.addr = reqrsp_req_i.q.addr; - assign obi_req_o.a.we = reqrsp_req_i.q.write || amo_detected; + assign obi_req_o.a.we = reqrsp_req_i.q.write | amo_detected; assign obi_req_o.a.wdata = reqrsp_req_i.q.data; assign obi_req_o.a.be = reqrsp_req_i.q.strb; assign obi_req_o.a.aid = '0; diff --git a/hw/tile/converters/reqrsp64_to_obi32.sv b/hw/tile/converters/reqrsp64_to_obi32.sv index 70c0e99c..af8b0f09 100644 --- a/hw/tile/converters/reqrsp64_to_obi32.sv +++ b/hw/tile/converters/reqrsp64_to_obi32.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -23,22 +23,21 @@ module reqrsp64_to_obi32 import obi_pkg::*; #( - parameter type reqrsp_req_t = logic, // 64-bit reqrsp request type - parameter type reqrsp_rsp_t = logic, // 64-bit reqrsp response type - parameter type obi_req_t = logic, // 32-bit OBI request type - parameter type obi_rsp_t = logic, // 32-bit OBI response type + // 64-bit Snitch types from the RVD branch: the package ones are 32-bit when RVD is off + parameter type reqrsp_req_t, + parameter type reqrsp_rsp_t, parameter obi_pkg::obi_cfg_t ObiCfg = obi_pkg::ObiDefaultConfig )( - input logic clk_i, - input logic rst_ni, + input logic clk_i, + input logic rst_ni, // REQRSP side (64-bit from Snitch RV64) - input reqrsp_req_t reqrsp_req_i, - output reqrsp_rsp_t reqrsp_rsp_o, + input reqrsp_req_t reqrsp_req_i, + output reqrsp_rsp_t reqrsp_rsp_o, // OBI side (32-bit to peripherals/L2) - output obi_req_t obi_req_o, - input obi_rsp_t obi_rsp_i + output magia_tile_pkg::core_obi_data_req_t obi_req_o, + input magia_tile_pkg::core_obi_data_rsp_t obi_rsp_i ); /*******************************************************************/ @@ -81,11 +80,14 @@ module reqrsp64_to_obi32 // Track which word half was requested (for correct response data placement) logic [7:0] req_strb_q; - + logic req_fire; + + assign req_fire = reqrsp_req_i.q_valid & obi_rsp_i.gnt; + always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin req_strb_q <= 8'h0; - end else if (reqrsp_req_i.q_valid && obi_rsp_i.gnt) begin + end else if (req_fire) begin req_strb_q <= reqrsp_req_i.q.strb; end end diff --git a/hw/tile/converters/tcdm2hci.sv b/hw/tile/converters/tcdm2hci.sv index d54cf4e0..e9cea1b2 100644 --- a/hw/tile/converters/tcdm2hci.sv +++ b/hw/tile/converters/tcdm2hci.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -20,10 +20,10 @@ */ module tcdm2hci #( - parameter type tcdm_req_t = logic, - parameter type tcdm_rsp_t = logic, - parameter type hci_req_t = logic, - parameter type hci_rsp_t = logic + parameter type tcdm_req_t = magia_tile_pkg::spatz_tcdm_req_t, + parameter type tcdm_rsp_t = magia_tile_pkg::spatz_tcdm_rsp_t, + parameter type hci_req_t = magia_tile_pkg::core_hci_data_req_t, + parameter type hci_rsp_t = magia_tile_pkg::core_hci_data_rsp_t )( input logic clk_i, input logic rst_ni, @@ -41,13 +41,16 @@ module tcdm2hci #( /* TCDM → HCI Request Mapping */ /*******************************************************************/ - // Map request channel + localparam int unsigned HciAddW = $bits(hci_req_o.add); + localparam int unsigned HciUserW = $bits(hci_req_o.user); + + // Map request channel; the TCDM offset is zero extended to the HCI address assign hci_req_o.req = tcdm_req_i.q_valid; - assign hci_req_o.add = tcdm_req_i.q.addr; + assign hci_req_o.add = HciAddW'(tcdm_req_i.q.addr); assign hci_req_o.wen = ~tcdm_req_i.q.write; assign hci_req_o.data = tcdm_req_i.q.data; assign hci_req_o.be = tcdm_req_i.q.strb; - assign hci_req_o.user = tcdm_req_i.q.user; + assign hci_req_o.user = HciUserW'(tcdm_req_i.q.user); assign hci_req_o.id = '0; assign hci_req_o.ecc = '0; assign hci_req_o.ereq = '0; diff --git a/hw/tile/converters/tcdm2hci_atomic.sv b/hw/tile/converters/tcdm2hci_atomic.sv index c88d6a03..b88883d7 100644 --- a/hw/tile/converters/tcdm2hci_atomic.sv +++ b/hw/tile/converters/tcdm2hci_atomic.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -26,20 +26,20 @@ module tcdm2hci_atomic import obi_pkg::*; import magia_tile_pkg::*; #( - parameter type tcdm_req_t = logic, - parameter type tcdm_rsp_t = logic, - parameter type obi_req_t = logic, - parameter type obi_rsp_t = logic, - parameter type hci_req_t = logic, - parameter type hci_rsp_t = logic, + parameter type tcdm_req_t = magia_tile_pkg::spatz_tcdm_req_t, + parameter type tcdm_rsp_t = magia_tile_pkg::spatz_tcdm_rsp_t, + parameter type obi_req_t = magia_tile_pkg::core_obi_data_req_t, + parameter type obi_rsp_t = magia_tile_pkg::core_obi_data_rsp_t, + parameter type hci_req_t = magia_tile_pkg::core_hci_data_req_t, + parameter type hci_rsp_t = magia_tile_pkg::core_hci_data_rsp_t, // OBI channel types - parameter type obi_a_chan_t = logic, - parameter type obi_r_chan_t = logic, + parameter type obi_a_chan_t = magia_tile_pkg::core_data_obi_a_chan_t, + parameter type obi_r_chan_t = magia_tile_pkg::core_data_obi_r_chan_t, // OBI optional types for atomic resolver - parameter type obi_a_optional_t = logic, - parameter type obi_r_optional_t = logic, + parameter type obi_a_optional_t = magia_tile_pkg::core_data_obi_a_optional_t, + parameter type obi_r_optional_t = magia_tile_pkg::core_data_obi_r_optional_t, // OBI configuration for atomic resolver parameter obi_pkg::obi_cfg_t SbrPortObiCfg = obi_pkg::ObiDefaultConfig, @@ -119,27 +119,25 @@ module tcdm2hci_atomic /* Stage 3: OBI Cut (optional - controlled by BypassCut param) */ /*******************************************************************/ - generate - if (BypassCut) begin : gen_bypass_cut - assign obi_cut_req = obi_resolved_req; - assign obi_resolved_rsp = obi_cut_rsp; - end else begin : gen_enable_cut - obi_cut #( - .ObiCfg ( MgrPortObiCfg ), - .obi_a_chan_t ( obi_a_chan_t ), - .obi_r_chan_t ( obi_r_chan_t ), - .obi_req_t ( obi_req_t ), - .obi_rsp_t ( obi_rsp_t ) - ) i_obi_cut_post_atomic ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .sbr_port_req_i ( obi_resolved_req ), - .sbr_port_rsp_o ( obi_resolved_rsp ), - .mgr_port_req_o ( obi_cut_req ), - .mgr_port_rsp_i ( obi_cut_rsp ) - ); - end - endgenerate + if (BypassCut) begin : gen_bypass_cut + assign obi_cut_req = obi_resolved_req; + assign obi_resolved_rsp = obi_cut_rsp; + end else begin : gen_enable_cut + obi_cut #( + .ObiCfg ( MgrPortObiCfg ), + .obi_a_chan_t ( obi_a_chan_t ), + .obi_r_chan_t ( obi_r_chan_t ), + .obi_req_t ( obi_req_t ), + .obi_rsp_t ( obi_rsp_t ) + ) i_obi_cut_post_atomic ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .sbr_port_req_i ( obi_resolved_req ), + .sbr_port_rsp_o ( obi_resolved_rsp ), + .mgr_port_req_o ( obi_cut_req ), + .mgr_port_rsp_i ( obi_cut_rsp ) + ); + end /*******************************************************************/ /* Stage 4: OBI → HCI conversion (request and response) */ diff --git a/hw/tile/converters/tcdm2obi.sv b/hw/tile/converters/tcdm2obi.sv index c491bd48..a3210669 100644 --- a/hw/tile/converters/tcdm2obi.sv +++ b/hw/tile/converters/tcdm2obi.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -23,10 +23,10 @@ module tcdm2obi import reqrsp_pkg::*; #( - parameter type tcdm_req_t = logic, - parameter type tcdm_rsp_t = logic, - parameter type obi_req_t = logic, - parameter type obi_rsp_t = logic + parameter type tcdm_req_t = magia_tile_pkg::spatz_tcdm_req_t, + parameter type tcdm_rsp_t = magia_tile_pkg::spatz_tcdm_rsp_t, + parameter type obi_req_t = magia_tile_pkg::core_obi_data_req_t, + parameter type obi_rsp_t = magia_tile_pkg::core_obi_data_rsp_t )( input logic clk_i, input logic rst_ni, @@ -40,7 +40,7 @@ module tcdm2obi // Convert TCDM AMO to OBI ATOP encoding function automatic logic [5:0] amo_to_atop(reqrsp_pkg::amo_op_e amo); - case (amo) + unique case (amo) reqrsp_pkg::AMONone: return 6'h00; // ATOPNONE reqrsp_pkg::AMOSwap: return 6'h21; // AMOSWAP reqrsp_pkg::AMOAdd: return 6'h20; // AMOADD @@ -57,13 +57,15 @@ module tcdm2obi endcase endfunction + localparam int unsigned ObiAddW = $bits(obi_req_o.a.addr); + logic amo_detected; assign amo_detected = (tcdm_req_i.q.amo != reqrsp_pkg::AMONone); // TCDM → OBI Request (combinatorial) assign obi_req_o.req = tcdm_req_i.q_valid; - assign obi_req_o.a.addr = tcdm_req_i.q.addr; - assign obi_req_o.a.we = tcdm_req_i.q.write || amo_detected; + assign obi_req_o.a.addr = ObiAddW'(tcdm_req_i.q.addr); // TCDM offset, zero extended + assign obi_req_o.a.we = tcdm_req_i.q.write | amo_detected; assign obi_req_o.a.wdata = tcdm_req_i.q.data; assign obi_req_o.a.be = tcdm_req_i.q.strb; assign obi_req_o.a.aid = '0; diff --git a/hw/tile/converters/tcdm64_to_dual_hci32.sv b/hw/tile/converters/tcdm64_to_dual_hci32.sv index 76adac67..01f5bb14 100644 --- a/hw/tile/converters/tcdm64_to_dual_hci32.sv +++ b/hw/tile/converters/tcdm64_to_dual_hci32.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -21,12 +21,11 @@ */ module tcdm64_to_dual_hci32 #( - parameter type tcdm64_req_t = logic, // 64-bit TCDM request type - parameter type tcdm64_rsp_t = logic, // 64-bit TCDM response type - parameter type tcdm32_req_t = logic, // 32-bit TCDM request type - parameter type tcdm32_rsp_t = logic, // 32-bit TCDM response type - parameter type hci_req_t = logic, // 32-bit HCI request type - parameter type hci_rsp_t = logic // 32-bit HCI response type + // 64-bit Snitch types from the RVD branch: the package ones are 32-bit when RVD is off + parameter type tcdm64_req_t, + parameter type tcdm64_rsp_t, + parameter type hci_req_t = magia_tile_pkg::core_hci_data_req_t, // 32-bit HCI request type + parameter type hci_rsp_t = magia_tile_pkg::core_hci_data_rsp_t // 32-bit HCI response type )( input logic clk_i, input logic rst_ni, @@ -42,6 +41,10 @@ module tcdm64_to_dual_hci32 #( input hci_rsp_t hci_rsp_hi_i ); + // 32-bit side, fixed by the package; the HCI end depends on TileIW + typedef magia_tile_pkg::spatz_tcdm32_req_t tcdm32_req_t; + typedef magia_tile_pkg::spatz_tcdm32_rsp_t tcdm32_rsp_t; + // Internal TCDM32 signals tcdm32_req_t tcdm32_req_lo, tcdm32_req_hi; tcdm32_rsp_t tcdm32_rsp_lo, tcdm32_rsp_hi; @@ -51,11 +54,9 @@ module tcdm64_to_dual_hci32 #( /*******************************************************************/ tcdm64_to_dual_tcdm32 #( - .FIFO_DEPTH ( 4 ), // Match Snitch's NUM_INT_OUTSTANDING_MEM .tcdm64_req_t ( tcdm64_req_t ), .tcdm64_rsp_t ( tcdm64_rsp_t ), - .tcdm32_req_t ( tcdm32_req_t ), - .tcdm32_rsp_t ( tcdm32_rsp_t ) + .FIFO_DEPTH ( 4 ) // Match Snitch's NUM_INT_OUTSTANDING_MEM ) i_tcdm64_to_dual_tcdm32 ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), diff --git a/hw/tile/converters/tcdm64_to_dual_hci32_atomic.sv b/hw/tile/converters/tcdm64_to_dual_hci32_atomic.sv index cd3047d3..08bd2c51 100644 --- a/hw/tile/converters/tcdm64_to_dual_hci32_atomic.sv +++ b/hw/tile/converters/tcdm64_to_dual_hci32_atomic.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -23,21 +23,12 @@ module tcdm64_to_dual_hci32_atomic import obi_pkg::*; #( - parameter type tcdm64_req_t = logic, // 64-bit TCDM request type (with AMO) - parameter type tcdm64_rsp_t = logic, // 64-bit TCDM response type - parameter type tcdm32_req_t = logic, // 32-bit TCDM request type (with AMO) - parameter type tcdm32_rsp_t = logic, // 32-bit TCDM response type - parameter type obi32_req_t = logic, // 32-bit OBI request type - parameter type obi32_rsp_t = logic, // 32-bit OBI response type - parameter type obi32_a_chan_t = logic, // 32-bit OBI address channel type - parameter type obi32_r_chan_t = logic, // 32-bit OBI response channel type - parameter type hci_req_t = logic, // 32-bit HCI request type - parameter type hci_rsp_t = logic, // 32-bit HCI response type - - // OBI optional types for atomic resolvers - parameter type obi32_a_optional_t = logic, - parameter type obi32_r_optional_t = logic, - + // 64-bit Snitch types from the RVD branch: the package ones are 32-bit when RVD is off + parameter type tcdm64_req_t, + parameter type tcdm64_rsp_t, + parameter type hci_req_t = magia_tile_pkg::core_hci_data_req_t, // 32-bit HCI request type + parameter type hci_rsp_t = magia_tile_pkg::core_hci_data_rsp_t, // 32-bit HCI response type + // OBI configuration for atomic resolvers parameter obi_pkg::obi_cfg_t SbrPortObiCfg = obi_pkg::ObiDefaultConfig, parameter obi_pkg::obi_cfg_t MgrPortObiCfg = obi_pkg::ObiDefaultConfig, @@ -57,6 +48,16 @@ module tcdm64_to_dual_hci32_atomic input hci_rsp_t hci_rsp_hi_i ); + // 32-bit side, fixed by the package; the HCI end depends on TileIW + typedef magia_tile_pkg::spatz_tcdm32_req_t tcdm32_req_t; + typedef magia_tile_pkg::spatz_tcdm32_rsp_t tcdm32_rsp_t; + typedef magia_tile_pkg::spatz_obi32_req_t obi32_req_t; + typedef magia_tile_pkg::spatz_obi32_rsp_t obi32_rsp_t; + typedef magia_tile_pkg::spatz_obi32_a_chan_t obi32_a_chan_t; + typedef magia_tile_pkg::spatz_obi32_r_chan_t obi32_r_chan_t; + typedef magia_tile_pkg::spatz_obi32_a_optional_t obi32_a_optional_t; + typedef magia_tile_pkg::spatz_obi32_r_optional_t obi32_r_optional_t; + // Internal TCDM32 signals after tcdm64_to_dual_tcdm32 tcdm32_req_t tcdm32_req_lo, tcdm32_req_hi; tcdm32_rsp_t tcdm32_rsp_lo, tcdm32_rsp_hi; @@ -66,11 +67,9 @@ module tcdm64_to_dual_hci32_atomic /*******************************************************************/ tcdm64_to_dual_tcdm32 #( - .FIFO_DEPTH ( 4 ), // Match Snitch's NUM_INT_OUTSTANDING_MEM .tcdm64_req_t ( tcdm64_req_t ), .tcdm64_rsp_t ( tcdm64_rsp_t ), - .tcdm32_req_t ( tcdm32_req_t ), - .tcdm32_rsp_t ( tcdm32_rsp_t ) + .FIFO_DEPTH ( 4 ) // Match Snitch's NUM_INT_OUTSTANDING_MEM ) i_tcdm64_to_dual_tcdm32 ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), diff --git a/hw/tile/converters/tcdm64_to_dual_tcdm32.sv b/hw/tile/converters/tcdm64_to_dual_tcdm32.sv index a709fc03..ed45111e 100644 --- a/hw/tile/converters/tcdm64_to_dual_tcdm32.sv +++ b/hw/tile/converters/tcdm64_to_dual_tcdm32.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -21,12 +21,11 @@ */ module tcdm64_to_dual_tcdm32 #( + // 64-bit Snitch types from the RVD branch: the package ones are 32-bit when RVD is off + parameter type tcdm64_req_t, + parameter type tcdm64_rsp_t, parameter int unsigned FIFO_DEPTH = 4, // Match Snitch's NUM_INT_OUTSTANDING_MEM parameter bit EnableSpill = 1'b1, - parameter type tcdm64_req_t = logic, - parameter type tcdm64_rsp_t = logic, - parameter type tcdm32_req_t = logic, - parameter type tcdm32_rsp_t = logic, // Local parameter matching fifo_v3 definition parameter int unsigned ADDR_DEPTH = (FIFO_DEPTH > 1) ? $clog2(FIFO_DEPTH) : 1 )( @@ -36,12 +35,16 @@ module tcdm64_to_dual_tcdm32 #( input tcdm64_req_t tcdm_req_i, output tcdm64_rsp_t tcdm_rsp_o, - output tcdm32_req_t tcdm_req_lo_o, - input tcdm32_rsp_t tcdm_rsp_lo_i, - output tcdm32_req_t tcdm_req_hi_o, - input tcdm32_rsp_t tcdm_rsp_hi_i + output magia_tile_pkg::spatz_tcdm32_req_t tcdm_req_lo_o, + input magia_tile_pkg::spatz_tcdm32_rsp_t tcdm_rsp_lo_i, + output magia_tile_pkg::spatz_tcdm32_req_t tcdm_req_hi_o, + input magia_tile_pkg::spatz_tcdm32_rsp_t tcdm_rsp_hi_i ); + // 32-bit side, fixed by the package + typedef magia_tile_pkg::spatz_tcdm32_req_t tcdm32_req_t; + typedef magia_tile_pkg::spatz_tcdm32_rsp_t tcdm32_rsp_t; + /*******************************************************************/ /* Spill Register (Breaking Timing Loop) */ /*******************************************************************/ @@ -105,9 +108,9 @@ module tcdm64_to_dual_tcdm32 #( logic strb_is_zero, is_load, access_lo, access_hi; assign strb_is_zero = (tcdm_req_int.q.strb == 8'h00); - assign is_load = !tcdm_req_int.q.write; - assign access_lo = |tcdm_req_int.q.strb[3:0] || (strb_is_zero && is_load); - assign access_hi = |tcdm_req_int.q.strb[7:4] || (strb_is_zero && is_load); + assign is_load = ~tcdm_req_int.q.write; + assign access_lo = |tcdm_req_int.q.strb[3:0] | (strb_is_zero & is_load); + assign access_hi = |tcdm_req_int.q.strb[7:4] | (strb_is_zero & is_load); // FIFO signals logic fifo_full, fifo_empty; @@ -116,7 +119,7 @@ module tcdm64_to_dual_tcdm32 #( logic [ADDR_DEPTH-1:0] fifo_usage; // Match fifo_v3 usage_o width // FIFO push: when request is accepted - assign fifo_push = tcdm_req_int.q_valid && tcdm_rsp_int.q_ready; + assign fifo_push = tcdm_req_int.q_valid & tcdm_rsp_int.q_ready; // FIFO pop: when response is sent assign fifo_pop = tcdm_rsp_int.p_valid; @@ -157,7 +160,7 @@ module tcdm64_to_dual_tcdm32 #( if (!fifo_empty) begin if (access_lo_rsp && access_hi_rsp) begin - rsp_arriving = tcdm_rsp_lo_i.p_valid && tcdm_rsp_hi_i.p_valid; + rsp_arriving = tcdm_rsp_lo_i.p_valid & tcdm_rsp_hi_i.p_valid; end else if (access_lo_rsp) begin rsp_arriving = tcdm_rsp_lo_i.p_valid; end else if (access_hi_rsp) begin @@ -201,10 +204,11 @@ module tcdm64_to_dual_tcdm32 #( tcdm_req_lo_o.q.data = tcdm_req_int.q.data[31:0]; tcdm_req_lo_o.q.user = tcdm_req_int.q.user; - if (strb_is_zero && is_load) + if (strb_is_zero && is_load) begin tcdm_req_lo_o.q.strb = 4'hF; - else + end else begin tcdm_req_lo_o.q.strb = tcdm_req_int.q.strb[3:0]; + end end end @@ -226,10 +230,11 @@ module tcdm64_to_dual_tcdm32 #( tcdm_req_hi_o.q.data = tcdm_req_int.q.data[63:32]; tcdm_req_hi_o.q.user = tcdm_req_int.q.user; - if (strb_is_zero && is_load) + if (strb_is_zero && is_load) begin tcdm_req_hi_o.q.strb = 4'hF; - else + end else begin tcdm_req_hi_o.q.strb = tcdm_req_int.q.strb[7:4]; + end end end @@ -244,7 +249,7 @@ module tcdm64_to_dual_tcdm32 #( if (fifo_full) begin tcdm_rsp_int.q_ready = 1'b0; end else if (access_lo && access_hi) begin - tcdm_rsp_int.q_ready = tcdm_rsp_lo_i.q_ready && tcdm_rsp_hi_i.q_ready; + tcdm_rsp_int.q_ready = tcdm_rsp_lo_i.q_ready & tcdm_rsp_hi_i.q_ready; end else if (access_lo) begin tcdm_rsp_int.q_ready = tcdm_rsp_lo_i.q_ready; end else if (access_hi) begin diff --git a/hw/tile/converters/tcdm64_to_dual_tcdm32_blocking.sv b/hw/tile/converters/tcdm64_to_dual_tcdm32_blocking.sv index e2751d05..f7293930 100644 --- a/hw/tile/converters/tcdm64_to_dual_tcdm32_blocking.sv +++ b/hw/tile/converters/tcdm64_to_dual_tcdm32_blocking.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -21,11 +21,10 @@ */ module tcdm64_to_dual_tcdm32 #( - parameter bit EnableSpill = 1'b1, // Enable spill register to break timing loops - parameter type tcdm64_req_t = logic, // 64-bit TCDM request type - parameter type tcdm64_rsp_t = logic, // 64-bit TCDM response type - parameter type tcdm32_req_t = logic, // 32-bit TCDM request type - parameter type tcdm32_rsp_t = logic // 32-bit TCDM response type + // 64-bit Snitch types from the RVD branch: the package ones are 32-bit when RVD is off + parameter type tcdm64_req_t, + parameter type tcdm64_rsp_t, + parameter bit EnableSpill = 1'b1 // Enable spill register to break timing loops )( input logic clk_i, input logic rst_ni, @@ -35,12 +34,16 @@ module tcdm64_to_dual_tcdm32 #( output tcdm64_rsp_t tcdm_rsp_o, // TCDM 32-bit side (Two parallel TCDM ports) - output tcdm32_req_t tcdm_req_lo_o, // Lower 32-bit word (bits [31:0]) - input tcdm32_rsp_t tcdm_rsp_lo_i, - output tcdm32_req_t tcdm_req_hi_o, // Upper 32-bit word (bits [63:32]) - input tcdm32_rsp_t tcdm_rsp_hi_i + output magia_tile_pkg::spatz_tcdm32_req_t tcdm_req_lo_o, // Lower 32-bit word (bits [31:0]) + input magia_tile_pkg::spatz_tcdm32_rsp_t tcdm_rsp_lo_i, + output magia_tile_pkg::spatz_tcdm32_req_t tcdm_req_hi_o, // Upper 32-bit word (bits [63:32]) + input magia_tile_pkg::spatz_tcdm32_rsp_t tcdm_rsp_hi_i ); + // 32-bit side, fixed by the package + typedef magia_tile_pkg::spatz_tcdm32_req_t tcdm32_req_t; + typedef magia_tile_pkg::spatz_tcdm32_rsp_t tcdm32_rsp_t; + /*******************************************************************/ /* Spill Register (Breaking Timing Loop) */ /*******************************************************************/ @@ -107,23 +110,21 @@ module tcdm64_to_dual_tcdm32 #( // Decode request type assign strb_is_zero = (tcdm_req_int.q.strb == 8'h00); - assign is_load = !tcdm_req_int.q.write; + assign is_load = ~tcdm_req_int.q.write; - // Determine which banks to access: - // - Normal operation: access banks based on strobe bits - // - Load with strb=0: access BOTH banks (full 64-bit read) - // - Store with strb=0: access NO banks (no-op) - assign access_lo = |tcdm_req_int.q.strb[3:0] || (strb_is_zero && is_load); - assign access_hi = |tcdm_req_int.q.strb[7:4] || (strb_is_zero && is_load); + // The strobe selects the banks; strb = 0 reads both banks on a load and none on a store + assign access_lo = |tcdm_req_int.q.strb[3:0] | (strb_is_zero & is_load); + assign access_hi = |tcdm_req_int.q.strb[7:4] | (strb_is_zero & is_load); + logic access_lo_d, access_hi_d; logic access_lo_q, access_hi_q; - // Response arrives when BOTH accessed banks have responded + // Response arrives when BOTH accessed banks have responded logic rsp_arriving; always_comb begin rsp_arriving = 1'b0; if (access_lo_q && access_hi_q) begin - rsp_arriving = tcdm_rsp_lo_i.p_valid && tcdm_rsp_hi_i.p_valid; + rsp_arriving = tcdm_rsp_lo_i.p_valid & tcdm_rsp_hi_i.p_valid; end else if (access_lo_q) begin rsp_arriving = tcdm_rsp_lo_i.p_valid; end else if (access_hi_q) begin @@ -131,18 +132,27 @@ module tcdm64_to_dual_tcdm32 #( end end - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - access_lo_q <= 1'b0; - access_hi_q <= 1'b0; - end else if (tcdm_req_int.q_valid && tcdm_rsp_int.q_ready) begin + always_comb begin + access_lo_d = access_lo_q; + access_hi_d = access_hi_q; + if (tcdm_req_int.q_valid & tcdm_rsp_int.q_ready) begin // Latch access pattern for new requests - access_lo_q <= access_lo; - access_hi_q <= access_hi; + access_lo_d = access_lo; + access_hi_d = access_hi; end else if (tcdm_rsp_int.p_valid) begin // Reset when response completes without new request + access_lo_d = 1'b0; + access_hi_d = 1'b0; + end + end + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin access_lo_q <= 1'b0; access_hi_q <= 1'b0; + end else begin + access_lo_q <= access_lo_d; + access_hi_q <= access_hi_d; end end @@ -177,10 +187,11 @@ module tcdm64_to_dual_tcdm32 #( tcdm_req_lo_o.q.user = tcdm_req_int.q.user; // Strobe handling: load with strb=0 reads full 32-bit word - if (strb_is_zero && is_load) + if (strb_is_zero && is_load) begin tcdm_req_lo_o.q.strb = 4'hF; - else + end else begin tcdm_req_lo_o.q.strb = tcdm_req_int.q.strb[3:0]; + end end end @@ -203,10 +214,11 @@ module tcdm64_to_dual_tcdm32 #( tcdm_req_hi_o.q.user = tcdm_req_int.q.user; // Strobe handling: load with strb=0 reads full 32-bit word - if (strb_is_zero && is_load) + if (strb_is_zero && is_load) begin tcdm_req_hi_o.q.strb = 4'hF; - else + end else begin tcdm_req_hi_o.q.strb = tcdm_req_int.q.strb[7:4]; + end end end @@ -218,11 +230,11 @@ module tcdm64_to_dual_tcdm32 #( always_comb begin tcdm_rsp_int.q_ready = 1'b0; //Block if there's a pending response to ensure in-order completion - if(access_lo_q || access_hi_q) begin + if (access_lo_q || access_hi_q) begin tcdm_rsp_int.q_ready = 1'b0; end else if (access_lo && access_hi) begin // Both banks accessed: need both ready - tcdm_rsp_int.q_ready = tcdm_rsp_lo_i.q_ready && tcdm_rsp_hi_i.q_ready; + tcdm_rsp_int.q_ready = tcdm_rsp_lo_i.q_ready & tcdm_rsp_hi_i.q_ready; end else if (access_lo) begin // Only LO bank accessed tcdm_rsp_int.q_ready = tcdm_rsp_lo_i.q_ready; diff --git a/hw/tile/converters/xif_if2struct.sv b/hw/tile/converters/xif_if2struct.sv index 1d1bd1ec..b4b74099 100644 --- a/hw/tile/converters/xif_if2struct.sv +++ b/hw/tile/converters/xif_if2struct.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. diff --git a/hw/tile/core_data_demux.sv b/hw/tile/core_data_demux.sv new file mode 100644 index 00000000..baf3e4d6 --- /dev/null +++ b/hw/tile/core_data_demux.sv @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2026 ETH Zurich, University of Bologna and Fondazione Chips-IT + * + * Licensed under the Solderpad Hardware License, Version 0.51 + * (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://solderpad.org/licenses/SHL-0.51 + * + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: SHL-0.51 + * + * Authors: Niccolò Giuliani, Fondazione Chips-IT + * Luca Balboni, Fondazione Chips-IT + * + * Core Data Demux: address demux of a core data port with in-order responses and AMO ordering + * + */ + +module core_data_demux + import magia_tile_pkg::*; + import magia_pkg::*; +#( + parameter int unsigned NumSlv = 2, // Number of downstream slave ports + parameter int unsigned NumRules = 1, // Number of address rules + parameter int unsigned DefaultSlv = NumSlv-1, // Unmapped addresses and atomics + parameter logic [NumSlv-1:0] SerialSlv = '0, // Slaves whose accesses block later ones + parameter logic [NumSlv-1:0] BypassSlv = '0, // Slaves that skip the AMO resolver + parameter type req_t = magia_tile_pkg::core_data_req_t, + parameter type rsp_t = magia_tile_pkg::core_data_rsp_t, + localparam int unsigned SelW = magia_tile_pkg::gen_idx_width(NumSlv) +)( + input logic clk_i, + input logic rst_ni, + input logic clk_en_i, // Core clock enable: nothing is issued or answered while low + + input req_t core_data_req_i, + input logic core_data_atomic_i, // Travels alone to DefaultSlv, home of the AMO resolver + output rsp_t core_data_rsp_o, + + input magia_tile_pkg::obi_xbar_rule_t [NumRules-1:0] addr_map_i, + + output req_t [NumSlv-1:0] slv_data_req_o, + input rsp_t [NumSlv-1:0] slv_data_rsp_i +); + + // The cores keep at most 2 requests outstanding and take responses in issue order + localparam int unsigned MaxTrans = 2; + + logic [SelW-1:0] addr_slv; + logic [SelW-1:0] destination; + logic redirect; + logic serial; + + logic [SelW-1:0] order_d [MaxTrans]; // Destinations of the outstanding requests, oldest first + logic [SelW-1:0] order_q [MaxTrans]; + logic [1:0] cnt_d, cnt_q; // Outstanding requests + logic serial_d, serial_q; // The newest outstanding request is serializing + logic amo_shadow_d, amo_shadow_q; // An AMO write-back may still be pending + + rsp_t [NumSlv-1:0] rsp; + logic [NumSlv-1:0] rsp_empty; + logic [NumSlv-1:0] rsp_pop; + logic [SelW-1:0] head; + logic serial_pending; + logic drained; + logic can_issue; + logic push, pop; + + // --------------------------------------------------------------------------- + // Address decode + // --------------------------------------------------------------------------- + + addr_decode #( + .NoIndices ( NumSlv ), + .NoRules ( NumRules ), + .addr_t ( logic [magia_pkg::ADDR_W-1:0] ), + .rule_t ( magia_tile_pkg::obi_xbar_rule_t ) + ) i_addr_decode ( + .addr_i ( core_data_req_i.addr ), + .addr_map_i ( addr_map_i ), + .idx_o ( addr_slv ), + .dec_valid_o ( ), + .dec_error_o ( ), + .en_default_idx_i ( 1'b1 ), + .default_idx_i ( SelW'(DefaultSlv) ) + ); + + // The resolver answers an AMO before its write-back: the next bypassing access queues behind it + assign redirect = amo_shadow_q & BypassSlv[addr_slv]; + assign destination = (core_data_atomic_i | redirect) ? SelW'(DefaultSlv) : addr_slv; + // Atomics and redirected accesses serialize: a later access on another path could overtake them + assign serial = core_data_atomic_i | redirect | SerialSlv[destination]; + + // --------------------------------------------------------------------------- + // Request issue and in-order responses + // --------------------------------------------------------------------------- + + // Responses wait for their turn here, also while the core clock is off: up to MaxTrans per slave + for (genvar s = 0; s < NumSlv; s++) begin : gen_rsp_fifo + assign rsp_pop[s] = pop & (head == SelW'(s)); + + fifo_v3 #( + .FALL_THROUGH ( 1'b1 ), + .DEPTH ( MaxTrans ), + .dtype ( rsp_t ) + ) i_rsp_fifo ( + .clk_i, + .rst_ni, + .flush_i ( 1'b0 ), + .testmode_i ( 1'b0 ), + .full_o ( ), + .empty_o ( rsp_empty[s] ), + .usage_o ( ), + .data_i ( slv_data_rsp_i[s] ), + .push_i ( slv_data_rsp_i[s].rvalid ), + .data_o ( rsp[s] ), + .pop_i ( rsp_pop[s] ) + ); + end + + assign head = order_q[0]; + assign pop = clk_en_i & (cnt_q != '0) & ~rsp_empty[head]; + assign serial_pending = serial_q & ~(pop & (cnt_q == 2'd1)); + assign drained = (cnt_q == '0) | ((cnt_q == 2'd1) & pop); + // An atomic also waits for earlier accesses: a granted TCDM write may not have reached its bank + assign can_issue = clk_en_i & ((cnt_q != 2'(MaxTrans)) | pop) & ~serial_pending & + (~core_data_atomic_i | drained); + assign push = can_issue & core_data_req_i.req & slv_data_rsp_i[destination].gnt; + + always_comb begin : _REQ_FWD_ + for (int unsigned s = 0; s < NumSlv; s++) begin + slv_data_req_o[s] = core_data_req_i; + slv_data_req_o[s].req = core_data_req_i.req & (destination == SelW'(s)) & can_issue; + end + end + + always_comb begin : _RSP_FWD_ + core_data_rsp_o = rsp[head]; + core_data_rsp_o.rvalid = pop; + core_data_rsp_o.gnt = ~clk_en_i | (can_issue & slv_data_rsp_i[destination].gnt); + end + + // --------------------------------------------------------------------------- + // Next state and flops + // --------------------------------------------------------------------------- + + always_comb begin : _ORDER_ + order_d = order_q; + cnt_d = cnt_q; + if (pop) begin + order_d[0] = order_q[1]; + cnt_d = cnt_q - 2'd1; + end + if (push) begin + order_d[cnt_d[0]] = destination; + cnt_d = cnt_d + 2'd1; + end + end + + always_comb begin : _SERIAL_ + serial_d = serial_q; + if (push) begin + serial_d = serial; + end else if (pop & (cnt_q == 2'd1)) begin + serial_d = 1'b0; + end + end + + always_comb begin : _AMO_SHADOW_ + amo_shadow_d = amo_shadow_q; + if (push & core_data_atomic_i) begin + amo_shadow_d = 1'b1; + end else if (push & redirect) begin + amo_shadow_d = 1'b0; + end + end + + always_ff @(posedge clk_i or negedge rst_ni) begin : _STATE_ + if (!rst_ni) begin + order_q <= '{default: '0}; + cnt_q <= '0; + serial_q <= 1'b0; + amo_shadow_q <= 1'b0; + end else begin + order_q <= order_d; + cnt_q <= cnt_d; + serial_q <= serial_d; + amo_shadow_q <= amo_shadow_d; + end + end + +`ifndef SYNTHESIS + for (genvar s = 0; s < NumSlv; s++) begin : gen_assert + assert property (@(posedge clk_i) disable iff (!rst_ni) + !(slv_data_rsp_i[s].rvalid & (cnt_q == '0))) + else $fatal(1, "core_data_demux: response from slave %0d without an outstanding request", s); + end +`endif + +endmodule diff --git a/hw/tile/core_data_demux_eu_direct.sv b/hw/tile/core_data_demux_eu_direct.sv deleted file mode 100644 index d598e817..00000000 --- a/hw/tile/core_data_demux_eu_direct.sv +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (C) 2026 ETH Zurich, University of Bologna and Fondazione Chips-IT - * - * Licensed under the Solderpad Hardware License, Version 0.51 - * (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * SPDX-License-Identifier: SHL-0.51 - * - * Authors: Luca Balboni - * Victor Isachi - * - * Core Data Demux EU Direct Link - * - * This module implements a demux that splits core data requests between: - * - Regular crossbar for general memory/peripheral access - * - EU direct link for low-latency Event Unit access (WFE control) - * - * The demux decision is based on address range: - * - EVENT_UNIT_ADDR_START to EVENT_UNIT_ADDR_END -> EU direct link - * - All other addresses -> Regular crossbar - * - */ - -module core_data_demux_eu_direct - import magia_tile_pkg::*; - import magia_pkg::*; -#( - parameter logic [magia_pkg::ADDR_W-1:0] EVENT_UNIT_ADDR_START = magia_tile_pkg::EVENT_UNIT_ADDR_START, - parameter logic [magia_pkg::ADDR_W-1:0] EVENT_UNIT_ADDR_END = magia_tile_pkg::EVENT_UNIT_ADDR_END -)( - input logic clk_i, - input logic rst_ni, - input logic core_clock_en_i, - - // Core data interface (input from cv32e40p) - input magia_tile_pkg::core_data_req_t core_data_req_i, - output magia_tile_pkg::core_data_rsp_t core_data_rsp_o, - - // Regular crossbar interface (for general memory/peripheral access) - output magia_tile_pkg::core_data_req_t xbar_data_req_o, - input magia_tile_pkg::core_data_rsp_t xbar_data_rsp_i, - - // EU direct link interface (abstract types) - output magia_tile_pkg::eu_direct_req_t eu_direct_req_o, - input magia_tile_pkg::eu_direct_rsp_t eu_direct_rsp_i -); - - // --------------------------------------------------------------------------- - // Address decode (combinatorial) - // --------------------------------------------------------------------------- - - logic use_eu_direct; - - assign use_eu_direct = core_data_req_i.req && - (core_data_req_i.addr >= EVENT_UNIT_ADDR_START) && - (core_data_req_i.addr < EVENT_UNIT_ADDR_END); - - // --------------------------------------------------------------------------- - // In-order response tracking — 2-entry FIFO of issued destinations - // - // Same approach as data_periph_demux in the PULP cluster. The FIFO tracks - // which path (EU or XBAR) each outstanding request was sent to and therefore - // which path must supply the *next* response to forward to the core. - // - // arriving_order[0] = most-recently pushed (newest) - // arriving_order[1] = oldest (= head, must respond first) - // - // CV32E40P LSU has DEPTH=2 outstanding, so a 2-entry FIFO is sufficient. - // A single registered bit (as used previously) is NOT enough: if two - // requests go to different paths the second grant overwrites the first - // destination, causing the response of the first to be routed to the wrong - // instruction or silently dropped. - // --------------------------------------------------------------------------- - - typedef enum logic { XBAR_D = 1'b0, EU_D = 1'b1 } dest_e; - - dest_e destination; // combinatorial: destination of the current request - dest_e arriving_order [0:1]; // FIFO: [0]=newest, [1]=oldest - logic [1:0] num_outstanding; - dest_e head; // combinatorial: oldest pending destination - - assign destination = use_eu_direct ? EU_D : XBAR_D; - - always_comb begin : _HEAD_MUX_ - case (num_outstanding) - 2'd2: head = arriving_order[1]; // oldest - 2'd1: head = arriving_order[0]; - default: head = XBAR_D; // idle, value unused - endcase - end - - // --------------------------------------------------------------------------- - // Out-of-order response capture - // - // If a path's rvalid arrives while it is NOT at the head of the FIFO the - // response would be lost. A 1-entry capture register per path holds it - // until that path reaches the head. With DEPTH=2 at most one response can - // be queued behind the other at any time. - // --------------------------------------------------------------------------- - - logic eu_cap_rvalid_q; - logic [31:0] eu_cap_rdata_q; - logic eu_cap_err_q; - - logic xbar_cap_rvalid_q; - logic [31:0] xbar_cap_rdata_q; - logic xbar_cap_err_q; - - // "Effective" rvalid/rdata: direct arrival OR previously captured - logic eu_rvalid_eff, xbar_rvalid_eff; - logic [31:0] eu_rdata_eff, xbar_rdata_eff; - logic eu_err_eff, xbar_err_eff; - - // Direct arrival takes priority so the capture register is consumed first - // only when nothing arrives directly that cycle. - assign eu_rvalid_eff = eu_direct_rsp_i.rvalid | eu_cap_rvalid_q; - assign eu_rdata_eff = eu_direct_rsp_i.rvalid ? eu_direct_rsp_i.rdata : eu_cap_rdata_q; - assign eu_err_eff = eu_direct_rsp_i.rvalid ? eu_direct_rsp_i.err : eu_cap_err_q; - - assign xbar_rvalid_eff = xbar_data_rsp_i.rvalid | xbar_cap_rvalid_q; - assign xbar_rdata_eff = xbar_data_rsp_i.rvalid ? xbar_data_rsp_i.rdata : xbar_cap_rdata_q; - assign xbar_err_eff = xbar_data_rsp_i.rvalid ? xbar_data_rsp_i.err : xbar_cap_err_q; - - // Response forwarded to the core this cycle - logic resp_valid_to_core; - always_comb begin : _RESP_VALID_MUX_ - if (num_outstanding == '0) - resp_valid_to_core = 1'b0; - else if (head == EU_D) - resp_valid_to_core = eu_rvalid_eff && core_clock_en_i; - else - resp_valid_to_core = xbar_rvalid_eff && core_clock_en_i; - end - - // Capture/clear FFs - always_ff @(posedge clk_i, negedge rst_ni) begin : _CAPTURE_FFS_ - if (!rst_ni) begin - eu_cap_rvalid_q <= 1'b0; - eu_cap_rdata_q <= '0; - eu_cap_err_q <= 1'b0; - xbar_cap_rvalid_q <= 1'b0; - xbar_cap_rdata_q <= '0; - xbar_cap_err_q <= 1'b0; - end else begin - // EU: capture when rvalid arrives and EU is not at head; - // clear when EU response is forwarded to core. - if (eu_direct_rsp_i.rvalid && (num_outstanding > 0) && - ((head != EU_D) || !core_clock_en_i)) begin - eu_cap_rvalid_q <= 1'b1; - eu_cap_rdata_q <= eu_direct_rsp_i.rdata; - eu_cap_err_q <= eu_direct_rsp_i.err; - end else if ((head == EU_D) && resp_valid_to_core) begin - eu_cap_rvalid_q <= 1'b0; - end - - // XBAR: same logic - if (xbar_data_rsp_i.rvalid && (num_outstanding > 0) && - ((head != XBAR_D) || !core_clock_en_i)) begin - xbar_cap_rvalid_q <= 1'b1; - xbar_cap_rdata_q <= xbar_data_rsp_i.rdata; - xbar_cap_err_q <= xbar_data_rsp_i.err; - end else if ((head == XBAR_D) && resp_valid_to_core) begin - xbar_cap_rvalid_q <= 1'b0; - end - end - end - - // --------------------------------------------------------------------------- - // FIFO push/pop - // --------------------------------------------------------------------------- - - logic request_granted; - logic fifo_push, fifo_pop; - - assign request_granted = core_clock_en_i && core_data_req_i.req && core_data_rsp_o.gnt; - assign fifo_push = request_granted; - assign fifo_pop = resp_valid_to_core && (num_outstanding > 0); - - always_ff @(posedge clk_i, negedge rst_ni) begin : _FIFO_ - if (!rst_ni) begin - arriving_order[0] <= XBAR_D; - arriving_order[1] <= XBAR_D; - num_outstanding <= 2'b0; - end else begin - if (fifo_push && fifo_pop) begin - // Back-to-back: pop the old head, push the new destination - arriving_order[0] <= destination; - if (num_outstanding == 2) - arriving_order[1] <= arriving_order[0]; // shift oldest away - // num_outstanding unchanged - end else if (fifo_push) begin - arriving_order[1] <= arriving_order[0]; - arriving_order[0] <= destination; - num_outstanding <= num_outstanding + 1; - end else if (fifo_pop) begin - arriving_order[1] <= arriving_order[0]; - num_outstanding <= num_outstanding - 1; - end - end - end - - // --------------------------------------------------------------------------- - // Request forwarding - // Gate with num_outstanding < 2 to prevent FIFO overflow (CV32E40P DEPTH=2). - // Back-to-back allowed when a response is simultaneously being consumed. - // --------------------------------------------------------------------------- - - logic can_issue; - assign can_issue = (num_outstanding < 2) || fifo_pop; - - // To regular crossbar - assign xbar_data_req_o.req = core_clock_en_i && core_data_req_i.req && - !use_eu_direct && can_issue; - assign xbar_data_req_o.addr = core_data_req_i.addr; - assign xbar_data_req_o.be = core_data_req_i.be; - assign xbar_data_req_o.wdata = core_data_req_i.wdata; - assign xbar_data_req_o.we = core_data_req_i.we; -`ifdef CV32E40X - assign xbar_data_req_o.atop = core_data_req_i.atop; - assign xbar_data_req_o.memtype = core_data_req_i.memtype; - assign xbar_data_req_o.prot = core_data_req_i.prot; - assign xbar_data_req_o.dbg = core_data_req_i.dbg; -`endif - - // To EU direct link - assign eu_direct_req_o.req = core_clock_en_i && core_data_req_i.req && - use_eu_direct && can_issue; - assign eu_direct_req_o.addr = core_data_req_i.addr - EVENT_UNIT_ADDR_START; - assign eu_direct_req_o.wen = ~core_data_req_i.we; - assign eu_direct_req_o.wdata = core_data_req_i.wdata; - assign eu_direct_req_o.be = core_data_req_i.be; - - // --------------------------------------------------------------------------- - // Response mux to core — select from head path (direct or captured) - // --------------------------------------------------------------------------- - - always_comb begin : _HANDLE_RESP_ - core_data_rsp_o.rvalid = resp_valid_to_core; - if (head == EU_D) begin - core_data_rsp_o.rdata = eu_rdata_eff; - core_data_rsp_o.err = eu_err_eff; -`ifdef CV32E40X - core_data_rsp_o.exokay = '0; -`endif - end else begin - core_data_rsp_o.rdata = xbar_rdata_eff; - core_data_rsp_o.err = xbar_err_eff; -`ifdef CV32E40X - core_data_rsp_o.exokay = xbar_data_rsp_i.exokay; -`endif - end - end - - assign core_data_rsp_o.gnt = !core_clock_en_i ? 1'b1 : - (can_issue && - (use_eu_direct ? eu_direct_rsp_i.gnt - : xbar_data_rsp_i.gnt)); - -endmodule diff --git a/hw/tile/ctrl_demux.sv b/hw/tile/ctrl_demux.sv new file mode 100644 index 00000000..594d7dd4 --- /dev/null +++ b/hw/tile/ctrl_demux.sv @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2026 ETH Zurich, University of Bologna and Fondazione Chips-IT + * + * Licensed under the Solderpad Hardware License, Version 0.51 + * (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://solderpad.org/licenses/SHL-0.51 + * + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: SHL-0.51 + * + * Authors: Luca Balboni, Fondazione Chips-IT + * + * MAGIA control demux: demuxes the single control port of the OBI crossbar towards + * the control registers of each enabled unit +*/ + +module ctrl_demux + import magia_tile_pkg::*; +#( + parameter magia_tile_pkg::magia_tile_cfg_t TileCfg = magia_tile_pkg::MagiaTileDefaultCfg, + localparam magia_tile_pkg::ctrl_map_t CtrlMap = magia_tile_pkg::gen_ctrl_map(TileCfg) +)( + input logic clk_i, + input logic rst_ni, + + input magia_tile_pkg::core_obi_data_req_t obi_req_i, + output magia_tile_pkg::core_obi_data_rsp_t obi_rsp_o, + + // One port per enabled unit, indexed by CtrlMap + output magia_tile_pkg::core_obi_data_req_t[CtrlMap.num_units-1:0] unit_req_o, + input magia_tile_pkg::core_obi_data_rsp_t[CtrlMap.num_units-1:0] unit_rsp_i +); + + localparam magia_tile_pkg::ctrl_rules_t CtrlRules = magia_tile_pkg::gen_ctrl_rules(TileCfg); + localparam int unsigned ErrIdx = CtrlMap.num_units; // Default port, after the units + localparam int unsigned SelW = magia_tile_pkg::gen_idx_width(CtrlMap.num_units + 1); + + magia_tile_pkg::obi_xbar_rule_t[CtrlMap.num_units-1:0] ctrl_rule; + magia_tile_pkg::core_obi_data_req_t[CtrlMap.num_units:0] demux_req; + // Each element comes from a different unit: split it, or Verilator sees a false combinational loop + magia_tile_pkg::core_obi_data_rsp_t[CtrlMap.num_units:0] demux_rsp /* verilator split_var */; + + for (genvar i = 0; i < CtrlMap.num_units; i++) begin: gen_ctrl_rule + assign ctrl_rule[i] = CtrlRules[i]; + end + + obi_demux_addr #( + .SbrPortObiCfg ( magia_tile_pkg::obi_amo_cfg ), + .NumMgrPorts ( CtrlMap.num_units + 1 ), + .NumMaxTrans ( magia_tile_pkg::N_MAX_TRAN ), + .NumAddrRules ( CtrlMap.num_units ) + ) i_ctrl_demux ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .sbr_ports_req_i ( obi_req_i ), + .sbr_ports_rsp_o ( obi_rsp_o ), + .mgr_ports_req_o ( demux_req ), + .mgr_ports_rsp_i ( demux_rsp ), + .addr_map_i ( ctrl_rule ), + .en_default_idx_i ( 1'b1 ), + .default_idx_i ( SelW'(ErrIdx) ) + ); + + assign unit_req_o = demux_req[CtrlMap.num_units-1:0]; + assign demux_rsp[CtrlMap.num_units-1:0] = unit_rsp_i; + + // Disabled units and holes in the control window get an error response + obi_err_sbr #( + .ObiCfg ( magia_tile_pkg::obi_amo_cfg ), + .obi_req_t ( magia_tile_pkg::core_obi_data_req_t ), + .obi_rsp_t ( magia_tile_pkg::core_obi_data_rsp_t ) + ) i_obi_err_sbr ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .testmode_i ( 1'b0 ), + .obi_req_i ( demux_req[ErrIdx] ), + .obi_rsp_o ( demux_rsp[ErrIdx] ) + ); + +`ifndef SYNTHESIS + assert property (@(posedge clk_i) disable iff (!rst_ni) !demux_req[ErrIdx].req) + else $fatal(1, "ctrl_demux: OBI access to unmapped control address 0x%08x (unit disabled?)", + demux_req[ErrIdx].a.addr); +`endif + +endmodule: ctrl_demux diff --git a/hw/tile/eu_direct_cut.sv b/hw/tile/eu_direct_cut.sv index 5635de6d..46a2f01d 100644 --- a/hw/tile/eu_direct_cut.sv +++ b/hw/tile/eu_direct_cut.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -22,8 +22,6 @@ module eu_direct_cut import magia_tile_pkg::*; #( - parameter type eu_direct_req_t = logic, - parameter type eu_direct_rsp_t = logic, parameter bit Bypass = 1'b0, parameter bit BypassReq = Bypass, parameter bit BypassRsp = Bypass, @@ -58,7 +56,7 @@ module eu_direct_cut // ============================ // Per-core logic // ============================ - for (genvar i = 0; i < NB_CORES; i++) begin : GEN_EU_CUT + for (genvar i = 0; i < NB_CORES; i++) begin : gen_eu_cut // ---------------------------- // Request path diff --git a/hw/tile/idma_axi_obi_transfer_ch.sv b/hw/tile/idma_axi_obi_transfer_ch.sv index ba9115be..fedb388a 100644 --- a/hw/tile/idma_axi_obi_transfer_ch.sv +++ b/hw/tile/idma_axi_obi_transfer_ch.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -25,13 +25,7 @@ module idma_axi_obi_transfer_ch import idma_pkg::*; #( parameter magia_tile_pkg::idma_transfer_ch_e CHANNEL_T = magia_tile_pkg::AXI2OBI, - parameter idma_pkg::error_cap_e ERROR_CAP = idma_pkg::NO_ERROR_HANDLING, - parameter type idma_fe_reg_req_t = magia_tile_pkg::idma_fe_reg_req_t, - parameter type idma_fe_reg_rsp_t = magia_tile_pkg::idma_fe_reg_rsp_t, - parameter type axi_req_t = magia_tile_pkg::idma_axi_req_t, - parameter type axi_rsp_t = magia_tile_pkg::idma_axi_rsp_t, - parameter type obi_req_t = magia_tile_pkg::idma_obi_req_t, - parameter type obi_rsp_t = magia_tile_pkg::idma_obi_rsp_t + parameter idma_pkg::error_cap_e ERROR_CAP = idma_pkg::NO_ERROR_HANDLING )( input logic clk_i, input logic rst_ni, @@ -41,11 +35,11 @@ module idma_axi_obi_transfer_ch input idma_fe_reg_req_t cfg_req_i, output idma_fe_reg_rsp_t cfg_rsp_o, - output axi_req_t axi_req_o, - input axi_rsp_t axi_rsp_i, + output idma_axi_req_t axi_req_o, + input idma_axi_rsp_t axi_rsp_i, - output obi_req_t obi_req_o, - input obi_rsp_t obi_rsp_i, + output idma_obi_req_t obi_req_o, + input idma_obi_rsp_t obi_rsp_i, // IRQ-related outputs output logic transfer_busy_o, @@ -215,7 +209,7 @@ module idma_axi_obi_transfer_ch /** Back-end Beginning **/ /*******************************************************/ - generate if (CHANNEL_T == magia_tile_pkg::AXI2OBI) begin: gen_axi2obi_ch + if (CHANNEL_T == magia_tile_pkg::AXI2OBI) begin: gen_axi2obi_ch idma_backend_r_axi_w_obi #( .DataWidth ( magia_tile_pkg::iDMA_DataWidth ), .AddrWidth ( magia_tile_pkg::iDMA_AddrWidth ), @@ -323,7 +317,7 @@ module idma_axi_obi_transfer_ch .busy_o ( busy ) ); - end endgenerate + end /*******************************************************/ /** Back-end End **/ diff --git a/hw/tile/idma_ctrl_mm.sv b/hw/tile/idma_ctrl_mm.sv index 507c169c..ae436680 100644 --- a/hw/tile/idma_ctrl_mm.sv +++ b/hw/tile/idma_ctrl_mm.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -29,46 +29,38 @@ module idma_ctrl_mm import magia_tile_pkg::*; import idma_pkg::*; #( - parameter int unsigned ERROR_CAP = 3, - parameter type obi_req_t = magia_tile_pkg::core_obi_data_req_t, - parameter type obi_rsp_t = magia_tile_pkg::core_obi_data_rsp_t, - parameter type idma_fe_reg_req_t = magia_tile_pkg::idma_fe_reg_req_t, - parameter type idma_fe_reg_rsp_t = magia_tile_pkg::idma_fe_reg_rsp_t, - parameter type axi_req_t = magia_tile_pkg::idma_axi_req_t, - parameter type axi_rsp_t = magia_tile_pkg::idma_axi_rsp_t, - parameter type idma_obi_req_t = magia_tile_pkg::idma_obi_req_t, - parameter type idma_obi_rsp_t = magia_tile_pkg::idma_obi_rsp_t + parameter idma_pkg::error_cap_e ERROR_CAP = idma_pkg::NO_ERROR_HANDLING )( - input logic clk_i, - input logic rst_ni, - input logic test_en_i, - input logic clear_i, + input logic clk_i, + input logic rst_ni, + input logic test_en_i, + input logic clear_i, // OBI Slave Interface (CPU memory-mapped access) - input obi_req_t obi_req_i, - output obi_rsp_t obi_rsp_o, + input core_obi_data_req_t obi_req_i, + output core_obi_data_rsp_t obi_rsp_o, // AXI Master Interfaces (to L2 memory) - output axi_req_t axi_read_req_o, // AXI2OBI: L2 read - input axi_rsp_t axi_read_rsp_i, - output axi_req_t axi_write_req_o, // OBI2AXI: L2 write - input axi_rsp_t axi_write_rsp_i, + output idma_axi_req_t axi_read_req_o, // AXI2OBI: L2 read + input idma_axi_rsp_t axi_read_rsp_i, + output idma_axi_req_t axi_write_req_o, // OBI2AXI: L2 write + input idma_axi_rsp_t axi_write_rsp_i, // OBI Master Interfaces (to L1 memory) - output idma_obi_req_t obi_read_req_o, // OBI2AXI: L1 read - input idma_obi_rsp_t obi_read_rsp_i, - output idma_obi_req_t obi_write_req_o, // AXI2OBI: L1 write - input idma_obi_rsp_t obi_write_rsp_i, + output idma_obi_req_t obi_read_req_o, // OBI2AXI: L1 read + input idma_obi_rsp_t obi_read_rsp_i, + output idma_obi_req_t obi_write_req_o, // AXI2OBI: L1 write + input idma_obi_rsp_t obi_write_rsp_i, // Serialized IRQ outputs - output logic irq_a2o_busy_o, - output logic irq_a2o_start_o, - output logic irq_a2o_done_o, - output logic irq_a2o_error_o, - output logic irq_o2a_busy_o, - output logic irq_o2a_start_o, - output logic irq_o2a_done_o, - output logic irq_o2a_error_o + output logic irq_a2o_busy_o, + output logic irq_a2o_start_o, + output logic irq_a2o_done_o, + output logic irq_a2o_error_o, + output logic irq_o2a_busy_o, + output logic irq_o2a_start_o, + output logic irq_o2a_done_o, + output logic irq_o2a_error_o ); /*******************************************************/ @@ -98,13 +90,7 @@ module idma_ctrl_mm // AXI2OBI Transfer Channel (L2 to L1) idma_axi_obi_transfer_ch #( .CHANNEL_T ( magia_tile_pkg::AXI2OBI ), - .ERROR_CAP ( ERROR_CAP ), - .idma_fe_reg_req_t ( magia_tile_pkg::idma_fe_reg_req_t ), - .idma_fe_reg_rsp_t ( magia_tile_pkg::idma_fe_reg_rsp_t ), - .axi_req_t ( magia_tile_pkg::idma_axi_req_t ), - .axi_rsp_t ( magia_tile_pkg::idma_axi_rsp_t ), - .obi_req_t ( magia_tile_pkg::idma_obi_req_t ), - .obi_rsp_t ( magia_tile_pkg::idma_obi_rsp_t ) + .ERROR_CAP ( ERROR_CAP ) ) i_l2_to_l1_ch ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -128,13 +114,7 @@ module idma_ctrl_mm // OBI2AXI Transfer Channel (L1 to L2) idma_axi_obi_transfer_ch #( .CHANNEL_T ( magia_tile_pkg::OBI2AXI ), - .ERROR_CAP ( ERROR_CAP ), - .idma_fe_reg_req_t ( magia_tile_pkg::idma_fe_reg_req_t ), - .idma_fe_reg_rsp_t ( magia_tile_pkg::idma_fe_reg_rsp_t ), - .axi_req_t ( magia_tile_pkg::idma_axi_req_t ), - .axi_rsp_t ( magia_tile_pkg::idma_axi_rsp_t ), - .obi_req_t ( magia_tile_pkg::idma_obi_req_t ), - .obi_rsp_t ( magia_tile_pkg::idma_obi_rsp_t ) + .ERROR_CAP ( ERROR_CAP ) ) i_l1_to_l2_ch ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -177,12 +157,20 @@ module idma_ctrl_mm // send more requests than we can absorb in the fifo assign obi_read_req_o.rready = 1'b1; + // OBI integrity parity is the inverted copy of each handshake signal + assign obi_read_req_o.reqpar = ~obi_read_req_o.req; + assign obi_read_req_o.rreadypar = ~obi_read_req_o.rready; + assign obi_read_rsp_converter.gntpar = ~obi_read_rsp_converter.gnt; + assign obi_read_rsp_converter.rvalidpar = ~obi_read_rsp_converter.rvalid; + /*******************************************************/ /** Memory-Mapped Bridge with IRQ Serialization **/ /*******************************************************/ idma_obi_ctrl_decoder i_idma_obi_ctrl_decoder ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), .obi_req_i ( obi_req_i ), .obi_rsp_o ( obi_rsp_o ), diff --git a/hw/tile/idma_obi_ctrl_decoder.sv b/hw/tile/idma_obi_ctrl_decoder.sv index d6ecb0c8..c66f249e 100644 --- a/hw/tile/idma_obi_ctrl_decoder.sv +++ b/hw/tile/idma_obi_ctrl_decoder.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this fendmodule : idma_obi_ctrl_decoderle except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -24,22 +24,20 @@ module idma_obi_ctrl_decoder import magia_tile_pkg::*; import magia_pkg::*; - #( - parameter type obi_req_t = magia_tile_pkg::core_obi_data_req_t, - parameter type obi_rsp_t = magia_tile_pkg::core_obi_data_rsp_t, - parameter type idma_fe_reg_req_t = magia_tile_pkg::idma_fe_reg_req_t, - parameter type idma_fe_reg_rsp_t = magia_tile_pkg::idma_fe_reg_rsp_t -)( +( + input logic clk_i, + input logic rst_ni, + // OBI Slave Interface (CPU access) - input obi_req_t obi_req_i, - output obi_rsp_t obi_rsp_o, + input core_obi_data_req_t obi_req_i, + output core_obi_data_rsp_t obi_rsp_o, // iDMA Register Frontend Interface - output idma_fe_reg_req_t idma_axi2obi_req_o, - input idma_fe_reg_rsp_t idma_axi2obi_rsp_i, + output idma_fe_reg_req_t idma_axi2obi_req_o, + input idma_fe_reg_rsp_t idma_axi2obi_rsp_i, - output idma_fe_reg_req_t idma_obi2axi_req_o, - input idma_fe_reg_rsp_t idma_obi2axi_rsp_i + output idma_fe_reg_req_t idma_obi2axi_req_o, + input idma_fe_reg_rsp_t idma_obi2axi_rsp_i ); /*******************************************************/ @@ -52,7 +50,7 @@ module idma_obi_ctrl_decoder localparam logic [magia_pkg::ADDR_W-1:0] IDMA_END_ADDR = magia_tile_pkg::IDMA_CTRL_ADDR_END; localparam int unsigned ADDR_WIDTH = 32; - localparam int unsigned DIRECTION_OFFSET = 12'h200; // +0x200 for direction change + localparam int unsigned DIRECTION_OFFSET = 32'h200; // +0x200 for direction change // Register offset definitions based on official reg32_3d spec localparam logic [11:0] IDMA_CONFIG_OFFSET = 12'h0; @@ -88,6 +86,11 @@ module idma_obi_ctrl_decoder idma_fe_reg_req_t selected_idma_req; idma_fe_reg_rsp_t selected_idma_rsp; + logic obi_gnt; + logic rvalid_q; + logic [DATA_W-1:0] rdata_q; + logic err_q; + /*******************************************************/ /** Internal Signal Definitions End **/ /*******************************************************/ @@ -95,7 +98,7 @@ module idma_obi_ctrl_decoder /*******************************************************/ // Address range validation - check if address is within iDMA control space - assign is_address_in_range = (obi_req_i.a.addr >= IDMA_BASE_ADDR) && + assign is_address_in_range = (obi_req_i.a.addr >= IDMA_BASE_ADDR) & (obi_req_i.a.addr <= IDMA_END_ADDR); // Address decoding - check if address is in OBI2AXI range (+0x200 offset) @@ -105,25 +108,25 @@ module idma_obi_ctrl_decoder (obi_req_i.a.addr[11:0] - IDMA_BASE_ADDR[11:0]); // Validate access: must be in address range AND at known register offset - assign is_valid_access = is_address_in_range && ( - (reg_offset == IDMA_CONFIG_OFFSET) || + assign is_valid_access = is_address_in_range & ( + (reg_offset == IDMA_CONFIG_OFFSET) | // Status registers (multireg 0x4-0x40, step 4) - ((reg_offset >= 12'h4) && (reg_offset <= 12'h40) && ((reg_offset & 12'h3) == 12'h0)) || + ((reg_offset >= 12'h4) & (reg_offset <= 12'h40) & ((reg_offset & 12'h3) == 12'h0)) | // Next ID registers (multireg 0x44-0x80, step 4) - ((reg_offset >= 12'h44) && (reg_offset <= 12'h80) && ((reg_offset & 12'h3) == 12'h0)) || + ((reg_offset >= 12'h44) & (reg_offset <= 12'h80) & ((reg_offset & 12'h3) == 12'h0)) | // Done ID registers (multireg 0x84-0xc0, step 4) - ((reg_offset >= 12'h84) && (reg_offset <= 12'hc0) && ((reg_offset & 12'h3) == 12'h0)) || + ((reg_offset >= 12'h84) & (reg_offset <= 12'hc0) & ((reg_offset & 12'h3) == 12'h0)) | // Configuration registers at specific skipto addresses - (reg_offset == IDMA_DST_ADDR_LOW_OFFSET) || - (reg_offset == IDMA_SRC_ADDR_LOW_OFFSET) || - (reg_offset == IDMA_LENGTH_LOW_OFFSET) || - (reg_offset == IDMA_DST_STRIDE_2_LOW_OFFSET) || - (reg_offset == IDMA_SRC_STRIDE_2_LOW_OFFSET) || - (reg_offset == IDMA_REPS_2_LOW_OFFSET) || - (reg_offset == IDMA_DST_STRIDE_3_LOW_OFFSET) || - (reg_offset == IDMA_SRC_STRIDE_3_LOW_OFFSET) || - (reg_offset == IDMA_REPS_3_LOW_OFFSET) || - (reg_offset == IDMA_MULTICAST_MASK_OFFSET) || + (reg_offset == IDMA_DST_ADDR_LOW_OFFSET) | + (reg_offset == IDMA_SRC_ADDR_LOW_OFFSET) | + (reg_offset == IDMA_LENGTH_LOW_OFFSET) | + (reg_offset == IDMA_DST_STRIDE_2_LOW_OFFSET) | + (reg_offset == IDMA_SRC_STRIDE_2_LOW_OFFSET) | + (reg_offset == IDMA_REPS_2_LOW_OFFSET) | + (reg_offset == IDMA_DST_STRIDE_3_LOW_OFFSET) | + (reg_offset == IDMA_SRC_STRIDE_3_LOW_OFFSET) | + (reg_offset == IDMA_REPS_3_LOW_OFFSET) | + (reg_offset == IDMA_MULTICAST_MASK_OFFSET) | (reg_offset == IDMA_COLLECTIVE_SEL_OFFSET) ); @@ -163,22 +166,32 @@ module idma_obi_ctrl_decoder selected_idma_req.write = obi_req_i.a.we; selected_idma_req.wdata = obi_req_i.a.wdata; selected_idma_req.wstrb = obi_req_i.a.be; - selected_idma_req.valid = obi_req_i.req && is_valid_access; + selected_idma_req.valid = obi_req_i.req & is_valid_access; + end + + assign obi_gnt = obi_req_i.req & is_valid_access & selected_idma_rsp.ready; + + always_ff @(posedge clk_i, negedge rst_ni) begin: obi_response + if (~rst_ni) begin + rvalid_q <= 1'b0; + rdata_q <= '0; + err_q <= 1'b0; + end else begin + rvalid_q <= obi_gnt; + if (obi_gnt) begin + rdata_q <= selected_idma_rsp.rdata; + err_q <= selected_idma_rsp.error; + end + end end - // OBI response - purely combinatorial like XIF interface always_comb begin: idma_reg_to_obi - // Grant immediately for valid requests (OBI protocol requirement) - obi_rsp_o.gnt = obi_req_i.req && is_valid_access; - - // Response valid when iDMA is ready to respond (both read and write) - obi_rsp_o.rvalid = selected_idma_rsp.ready && is_valid_access; - - // Read data directly from iDMA response (writes return 0) - obi_rsp_o.r.rdata = selected_idma_rsp.rdata; + obi_rsp_o.gnt = obi_gnt; + obi_rsp_o.rvalid = rvalid_q; + obi_rsp_o.r.rdata = rdata_q; obi_rsp_o.r.r_optional = '0; - obi_rsp_o.r.err = selected_idma_rsp.error || !is_valid_access; - obi_rsp_o.r.rid = '0; + obi_rsp_o.r.err = err_q; + obi_rsp_o.r.rid = '0; end /*******************************************************/ diff --git a/hw/tile/l1_spm.sv b/hw/tile/l1_spm.sv index 95de2e7a..f8411e32 100644 --- a/hw/tile/l1_spm.sv +++ b/hw/tile/l1_spm.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -37,12 +37,12 @@ module l1_spm #( assign rsp_id_d = tcdm_slave[i].id; assign tcdm_slave[i].r_id = rsp_id_q; - always_ff @(posedge clk_i or negedge rst_ni) - begin - if (~rst_ni) + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin rsp_id_q <= '0; - else + end else begin rsp_id_q <= rsp_id_d; + end end tc_sram #( diff --git a/hw/tile/local_interconnect.sv b/hw/tile/local_interconnect.sv index 4f7019d2..68a190ba 100644 --- a/hw/tile/local_interconnect.sv +++ b/hw/tile/local_interconnect.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -159,10 +159,13 @@ module local_interconnect ); end + // The trees' inner nodes re-arbitrate while not granted: internal signals, not protocol ports hci_arbiter_tree #( .NB_REQUESTS ( N_HWPE ), .NB_CHAN ( N_MEM ), - .`HCI_SIZE_PARAM(out) ( `HCI_SIZE_PARAM(hwpe_mem_muxed) ) + .`HCI_SIZE_PARAM(out) ( `HCI_SIZE_PARAM(hwpe_mem_muxed) ), + .WAIVE_RQ3_ASSERT ( 1'b1 ), + .WAIVE_RQ4_ASSERT ( 1'b1 ) ) i_hwpe_wide_port_arbiter_tree ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -197,7 +200,9 @@ module local_interconnect hci_arbiter_tree #( .NB_REQUESTS ( N_DMA ), .NB_CHAN ( N_MEM ), - .`HCI_SIZE_PARAM(out) ( `HCI_SIZE_PARAM(dma_mem_muxed) ) + .`HCI_SIZE_PARAM(out) ( `HCI_SIZE_PARAM(dma_mem_muxed) ), + .WAIVE_RQ3_ASSERT ( 1'b1 ), + .WAIVE_RQ4_ASSERT ( 1'b1 ) ) i_dma_wide_port_arbiter_tree ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -250,7 +255,9 @@ module local_interconnect hci_arbiter_tree #( .NB_REQUESTS ( N_CORE ), .NB_CHAN ( N_MEM ), - .`HCI_SIZE_PARAM(out) ( `HCI_SIZE_PARAM(core_mem_muxed) ) + .`HCI_SIZE_PARAM(out) ( `HCI_SIZE_PARAM(core_mem_muxed) ), + .WAIVE_RQ3_ASSERT ( 1'b1 ), + .WAIVE_RQ4_ASSERT ( 1'b1 ) ) i_core_wide_port_arbiter_tree ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), diff --git a/hw/tile/magia_cluster_wrap.sv b/hw/tile/magia_cluster_wrap.sv new file mode 100644 index 00000000..8fdf8237 --- /dev/null +++ b/hw/tile/magia_cluster_wrap.sv @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2026 ETH Zurich, University of Bologna and Fondazione Chips-IT + * + * Licensed under the Solderpad Hardware License, Version 0.51 + * (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://solderpad.org/licenses/SHL-0.51 + * + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: SHL-0.51 + * + * Authors: Niccolò Giuliani, Fondazione Chips-IT + * Luca Balboni, Fondazione Chips-IT + * + * MAGIA PULP Cluster Wrapper + * + */ + +module magia_cluster_wrap + import magia_tile_pkg::*; + import magia_pkg::*; +#( + parameter magia_tile_pkg::magia_tile_cfg_t TileCfg = magia_tile_pkg::MagiaTileDefaultCfg, + // Derived from TileCfg + localparam int unsigned NClusterCores = TileCfg.Cluster.NumCores, + // First hart id of the block and number of tiles sharing it + parameter int unsigned HartIdBase = 0, + parameter int unsigned InstanceCount = magia_pkg::N_TILES, + + // HCI types are supplied by magia_tile + parameter type hci_req_t = magia_tile_pkg::core_hci_data_req_t, + parameter type hci_rsp_t = magia_tile_pkg::core_hci_data_rsp_t +)( + input logic sys_clk_i, + input logic rst_ni, + input logic test_mode_i, + + // Per-core gated clocks (one clock gate per core, driven in magia_tile). + input logic [NClusterCores-1:0] cluster_clk_i, + input logic [NClusterCores-1:0] debug_req_i, + + // Tile hart-id base (control core is 0; cluster cores start after the tiles' ctrl cores) + input logic [31:0] mhartid_i, + + // TCDM ranges, idx 0: they take the dedicated HCI port, everything else the OBI crossbar + input magia_tile_pkg::obi_xbar_rule_t [magia_tile_pkg::NUM_TCDM_RULES-1:0] tcdm_rules_i, + + // Control outputs from the cluster CSR (in magia_tile). + input logic [31:0] cluster_boot_addr_i [NClusterCores-1:0], + input logic [NClusterCores-1:0] cluster_fetch_enable_i, + input logic [NClusterCores-1:0] cluster_start_irq_i, // 1-cycle dispatch IRQ pulse per core + + // Per-core OBI data manager ports (peripheral path -> tile OBI crossbar) + output magia_tile_pkg::core_obi_data_req_t [NClusterCores-1:0] cluster_obi_data_req_o, + input magia_tile_pkg::core_obi_data_rsp_t [NClusterCores-1:0] cluster_obi_data_rsp_i, + + // Per-core HCI data manager ports (L1/TCDM path -> tile HCI interconnect) + output hci_req_t [NClusterCores-1:0] cluster_hci_data_req_o, + input hci_rsp_t [NClusterCores-1:0] cluster_hci_data_rsp_i, + + // Per-core instruction fetch ports (-> tile-level shared cluster i$) + output magia_tile_pkg::core_instr_req_t [NClusterCores-1:0] cluster_instr_req_o, + input magia_tile_pkg::core_instr_rsp_t [NClusterCores-1:0] cluster_instr_rsp_i +); + + // Data-demux slave map: TCDM must match idx of tcdm_rules_i + localparam int unsigned CLUSTER_DATA_N_SLV = 2; + localparam int unsigned CLUSTER_DATA_TCDM_IDX = 0; + localparam int unsigned CLUSTER_DATA_OBI_IDX = 1; + + logic [NClusterCores-1:0] cluster_core_sleep; + + // Cluster core data interface (CV32E40P native channel type). + magia_tile_pkg::cv32e40p_core_data_req_t [NClusterCores-1:0] cluster_data_req; + magia_tile_pkg::cv32e40p_core_data_rsp_t [NClusterCores-1:0] cluster_data_rsp; + + // Per-core demux downstream ports ([i][TCDM], [i][OBI]). + magia_tile_pkg::cv32e40p_core_data_req_t [NClusterCores-1:0][CLUSTER_DATA_N_SLV-1:0] cluster_ddemux_req; + magia_tile_pkg::cv32e40p_core_data_rsp_t [NClusterCores-1:0][CLUSTER_DATA_N_SLV-1:0] cluster_ddemux_rsp; + + // Dispatch IRQ of each core and the interrupt lines it drives + logic [NClusterCores-1:0] cluster_irq_ack; + logic [NClusterCores-1:0][magia_tile_pkg::CLIC_ID_W_CLUSTER-1:0] cluster_irq_id; + logic [NClusterCores-1:0] cluster_start_irq_pending_d, cluster_start_irq_pending_q; + logic [NClusterCores-1:0][31:0] cluster_irq_vec; + + // Dispatch IRQ is a 1-cycle pulse from the CSR: hold it until the core acks + assign cluster_start_irq_pending_d = ~cluster_irq_ack & (cluster_start_irq_i | cluster_start_irq_pending_q); + + always_ff @(posedge sys_clk_i or negedge rst_ni) begin + if (!rst_ni) begin + cluster_start_irq_pending_q <= '0; + end else begin + cluster_start_irq_pending_q <= cluster_start_irq_pending_d; + end + end + + // Only the machine external interrupt (bit 11) is used, by the pending dispatch IRQ + for (genvar k = 0; k < NClusterCores; k++) begin : gen_cluster_irq_vec + assign cluster_irq_vec[k] = {20'b0, cluster_start_irq_pending_q[k], 11'b0}; + end + + // --------------------------------------------------------------------------- + // Cluster cores (always CV32E40P) + // --------------------------------------------------------------------------- + for (genvar i = 0; i < NClusterCores; i++) begin : gen_core + `ifndef CORE_TRACES + cv32e40p_top #( + `else + cv32e40p_wrapper #( + `endif + .COREV_PULP ( 1 ), + .COREV_CLUSTER ( 0 ), + .FPU ( FPU ), + .ZFINX ( magia_tile_pkg::ZFINX_CLUSTER ), + .FPU_ADDMUL_LAT ( 1 ), // Match C_LAT_FP32=1 in fpnew wrapper + .FPU_OTHERS_LAT ( 1 ), // Match C_LAT_NONCOMP=1 in fpnew wrapper + .NUM_MHPMCOUNTERS ( 29 ) + ) i_cv32e40p_core ( + // Clock and Reset + .clk_i ( cluster_clk_i[i] ), // Per-core gated clock + .rst_ni ( rst_ni ), + + // Clock always enabled; sleep/wake via WFI / MEI (dispatch IRQ) + .pulp_clock_en_i ( 1'b0 ), // WFI/MEI; cluster event loads disabled + .scan_cg_en_i ( test_mode_i ), + .boot_addr_i ( cluster_boot_addr_i[i] ), // From cluster CSR, dynamic per tile + .mtvec_addr_i ( cluster_boot_addr_i[i] ), // mtvec defaults to boot vector; SW can override via csrw + .dm_halt_addr_i ( magia_tile_pkg::DM_HALT_ADDR), + .hart_id_i ( 32'(HartIdBase + 2 * InstanceCount) + mhartid_i * NClusterCores + i ), + .dm_exception_addr_i ( magia_tile_pkg::DM_HALT_ADDR + 32'h000C), //to be checked + // Instruction interface (-> tile-level shared cluster i$) + .instr_req_o ( cluster_instr_req_o[i].req ), + .instr_addr_o ( cluster_instr_req_o[i].addr ), + .instr_gnt_i ( cluster_instr_rsp_i[i].gnt ), + .instr_rvalid_i ( cluster_instr_rsp_i[i].rvalid ), + .instr_rdata_i ( cluster_instr_rsp_i[i].rdata ), + // Data interface (goes through the per-core data demux below) + .data_req_o ( cluster_data_req[i].req ), + .data_addr_o ( cluster_data_req[i].addr ), + .data_be_o ( cluster_data_req[i].be ), + .data_wdata_o ( cluster_data_req[i].wdata ), + .data_we_o ( cluster_data_req[i].we ), + .data_gnt_i ( cluster_data_rsp[i].gnt ), + .data_rvalid_i ( cluster_data_rsp[i].rvalid ), + .data_rdata_i ( cluster_data_rsp[i].rdata ), + // Interrupts: only the dispatch IRQ (MEI bit 11) from the cluster CSR; no event unit + .irq_i ( cluster_irq_vec[i] ), + .irq_ack_o ( cluster_irq_ack[i] ), + .irq_id_o ( cluster_irq_id[i] ), + + .debug_req_i ( debug_req_i[i] ), + // Debug status outputs unused: no tile-level output exposes per-cluster-core debug status. + .debug_havereset_o ( ), + .debug_running_o ( ), + .debug_halted_o ( ), + // CPU control + .fetch_enable_i ( cluster_fetch_enable_i[i] ), + .core_sleep_o ( cluster_core_sleep[i] ) + ); + end + + // --------------------------------------------------------------------------- + // Per-core data demux: TCDM -> dedicated HCI port, rest -> OBI xbar + // --------------------------------------------------------------------------- + for (genvar i = 0; i < NClusterCores; i++) begin : gen_cluster_data_demux + core_data_demux #( + .NumSlv ( CLUSTER_DATA_N_SLV ), + .NumRules ( magia_tile_pkg::NUM_TCDM_RULES ), + .DefaultSlv ( CLUSTER_DATA_OBI_IDX ), + .req_t ( magia_tile_pkg::cv32e40p_core_data_req_t ), + .rsp_t ( magia_tile_pkg::cv32e40p_core_data_rsp_t ) + ) i_cluster_data_demux ( + .clk_i ( cluster_clk_i[i] ), + .rst_ni ( rst_ni ), + .clk_en_i ( 1'b1 ), + .core_data_req_i ( cluster_data_req[i] ), + .core_data_atomic_i ( 1'b0 ), + .core_data_rsp_o ( cluster_data_rsp[i] ), + .addr_map_i ( tcdm_rules_i ), + .slv_data_req_o ( cluster_ddemux_req[i] ), + .slv_data_rsp_i ( cluster_ddemux_rsp[i] ) + ); + end + + // --------------------------------------------------------------------------- + // Per-core converters: OBI path demux->xbar; TCDM path demux->OBI->HCI + // --------------------------------------------------------------------------- + for (genvar i = 0; i < NClusterCores; i++) begin : gen_cluster_data_obi + + // --- OBI (peripheral) path --- + cv32e40p_data2obi_req i_cluster_data2obi ( + .data_req_i ( cluster_ddemux_req[i][CLUSTER_DATA_OBI_IDX] ), + .obi_req_o ( cluster_obi_data_req_o[i] ) + ); + + cv32e40p_obi2data_rsp i_cluster_obi2data ( + .obi_rsp_i ( cluster_obi_data_rsp_i[i] ), + .data_rsp_o ( cluster_ddemux_rsp[i][CLUSTER_DATA_OBI_IDX] ) + ); + + // --- TCDM (L1) path: native mem -> OBI -> HCI dedicated interconnect port --- + magia_tile_pkg::core_obi_data_req_t cluster_tcdm_obi_req; + magia_tile_pkg::core_obi_data_rsp_t cluster_tcdm_obi_rsp; + + cv32e40p_data2obi_req i_cluster_tcdm_data2obi ( + .data_req_i ( cluster_ddemux_req[i][CLUSTER_DATA_TCDM_IDX] ), + .obi_req_o ( cluster_tcdm_obi_req ) + ); + + cv32e40p_obi2data_rsp i_cluster_tcdm_obi2data ( + .obi_rsp_i ( cluster_tcdm_obi_rsp ), + .data_rsp_o ( cluster_ddemux_rsp[i][CLUSTER_DATA_TCDM_IDX] ) + ); + + obi2hci_req #( + .obi_req_t ( magia_tile_pkg::core_obi_data_req_t ), + .hci_req_t ( hci_req_t ) + ) i_cluster_tcdm_obi2hci_req ( + .obi_req_i ( cluster_tcdm_obi_req ), + .hci_req_o ( cluster_hci_data_req_o[i] ) + ); + + hci2obi_rsp #( + .hci_rsp_t ( hci_rsp_t ), + .obi_rsp_t ( magia_tile_pkg::core_obi_data_rsp_t ) + ) i_cluster_tcdm_hci2obi_rsp ( + .hci_rsp_i ( cluster_hci_data_rsp_i[i] ), + .obi_rsp_o ( cluster_tcdm_obi_rsp ) + ); + end + +endmodule: magia_cluster_wrap diff --git a/hw/tile/magia_event_unit.sv b/hw/tile/magia_event_unit.sv index dbff502b..15f1d20c 100644 --- a/hw/tile/magia_event_unit.sv +++ b/hw/tile/magia_event_unit.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -83,33 +83,31 @@ import magia_tile_pkg::*; // Convert abstract eu_direct interface to XBAR_PERIPH_BUS (one per core) // eu_direct_addr_i already contains relative offset (subtracted by demux) - generate - for (genvar k = 0; k < NB_CORES; k++) begin : gen_eu_direct_link - assign eu_direct_link[k].req = eu_direct_req_i[k]; - assign eu_direct_link[k].add = eu_direct_addr_i[k]; - assign eu_direct_link[k].wen = eu_direct_wen_i[k]; - assign eu_direct_link[k].wdata = eu_direct_wdata_i[k]; - assign eu_direct_link[k].be = eu_direct_be_i[k]; - assign eu_direct_link[k].id = '0; + for (genvar k = 0; k < NB_CORES; k++) begin : gen_eu_direct_link + assign eu_direct_link[k].req = eu_direct_req_i[k]; + assign eu_direct_link[k].add = eu_direct_addr_i[k]; + assign eu_direct_link[k].wen = eu_direct_wen_i[k]; + assign eu_direct_link[k].wdata = eu_direct_wdata_i[k]; + assign eu_direct_link[k].be = eu_direct_be_i[k]; + assign eu_direct_link[k].id = '0; - assign eu_direct_gnt_o[k] = eu_direct_link[k].gnt; - assign eu_direct_rvalid_o[k] = eu_direct_link[k].r_valid; - assign eu_direct_rdata_o[k] = eu_direct_link[k].r_rdata; - assign eu_direct_err_o[k] = eu_direct_link[k].r_opc; - end - endgenerate + assign eu_direct_gnt_o[k] = eu_direct_link[k].gnt; + assign eu_direct_rvalid_o[k] = eu_direct_link[k].r_valid; + assign eu_direct_rdata_o[k] = eu_direct_link[k].r_rdata; + assign eu_direct_err_o[k] = eu_direct_link[k].r_opc; + end // Address range check and offset calculation localparam logic [magia_pkg::ADDR_W-1:0] EU_BASE_ADDR = magia_tile_pkg::EVENT_UNIT_ADDR_START; logic addr_in_range; logic [magia_pkg::ADDR_W-1:0] addr_offset; - assign addr_in_range = (obi_req_i.a.addr >= magia_tile_pkg::EVENT_UNIT_ADDR_START) && + assign addr_in_range = (obi_req_i.a.addr >= magia_tile_pkg::EVENT_UNIT_ADDR_START) & (obi_req_i.a.addr < magia_tile_pkg::EVENT_UNIT_ADDR_END); assign addr_offset = obi_req_i.a.addr - EU_BASE_ADDR; // OBI to XBAR_PERIPH_BUS conversion - pass RELATIVE address (offset from base) - assign speriph_slave.req = obi_req_i.req && addr_in_range; + assign speriph_slave.req = obi_req_i.req & addr_in_range; assign speriph_slave.add = addr_offset; assign speriph_slave.wen = ~obi_req_i.a.we; assign speriph_slave.wdata = obi_req_i.a.wdata; diff --git a/hw/tile/magia_isle.sv b/hw/tile/magia_isle.sv new file mode 100644 index 00000000..a639043e --- /dev/null +++ b/hw/tile/magia_isle.sv @@ -0,0 +1,2077 @@ +/* + * Copyright (C) 2023-2026 ETH Zurich, University of Bologna and Fondazione Chips-IT + * + * Licensed under the Solderpad Hardware License, Version 0.51 + * (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://solderpad.org/licenses/SHL-0.51 + * + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: SHL-0.51 + * + * Authors: Victor Isachi + * Luca Balboni, Fondazione Chips-IT + * + * MAGIA Isle + */ + +`include "hci_helpers.svh" +`include "hwpe_ctrl_helpers.svh" + +// Observation port of the Verilator testbench, dropped by MAGIA_NO_OBSERVE +`ifdef VERILATOR +`ifndef MAGIA_NO_OBSERVE +`define MAGIA_ISLE_OBSERVE +`endif +`endif + +module magia_isle + import magia_tile_pkg::*; + import magia_pkg::*; + import redmule_pkg::*; + import hci_package::*; +`ifdef CV32E40X + import cv32e40x_pkg::*; + import fpu_ss_pkg::*; +`endif + import snitch_icache_pkg::*; + import idma_pkg::*; + import obi_pkg::*; + import axi_pkg::*; +#( + parameter magia_tile_pkg::magia_tile_cfg_t TileCfg = magia_tile_pkg::MagiaTileDefaultCfg, + + // Hart ids: control core and Spatz at HartIdBase + mhartid_i, cluster cores after all tiles + parameter int unsigned HartIdBase = 0, + parameter int unsigned InstanceCount = magia_pkg::N_TILES, + + // Cacheable code region for the i-caches and Spatz's PMA; size 0 caches every fetch + parameter longint unsigned CodeRegionBase = 64'h0, + parameter longint unsigned CodeRegionSize = 64'h0 +)( + input logic clk_i, + input logic rst_ni, + input logic test_mode_i, + input logic tile_enable_i, + + // Narrow AXI: requests leaving the isle + output magia_pkg::axi_xbar_mst_req_t axi_narrow_mst_req_o, + input magia_pkg::axi_xbar_mst_rsp_t axi_narrow_mst_rsp_i, + // Narrow AXI: requests entering the isle + input magia_tile_pkg::axi_xbar_slv_req_t axi_narrow_slv_req_i, + output magia_tile_pkg::axi_xbar_slv_rsp_t axi_narrow_slv_rsp_o, + // Wide AXI: iDMA requests leaving the isle + output magia_tile_pkg::idma_axi_req_t axi_wide_mst_req_o, + input magia_tile_pkg::idma_axi_rsp_t axi_wide_mst_rsp_i, + // Wide AXI: iDMA requests entering the isle + input magia_tile_pkg::idma_axi_req_t axi_wide_slv_req_i, + output magia_tile_pkg::idma_axi_rsp_t axi_wide_slv_rsp_o, + +`ifdef MAGIA_FSYNC + fractal_sync_if.mst_port ht_fsync_if_o, + fractal_sync_if.mst_port hn_fsync_if_o, + fractal_sync_if.mst_port vt_fsync_if_o, + fractal_sync_if.mst_port vn_fsync_if_o, +`endif + + input logic[31:0] mhartid_i, // Position of the isle in the global address map + input logic[31:0] boot_addr_i, + input logic fetch_enable_i, + output logic core_sleep_o, + + // Event Unit interrupt of the control core, for an external controller (e.g. host CLIC) + output logic eu_irq_req_o, + output logic[4:0] eu_irq_id_o, + input logic eu_irq_ack_i, // Clears event eu_irq_ack_id_i + input logic[4:0] eu_irq_ack_id_i, + + input logic[magia_tile_pkg::N_CLUSTER_CORES:0] debug_req_i, // [0] control core, [N:1] cluster cores + output logic debug_havereset_o, + output logic debug_running_o, + output logic debug_halted_o, + output logic debug_pc_valid_o, + output logic[31:0] debug_pc_o, + output logic[63:0] mcycle_o, + // Debug halt and exception entry points of the control core + input logic[31:0] dm_halt_addr_i, + input logic[31:0] dm_exception_addr_i +`ifdef CV32E40X + // Read only by the CV32E40X + , input logic scan_cg_en_i, + input logic[31:0] mtvec_addr_i, + input logic[ 3:0] mimpid_patch_i, + input logic[63:0] time_i, + input logic wu_wfe_i +`endif +`ifdef MAGIA_ISLE_OBSERVE + , output magia_tile_observe_t observe_o +`endif +); + +/*******************************************************/ +/** Configuration Beginning **/ +/*******************************************************/ + + localparam magia_tile_pkg::obi_mgr_map_t ObiMgr = magia_tile_pkg::gen_obi_mgr_map(TileCfg); + localparam magia_tile_pkg::obi_sbr_map_t ObiSbr = magia_tile_pkg::gen_obi_sbr_map(TileCfg); + localparam magia_tile_pkg::axi_xbar_mst_map_t AxiMst = magia_tile_pkg::gen_axi_xbar_mst_map(TileCfg); + localparam axi_pkg::xbar_cfg_t AxiXbarCfg = magia_tile_pkg::gen_axi_xbar_cfg(TileCfg); + localparam magia_tile_pkg::ctrl_map_t CtrlMap = magia_tile_pkg::gen_ctrl_map(TileCfg); + + // NoC traffic never goes back out to the NoC: the xbar answers it with a DECERR + localparam bit [AxiXbarCfg.NoSlvPorts-1:0][AxiXbarCfg.NoMstPorts-1:0] AxiConnectivity = + ~((AxiXbarCfg.NoSlvPorts*AxiXbarCfg.NoMstPorts)'(1) << (magia_tile_pkg::AXI_SLV_EXT_IDX*AxiXbarCfg.NoMstPorts + AxiMst.ext)); + + localparam int unsigned NumSpatzHciPorts = magia_tile_pkg::gen_tile_spatz_hci_ports(TileCfg); + localparam int unsigned NumHciCore = magia_tile_pkg::gen_tile_num_hci_core(TileCfg); + localparam int unsigned NClusterCores = TileCfg.Cluster.NumCores; + + localparam int unsigned NumMemBanks = TileCfg.L1.NumBanks; + localparam int unsigned NumWordsBank = TileCfg.L1.NumWordsBank; + localparam int unsigned L1BankAddrW = $clog2(NumWordsBank * magia_tile_pkg::DW_LIC / magia_tile_pkg::BW_LIC); // Byte address within a bank + + localparam int unsigned NumHwpe = magia_tile_pkg::N_HWPE; // Stays 1 without RedMulE: local_interconnect is not 0-safe + localparam int unsigned NumDma = magia_tile_pkg::N_DMA; + localparam int unsigned NumExt = magia_tile_pkg::N_EXT; + localparam int unsigned TileIW = NumHwpe + NumHciCore + NumDma + NumExt; + + localparam int unsigned RedmuleFpW = 16; // FP16 + localparam int unsigned RedmuleDataW = TileCfg.RedMule.Height * (TileCfg.RedMule.NumPipeRegs + 1) * RedmuleFpW; + + `HCI_TYPEDEF_REQ_T(tile_redmule_data_req_t, logic[magia_tile_pkg::AWC-1:0], logic[RedmuleDataW-1:0], logic[RedmuleDataW/magia_tile_pkg::BWH-1:0], logic[magia_tile_pkg::UWH-1:0], logic[TileIW-1:0], logic[0:0], logic[0:0]) + `HCI_TYPEDEF_RSP_T(tile_redmule_data_rsp_t, logic[RedmuleDataW-1:0], logic[magia_tile_pkg::UWH-1:0], logic[TileIW-1:0], logic[0:0], logic[0:0]) + + `HCI_TYPEDEF_REQ_T(tile_hci_data_req_t, logic[magia_tile_pkg::AWC-1:0], logic[magia_tile_pkg::DW_LIC-1:0], logic[magia_tile_pkg::SW_LIC-1:0], logic[magia_tile_pkg::UWH-1:0], logic[TileIW-1:0], logic[0:0], logic[0:0]) + `HCI_TYPEDEF_RSP_T(tile_hci_data_rsp_t, logic[magia_tile_pkg::DW_LIC-1:0], logic[magia_tile_pkg::UWH-1:0], logic[TileIW-1:0], logic[0:0], logic[0:0]) + `HCI_TYPEDEF_REQ_T(tile_idma_hci_req_t, logic[magia_tile_pkg::iDMA_AddrWidth-1:0], logic[magia_tile_pkg::iDMA_DataWidth-1:0], logic[magia_tile_pkg::iDMA_StrbWidth-1:0], logic[magia_tile_pkg::iDMA_UserWidth-1:0], logic[TileIW-1:0], logic[0:0], logic[0:0]) + `HCI_TYPEDEF_RSP_T(tile_idma_hci_rsp_t, logic[magia_tile_pkg::iDMA_DataWidth-1:0], logic[magia_tile_pkg::iDMA_UserWidth-1:0], logic[TileIW-1:0], logic[0:0], logic[0:0]) + + localparam logic[31:0] CodeRegionMask = (CodeRegionSize == 0) ? 32'h0 + : ~(32'(CodeRegionSize) - 32'd1); + +`ifndef SYNTHESIS + if (CodeRegionSize != 0 && + (((CodeRegionSize & (CodeRegionSize - 1)) != 0) || ((CodeRegionBase & (CodeRegionSize - 1)) != 0))) begin: gen_code_region_err + $fatal(1, "magia_isle: the code region 0x%0h+0x%0h is not a power of two aligned to its size", + CodeRegionBase, CodeRegionSize); + end +`endif + + localparam snitch_pma_pkg::snitch_pma_t SpatzPmaCfg = + (CodeRegionSize == 0) ? magia_tile_pkg::SPATZ_SNITCH_PMA_CFG + : magia_tile_pkg::gen_spatz_pma_cfg(magia_pkg::ADDR_W'(CodeRegionBase), CodeRegionMask); + +/*******************************************************/ +/** Configuration End **/ +/*******************************************************/ +/** Clock Gating Beginning **/ +/*******************************************************/ + + logic sys_clk_en; + logic sys_clk; + + always_ff @(posedge clk_i or negedge rst_ni) begin : sys_clk_en_ff + if (!rst_ni) begin + sys_clk_en <= 1'b0; + end else begin + sys_clk_en <= tile_enable_i; + end + end + + tc_clk_gating sys_clock_gating ( + .clk_i , + .en_i ( sys_clk_en ), + .test_en_i ( test_mode_i ), + .clk_o ( sys_clk ) + ); + + // The Event Unit gates the control core while it waits for an event + logic eu_core_clk_en; + logic core_clk_en; + logic core_clk; + + assign core_clk_en = eu_core_clk_en; + + tc_clk_gating core_clock_gating ( + .clk_i ( sys_clk ), + .en_i ( core_clk_en ), + .test_en_i ( test_mode_i ), + .clk_o ( core_clk ) + ); + +/*******************************************************/ +/** Clock Gating End **/ +/*******************************************************/ +/** Tile Address Map Beginning **/ +/*******************************************************/ + + // L1 is global: each tile owns the slot at mhartid*L1_TILE_OFFSET + logic[magia_pkg::ADDR_W-1:0] tile_l1_start_addr; + logic[magia_pkg::ADDR_W-1:0] tile_l1_end_addr; + logic[magia_pkg::ADDR_W-1:0] tile_event_unit_start_addr; + logic[magia_pkg::ADDR_W-1:0] tile_event_unit_end_addr; + + assign tile_l1_start_addr = magia_tile_pkg::L1_ADDR_START + mhartid_i*magia_tile_pkg::L1_TILE_OFFSET; + assign tile_l1_end_addr = magia_tile_pkg::L1_ADDR_END + mhartid_i*magia_tile_pkg::L1_TILE_OFFSET; + assign tile_event_unit_start_addr = magia_tile_pkg::EVENT_UNIT_ADDR_START; + assign tile_event_unit_end_addr = magia_tile_pkg::EVENT_UNIT_ADDR_END; + + // TCDM ranges of core data, idx 0 of the cluster data demux + magia_tile_pkg::obi_xbar_rule_t [magia_tile_pkg::NUM_TCDM_RULES-1:0] tcdm_rules; + + assign tcdm_rules[0] = '{idx: 0, start_addr: tile_l1_start_addr, end_addr: tile_l1_end_addr}; + +/*******************************************************/ +/** Tile Address Map End **/ +/*******************************************************/ +/** Control Core Beginning **/ +/*******************************************************/ + + magia_tile_pkg::core_instr_req_t core_instr_req; + magia_tile_pkg::core_instr_rsp_t core_instr_rsp; + magia_tile_pkg::core_data_req_t core_data_req; + magia_tile_pkg::core_data_rsp_t core_data_rsp; + + logic fencei_flush_req; + logic fencei_flush_ack; + + // No CPU interrupts: the control core waits on the Event Unit + logic[magia_pkg::N_IRQ-1:0] irq; + logic[31:0] core_irq_vec; + + assign irq = '0; + assign core_irq_vec = '0; + +`ifdef CV32E40X + logic clic_irq; + logic[magia_tile_pkg::CLIC_ID_W-1:0] clic_irq_id; + logic[7:0] clic_irq_level; + logic[1:0] clic_irq_priv; + logic clic_irq_shv; + + assign clic_irq = 1'b0; + assign clic_irq_id = '0; + assign clic_irq_level = '0; + assign clic_irq_priv = '0; + assign clic_irq_shv = 1'b0; + + // Shared by the core (cpu_*) and the FPU (coproc_*) + cv32e40x_if_xif #( + .X_NUM_RS ( magia_tile_pkg::X_NUM_RS ), + .X_ID_WIDTH ( magia_tile_pkg::X_ID_W ), + .X_MEM_WIDTH ( magia_tile_pkg::X_MEM_W ), + .X_RFR_WIDTH ( magia_tile_pkg::X_RFR_W ), + .X_RFW_WIDTH ( magia_tile_pkg::X_RFW_W ), + .X_MISA ( magia_tile_pkg::X_MISA ), + .X_ECS_XS ( magia_tile_pkg::X_ECS_XS ) + ) xif_if (); + +`ifndef CORE_TRACES + cv32e40x_core #( +`else + cv32e40x_wrapper #( +`endif + .RV32 ( TileCfg.CtrlCore.ISA ), + .A_EXT ( TileCfg.CtrlCore.A ), + .B_EXT ( TileCfg.CtrlCore.B ), + .M_EXT ( TileCfg.CtrlCore.M ), + .X_EXT ( magia_tile_pkg::X_EXT_EN ), + .X_NUM_RS ( magia_tile_pkg::X_NUM_RS ), + .X_ID_WIDTH ( magia_tile_pkg::X_ID_W ), + .X_MEM_WIDTH ( magia_tile_pkg::X_MEM_W ), + .X_RFR_WIDTH ( magia_tile_pkg::X_RFR_W ), + .X_RFW_WIDTH ( magia_tile_pkg::X_RFW_W ), + .X_MISA ( magia_tile_pkg::X_MISA ), + .X_ECS_XS ( magia_tile_pkg::X_ECS_XS ), + .NUM_MHPMCOUNTERS ( 1 ), + .DEBUG ( 1 ), + .DM_REGION_START ( magia_tile_pkg::DM_REGION_START ), + .DM_REGION_END ( magia_tile_pkg::DM_REGION_END ), + .DBG_NUM_TRIGGERS ( 1 ), + .PMA_NUM_REGIONS ( 0 ), + .PMA_CFG ( ), + .CLIC ( magia_tile_pkg::CLIC_EN ), + .CLIC_ID_WIDTH ( magia_tile_pkg::CLIC_ID_W ) + ) i_cv32e40x_ctrl_core ( + .clk_i ( core_clk ), + .rst_ni ( rst_ni ), + .scan_cg_en_i , + + .boot_addr_i , + .mtvec_addr_i , + .dm_halt_addr_i , + .dm_exception_addr_i , + .mhartid_i ( 32'(HartIdBase) + mhartid_i ), + .mimpid_patch_i , + + .instr_req_o ( core_instr_req.req ), + .instr_gnt_i ( core_instr_rsp.gnt ), + .instr_addr_o ( core_instr_req.addr ), + .instr_memtype_o ( core_instr_req.memtype ), + .instr_prot_o ( core_instr_req.prot ), + .instr_dbg_o ( core_instr_req.dbg ), + .instr_rvalid_i ( core_instr_rsp.rvalid ), + .instr_rdata_i ( core_instr_rsp.rdata ), + .instr_err_i ( core_instr_rsp.err ), + + .data_req_o ( core_data_req.req ), + .data_gnt_i ( core_data_rsp.gnt ), + .data_addr_o ( core_data_req.addr ), + .data_atop_o ( core_data_req.atop ), + .data_be_o ( core_data_req.be ), + .data_memtype_o ( core_data_req.memtype ), + .data_prot_o ( core_data_req.prot ), + .data_dbg_o ( core_data_req.dbg ), + .data_wdata_o ( core_data_req.wdata ), + .data_we_o ( core_data_req.we ), + .data_rvalid_i ( core_data_rsp.rvalid ), + .data_rdata_i ( core_data_rsp.rdata ), + .data_err_i ( core_data_rsp.err ), + .data_exokay_i ( core_data_rsp.exokay ), + + .mcycle_o , + .time_i , + + .xif_compressed_if ( xif_if.cpu_compressed ), + .xif_issue_if ( xif_if.cpu_issue ), + .xif_commit_if ( xif_if.cpu_commit ), + .xif_mem_if ( xif_if.cpu_mem ), + .xif_mem_result_if ( xif_if.cpu_mem_result ), + .xif_result_if ( xif_if.cpu_result ), + + .irq_i ( irq ), + + .clic_irq_i ( clic_irq ), + .clic_irq_id_i ( clic_irq_id ), + .clic_irq_level_i ( clic_irq_level ), + .clic_irq_priv_i ( clic_irq_priv ), + .clic_irq_shv_i ( clic_irq_shv ), + + .fencei_flush_req_o ( fencei_flush_req ), + .fencei_flush_ack_i ( fencei_flush_ack ), + + .debug_req_i ( debug_req_i[0] ), + .debug_havereset_o , + .debug_running_o , + .debug_halted_o , + .debug_pc_valid_o , + .debug_pc_o , + + .fetch_enable_i , + .core_sleep_o , + .wu_wfe_i + ); +`else +`ifndef CORE_TRACES + cv32e40p_top #( +`else + cv32e40p_wrapper #( +`endif + .COREV_PULP ( 1 ), + .COREV_CLUSTER ( 1 ), + .FPU ( FPU ), + .ZFINX ( magia_tile_pkg::ZFINX_CTRL ), + .FPU_ADDMUL_LAT ( 1 ), // Match C_LAT_FP32 in the fpnew wrapper + .FPU_OTHERS_LAT ( 1 ), // Match C_LAT_NONCOMP in the fpnew wrapper + .NUM_MHPMCOUNTERS ( 29 ) + ) i_cv32e40p_ctrl_core ( + .clk_i ( core_clk ), + .rst_ni ( rst_ni ), + + .pulp_clock_en_i ( core_clk_en ), + .scan_cg_en_i ( test_mode_i ), + .boot_addr_i ( boot_addr_i ), + .mtvec_addr_i ( boot_addr_i ), // SW can move mtvec with csrw + .dm_halt_addr_i ( dm_halt_addr_i ), + .hart_id_i ( 32'(HartIdBase) + mhartid_i ), + .dm_exception_addr_i ( dm_exception_addr_i ), + + .instr_req_o ( core_instr_req.req ), + .instr_gnt_i ( core_instr_rsp.gnt ), + .instr_rvalid_i ( core_instr_rsp.rvalid ), + .instr_addr_o ( core_instr_req.addr ), + .instr_rdata_i ( core_instr_rsp.rdata ), + + .data_req_o ( core_data_req.req ), + .data_gnt_i ( core_data_rsp.gnt ), + .data_rvalid_i ( core_data_rsp.rvalid ), + .data_addr_o ( core_data_req.addr ), + .data_be_o ( core_data_req.be ), + .data_wdata_o ( core_data_req.wdata ), + .data_we_o ( core_data_req.we ), + .data_rdata_i ( core_data_rsp.rdata ), + + .irq_i ( core_irq_vec ), + .irq_ack_o ( ), + .irq_id_o ( ), + + .debug_req_i ( debug_req_i[0] ), + .debug_havereset_o ( debug_havereset_o ), + .debug_running_o ( debug_running_o ), + .debug_halted_o ( debug_halted_o ), + + .fetch_enable_i ( fetch_enable_i ), + .core_sleep_o ( core_sleep_o ) + ); + + assign core_instr_req.memtype = 2'b00; + assign core_instr_req.prot = 3'b000; + assign core_instr_req.dbg = 1'b0; + + assign mcycle_o = 64'h0; + assign debug_pc_valid_o = 1'b0; + assign debug_pc_o = 32'h0; +`endif + +/*******************************************************/ +/** Control Core End **/ +/*******************************************************/ +/** Floating-Point Unit Beginning **/ +/*******************************************************/ + +`ifdef CV32E40X + logic x_compressed_valid; + logic x_compressed_ready; + fpu_ss_pkg::x_compressed_req_t x_compressed_req; + fpu_ss_pkg::x_compressed_resp_t x_compressed_resp; + logic x_issue_valid; + logic x_issue_ready; + fpu_ss_pkg::x_issue_req_t x_issue_req; + fpu_ss_pkg::x_issue_resp_t x_issue_resp; + logic x_commit_valid; + fpu_ss_pkg::x_commit_t x_commit; + logic x_mem_valid; + logic x_mem_ready; + fpu_ss_pkg::x_mem_req_t x_mem_req; + fpu_ss_pkg::x_mem_resp_t x_mem_resp; + logic x_mem_result_valid; + fpu_ss_pkg::x_mem_result_t x_mem_result; + logic x_result_valid; + logic x_result_ready; + fpu_ss_pkg::x_result_t x_result; + + xif_if2struct i_xif_if2struct ( + .xif_compressed_if_i ( xif_if.coproc_compressed ), + .xif_issue_if_i ( xif_if.coproc_issue ), + .xif_commit_if_i ( xif_if.coproc_commit ), + .xif_mem_if_o ( xif_if.coproc_mem ), + .xif_mem_result_if_i ( xif_if.coproc_mem_result ), + .xif_result_if_o ( xif_if.coproc_result ), + .x_compressed_valid_o ( x_compressed_valid ), + .x_compressed_ready_i ( x_compressed_ready ), + .x_compressed_req_o ( x_compressed_req ), + .x_compressed_resp_i ( x_compressed_resp ), + .x_issue_valid_o ( x_issue_valid ), + .x_issue_ready_i ( x_issue_ready ), + .x_issue_req_o ( x_issue_req ), + .x_issue_resp_i ( x_issue_resp ), + .x_commit_valid_o ( x_commit_valid ), + .x_commit_o ( x_commit ), + .x_mem_valid_i ( x_mem_valid ), + .x_mem_ready_o ( x_mem_ready ), + .x_mem_req_i ( x_mem_req ), + .x_mem_resp_o ( x_mem_resp ), + .x_mem_result_valid_o ( x_mem_result_valid ), + .x_mem_result_o ( x_mem_result ), + .x_result_valid_i ( x_result_valid ), + .x_result_ready_o ( x_result_ready ), + .x_result_i ( x_result ) + ); + + fpu_ss #( + .PULP_ZFINX ( magia_tile_pkg::ZFINX_CTRL ), + .INPUT_BUFFER_DEPTH ( magia_tile_pkg::FPU_BUFFER_DEPTH ), + .INPUT_BUFFER_FALL_THROUGH ( magia_tile_pkg::FPU_BUFFER_FT ), + .OUT_OF_ORDER ( magia_tile_pkg::FPU_OOO ), + .FORWARDING ( magia_tile_pkg::FPU_FWD ), + .PulpDivsqrt ( magia_tile_pkg::FPU_DIVSQRT ), + .FPU_FEATURES ( magia_tile_pkg::FPU_FEATURES ), + .FPU_IMPLEMENTATION ( magia_tile_pkg::FPU_IMPLEMENTATION ) + ) i_fpu ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .x_compressed_valid_i ( x_compressed_valid ), + .x_compressed_ready_o ( x_compressed_ready ), + .x_compressed_req_i ( x_compressed_req ), + .x_compressed_resp_o ( x_compressed_resp ), + .x_issue_valid_i ( x_issue_valid ), + .x_issue_ready_o ( x_issue_ready ), + .x_issue_req_i ( x_issue_req ), + .x_issue_resp_o ( x_issue_resp ), + .x_commit_valid_i ( x_commit_valid ), + .x_commit_i ( x_commit ), + .x_mem_valid_o ( x_mem_valid ), + .x_mem_ready_i ( x_mem_ready ), + .x_mem_req_o ( x_mem_req ), + .x_mem_resp_i ( x_mem_resp ), + .x_mem_result_valid_i ( x_mem_result_valid ), + .x_mem_result_i ( x_mem_result ), + .x_result_valid_o ( x_result_valid ), + .x_result_ready_i ( x_result_ready ), + .x_result_o ( x_result ) + ); +`endif + +/*******************************************************/ +/** Floating-Point Unit End **/ +/*******************************************************/ +/** Control Core i$ Beginning **/ +/*******************************************************/ + + magia_tile_pkg::core_cache_instr_req_t core_cache_instr_req; + magia_tile_pkg::core_cache_instr_rsp_t core_cache_instr_rsp; + magia_tile_pkg::core_axi_instr_req_t core_l2_instr_req; + magia_tile_pkg::core_axi_instr_rsp_t core_l2_instr_rsp; + + logic enable_prefetching; + logic[magia_tile_pkg::NR_FETCH_PORTS-1:0] flush_valid; + logic[magia_tile_pkg::NR_FETCH_PORTS-1:0] flush_ready; + + assign enable_prefetching = 1'b0; +`ifdef CV32E40X + assign flush_valid[0] = fencei_flush_req; + assign fencei_flush_ack = flush_ready[0]; +`else + assign flush_valid = '0; +`endif + + instr2cache_req i_core_instr2cache_req ( + .instr_req_i ( core_instr_req ), + .cache_req_o ( core_cache_instr_req ) + ); + + cache2instr_rsp i_core_cache2instr_rsp ( + .cache_rsp_i ( core_cache_instr_rsp ), + .instr_rsp_o ( core_instr_rsp ) + ); + + magia_tile_icache_wrap #( + .CachedRegionBase ( 32'(CodeRegionBase) ), + .CachedRegionMask ( CodeRegionMask ), + .NumFetchPorts ( magia_tile_pkg::NR_FETCH_PORTS ), + .L0_LINE_COUNT ( magia_tile_pkg::L0_LINE_COUNT ), + .LINE_WIDTH ( magia_tile_pkg::LINE_WIDTH ), + .LINE_COUNT ( magia_tile_pkg::LINE_COUNT ), + .WAY_COUNT ( magia_tile_pkg::WAY_COUNT ), + .FetchAddrWidth ( magia_tile_pkg::FETCH_AW ), + .FetchDataWidth ( magia_tile_pkg::FETCH_DW ), + .AxiAddrWidth ( magia_tile_pkg::FILL_AW ), + .AxiDataWidth ( magia_tile_pkg::FILL_DW ) + ) i_icache ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + + .fetch_req_i ( core_cache_instr_req.req ), + .fetch_addr_i ( core_cache_instr_req.addr ), + .fetch_gnt_o ( core_cache_instr_rsp.gnt ), + .fetch_rvalid_o ( core_cache_instr_rsp.rvalid ), + .fetch_rdata_o ( core_cache_instr_rsp.rdata ), + .fetch_rerror_o ( core_cache_instr_rsp.rerror ), + + .enable_prefetching_i ( enable_prefetching ), + .icache_l0_events_o ( ), + .icache_l1_events_o ( ), + .flush_valid_i ( flush_valid ), + .flush_ready_o ( flush_ready ), + + .sram_cfg_data_i ( '0 ), + .sram_cfg_tag_i ( '0 ), + + .axi_req_o ( core_l2_instr_req ), + .axi_rsp_i ( core_l2_instr_rsp ) + ); + +/*******************************************************/ +/** Control Core i$ End **/ +/*******************************************************/ +/** Control Core Data Path Beginning **/ +/*******************************************************/ + + // Event Unit accesses take the direct link, everything else the OBI crossbar + localparam int unsigned CoreDataObi = 0; + localparam int unsigned CoreDataEu = 1; + localparam int unsigned CoreDataNumSlv = 2; + + magia_tile_pkg::obi_xbar_rule_t [0:0] core_data_rules; + magia_tile_pkg::core_data_req_t [CoreDataNumSlv-1:0] core_data_slv_req; + magia_tile_pkg::core_data_rsp_t [CoreDataNumSlv-1:0] core_data_slv_rsp; + magia_tile_pkg::core_data_rsp_t core_data_eu_rsp; + magia_tile_pkg::eu_direct_req_t eu_direct_req; + magia_tile_pkg::eu_direct_rsp_t eu_direct_rsp; + magia_tile_pkg::eu_direct_req_t eu_direct_req_cut; + magia_tile_pkg::eu_direct_rsp_t eu_direct_rsp_cut; + + assign core_data_rules[0] = '{idx: CoreDataEu, start_addr: tile_event_unit_start_addr, end_addr: tile_event_unit_end_addr}; + + // EU accesses serialize, like cv.elw: a pipelined load must not overtake a blocking EU wait + core_data_demux #( + .NumSlv ( CoreDataNumSlv ), + .NumRules ( 1 ), + .DefaultSlv ( CoreDataObi ), + .SerialSlv ( CoreDataNumSlv'(1 << CoreDataEu) ), + .req_t ( magia_tile_pkg::core_data_req_t ), + .rsp_t ( magia_tile_pkg::core_data_rsp_t ) + ) i_core_data_demux ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .clk_en_i ( core_clk_en ), + .core_data_req_i ( core_data_req ), + .core_data_atomic_i ( 1'b0 ), + .core_data_rsp_o ( core_data_rsp ), + .addr_map_i ( core_data_rules ), + .slv_data_req_o ( core_data_slv_req ), + .slv_data_rsp_i ( core_data_slv_rsp ) + ); + + assign eu_direct_req.req = core_data_slv_req[CoreDataEu].req; + assign eu_direct_req.addr = core_data_slv_req[CoreDataEu].addr - tile_event_unit_start_addr; + assign eu_direct_req.wen = ~core_data_slv_req[CoreDataEu].we; + assign eu_direct_req.wdata = core_data_slv_req[CoreDataEu].wdata; + assign eu_direct_req.be = core_data_slv_req[CoreDataEu].be; + + always_comb begin + core_data_eu_rsp = '0; + core_data_eu_rsp.gnt = eu_direct_rsp.gnt; + core_data_eu_rsp.rvalid = eu_direct_rsp.rvalid; + core_data_eu_rsp.rdata = eu_direct_rsp.rdata; + core_data_eu_rsp.err = eu_direct_rsp.err; + end + + assign core_data_slv_rsp[CoreDataEu] = core_data_eu_rsp; + + eu_direct_cut #( + .Bypass ( 1'b0 ), + .BypassReq ( 1'b0 ), + .BypassRsp ( 1'b0 ), + .NB_CORES ( 1 ) + ) i_eu_direct_cut ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .sbr_req_i ( eu_direct_req ), + .sbr_rsp_o ( eu_direct_rsp ), + .mgr_req_o ( eu_direct_req_cut ), + .mgr_rsp_i ( eu_direct_rsp_cut ) + ); + + logic eu_direct_req_flat; + logic [31:0] eu_direct_addr_flat; + logic eu_direct_wen_flat; + logic [31:0] eu_direct_wdata_flat; + logic [3:0] eu_direct_be_flat; + logic eu_direct_gnt_flat; + logic eu_direct_rvalid_flat; + logic [31:0] eu_direct_rdata_flat; + logic eu_direct_err_flat; + + assign eu_direct_req_flat = eu_direct_req_cut.req; + assign eu_direct_addr_flat = eu_direct_req_cut.addr; + assign eu_direct_wen_flat = eu_direct_req_cut.wen; + assign eu_direct_wdata_flat = eu_direct_req_cut.wdata; + assign eu_direct_be_flat = eu_direct_req_cut.be; + assign eu_direct_rsp_cut.gnt = eu_direct_gnt_flat; + assign eu_direct_rsp_cut.rvalid = eu_direct_rvalid_flat; + assign eu_direct_rsp_cut.rdata = eu_direct_rdata_flat; + assign eu_direct_rsp_cut.err = eu_direct_err_flat; + + magia_tile_pkg::core_obi_data_req_t core_obi_data_req; + magia_tile_pkg::core_obi_data_rsp_t core_obi_data_rsp; + +`ifdef CV32E40X + cv32e40x_data2obi_req i_core_data2obi_req ( + .data_req_i ( core_data_slv_req[CoreDataObi] ), + .obi_req_o ( core_obi_data_req ) + ); + + cv32e40x_obi2data_rsp i_core_obi2data_rsp ( + .obi_rsp_i ( core_obi_data_rsp ), + .data_rsp_o ( core_data_slv_rsp[CoreDataObi] ) + ); +`else + cv32e40p_data2obi_req i_core_data2obi_req ( + .data_req_i ( core_data_slv_req[CoreDataObi] ), + .obi_req_o ( core_obi_data_req ) + ); + + cv32e40p_obi2data_rsp i_core_obi2data_rsp ( + .obi_rsp_i ( core_obi_data_rsp ), + .data_rsp_o ( core_data_slv_rsp[CoreDataObi] ) + ); +`endif + +/*******************************************************/ +/** Control Core Data Path End **/ +/*******************************************************/ +/** OBI Crossbar Beginning **/ +/*******************************************************/ + + // Managers, indexed by ObiMgr: core, ext, spatz, cluster cores + magia_tile_pkg::core_obi_data_req_t[ObiMgr.num_mgr-1:0] obi_xbar_slv_req; + magia_tile_pkg::core_obi_data_rsp_t[ObiMgr.num_mgr-1:0] obi_xbar_slv_rsp; + magia_tile_pkg::core_obi_data_req_t[ObiMgr.num_mgr-1:0] obi_xbar_slv_cut_req; + magia_tile_pkg::core_obi_data_rsp_t[ObiMgr.num_mgr-1:0] obi_xbar_slv_cut_rsp; + + // Subordinates, indexed by ObiSbr: l2, l1, eu, ctrl + magia_tile_pkg::core_obi_data_req_t[ObiSbr.num_sbr-1:0] core_mem_data_cut_req; + magia_tile_pkg::core_obi_data_rsp_t[ObiSbr.num_sbr-1:0] core_mem_data_cut_rsp; + magia_tile_pkg::core_obi_data_req_t[ObiSbr.num_sbr-1:0] core_mem_data_req; + magia_tile_pkg::core_obi_data_rsp_t[ObiSbr.num_sbr-1:0] core_mem_data_rsp; + + // Remote accesses from the AXI crossbar + magia_tile_pkg::core_obi_data_req_t ext_obi_data_req; + magia_tile_pkg::core_obi_data_rsp_t ext_obi_data_rsp; + + assign obi_xbar_slv_req[ObiMgr.core] = core_obi_data_req; + assign core_obi_data_rsp = obi_xbar_slv_rsp[ObiMgr.core]; + assign obi_xbar_slv_req[ObiMgr.ext] = ext_obi_data_req; + assign ext_obi_data_rsp = obi_xbar_slv_rsp[ObiMgr.ext]; + + localparam int unsigned RuleL2 = 0; + localparam int unsigned RuleL1 = 1; + localparam int unsigned RuleRes = 2; + localparam int unsigned RuleStack = 3; + localparam int unsigned RuleCtrl = 4; + localparam int unsigned RuleEu = 5; + localparam int unsigned RuleCtrlHi = 6; + + magia_tile_pkg::obi_xbar_rule_t[ObiSbr.num_rules-1:0] obi_xbar_rule; + logic[ObiMgr.num_mgr-1:0] obi_xbar_en_default_idx; + logic[ObiMgr.num_mgr-1:0][magia_tile_pkg::gen_idx_width(ObiSbr.num_sbr)-1:0] obi_xbar_default_idx; + + assign obi_xbar_rule[RuleL2] = '{idx: ObiSbr.l2, start_addr: magia_tile_pkg::L2_ADDR_START, end_addr: magia_tile_pkg::L2_ADDR_END }; + assign obi_xbar_rule[RuleL1] = '{idx: ObiSbr.l1, start_addr: tile_l1_start_addr, end_addr: tile_l1_end_addr }; + assign obi_xbar_rule[RuleRes] = '{idx: ObiSbr.l1, start_addr: magia_tile_pkg::RESERVED_ADDR_START, end_addr: magia_tile_pkg::RESERVED_ADDR_END }; + assign obi_xbar_rule[RuleStack] = '{idx: ObiSbr.l1, start_addr: magia_tile_pkg::STACK_ADDR_START, end_addr: magia_tile_pkg::STACK_ADDR_END }; + // The control window is split around the Event Unit: every address matches one rule + assign obi_xbar_rule[RuleCtrl] = '{idx: ObiSbr.ctrl, start_addr: magia_tile_pkg::TILE_PERIPH_BASE, end_addr: tile_event_unit_start_addr }; + assign obi_xbar_rule[RuleEu] = '{idx: ObiSbr.eu, start_addr: tile_event_unit_start_addr, end_addr: tile_event_unit_end_addr }; + assign obi_xbar_rule[RuleCtrlHi] = '{idx: ObiSbr.ctrl, start_addr: tile_event_unit_end_addr, end_addr: magia_tile_pkg::TILE_PERIPH_ADDR_END}; + + // Anything outside L1 and the peripheral window goes to the AXI crossbar + assign obi_xbar_en_default_idx = '1; + assign obi_xbar_default_idx = '0; + + // The core and the cluster cores enter the crossbar directly, ext and Spatz through a cut + assign obi_xbar_slv_cut_req[ObiMgr.core] = obi_xbar_slv_req[ObiMgr.core]; + assign obi_xbar_slv_rsp[ObiMgr.core] = obi_xbar_slv_cut_rsp[ObiMgr.core]; + + obi_cut #( + .ObiCfg ( magia_tile_pkg::obi_amo_cfg ), + .obi_a_chan_t ( magia_tile_pkg::core_data_obi_a_chan_t ), + .obi_r_chan_t ( magia_tile_pkg::core_data_obi_r_chan_t ), + .obi_req_t ( magia_tile_pkg::core_obi_data_req_t ), + .obi_rsp_t ( magia_tile_pkg::core_obi_data_rsp_t ) + ) i_obi_cut_ext ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .sbr_port_req_i ( obi_xbar_slv_req[ObiMgr.ext] ), + .sbr_port_rsp_o ( obi_xbar_slv_rsp[ObiMgr.ext] ), + .mgr_port_req_o ( obi_xbar_slv_cut_req[ObiMgr.ext] ), + .mgr_port_rsp_i ( obi_xbar_slv_cut_rsp[ObiMgr.ext] ) + ); + + if (TileCfg.EnSpatzCC) begin: gen_spatz_obi_cut + obi_cut #( + .ObiCfg ( magia_tile_pkg::obi_amo_cfg ), + .obi_a_chan_t ( magia_tile_pkg::core_data_obi_a_chan_t ), + .obi_r_chan_t ( magia_tile_pkg::core_data_obi_r_chan_t ), + .obi_req_t ( magia_tile_pkg::core_obi_data_req_t ), + .obi_rsp_t ( magia_tile_pkg::core_obi_data_rsp_t ) + ) i_obi_cut_spatz ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .sbr_port_req_i ( obi_xbar_slv_req[ObiMgr.spatz] ), + .sbr_port_rsp_o ( obi_xbar_slv_rsp[ObiMgr.spatz] ), + .mgr_port_req_o ( obi_xbar_slv_cut_req[ObiMgr.spatz] ), + .mgr_port_rsp_i ( obi_xbar_slv_cut_rsp[ObiMgr.spatz] ) + ); + end + + if (TileCfg.EnCluster) begin: gen_cluster_obi_passthrough + for (genvar idx_core = 0; idx_core < NClusterCores; idx_core++) begin: gen_cluster_obi_cut_bypass + assign obi_xbar_slv_cut_req[ObiMgr.cluster_base + idx_core] = obi_xbar_slv_req[ObiMgr.cluster_base + idx_core]; + assign obi_xbar_slv_rsp[ObiMgr.cluster_base + idx_core] = obi_xbar_slv_cut_rsp[ObiMgr.cluster_base + idx_core]; + end + end + + obi_xbar #( + .SbrPortObiCfg ( magia_tile_pkg::obi_amo_cfg ), + .MgrPortObiCfg ( ), + .sbr_port_obi_req_t ( magia_tile_pkg::core_obi_data_req_t ), + .sbr_port_a_chan_t ( magia_tile_pkg::core_data_obi_a_chan_t ), + .sbr_port_obi_rsp_t ( magia_tile_pkg::core_obi_data_rsp_t ), + .sbr_port_r_chan_t ( magia_tile_pkg::core_data_obi_r_chan_t ), + .mgr_port_obi_req_t ( ), + .mgr_port_obi_rsp_t ( ), + .NumSbrPorts ( ObiMgr.num_mgr ), + .NumMgrPorts ( ObiSbr.num_sbr ), + .NumMaxTrans ( magia_tile_pkg::N_MAX_TRAN ), + .NumAddrRules ( ObiSbr.num_rules ), + .addr_map_rule_t ( magia_tile_pkg::obi_xbar_rule_t ), + .UseIdForRouting ( ), + .Connectivity ( ) + ) i_obi_xbar ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .testmode_i ( test_mode_i ), + .sbr_ports_req_i ( obi_xbar_slv_cut_req ), + .sbr_ports_rsp_o ( obi_xbar_slv_cut_rsp ), + .mgr_ports_req_o ( core_mem_data_cut_req ), + .mgr_ports_rsp_i ( core_mem_data_cut_rsp ), + .addr_map_i ( obi_xbar_rule ), + .en_default_idx_i ( obi_xbar_en_default_idx ), + .default_idx_i ( obi_xbar_default_idx ) + ); + + for (genvar i = 0; i < ObiSbr.num_sbr; i++) begin: gen_obi_xbar_mgr_cut + obi_cut #( + .ObiCfg ( magia_tile_pkg::obi_amo_cfg ), + .obi_a_chan_t ( magia_tile_pkg::core_data_obi_a_chan_t ), + .obi_r_chan_t ( magia_tile_pkg::core_data_obi_r_chan_t ), + .obi_req_t ( magia_tile_pkg::core_obi_data_req_t ), + .obi_rsp_t ( magia_tile_pkg::core_obi_data_rsp_t ) + ) i_obi_xbar_mgr_cut ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .sbr_port_req_i ( core_mem_data_cut_req[i] ), + .sbr_port_rsp_o ( core_mem_data_cut_rsp[i] ), + .mgr_port_req_o ( core_mem_data_req[i] ), + .mgr_port_rsp_i ( core_mem_data_rsp[i] ) + ); + end + +/*******************************************************/ +/** OBI Crossbar End **/ +/*******************************************************/ +/** Event Unit Beginning **/ +/*******************************************************/ + + // Every event source drives its own slice in its section + magia_tile_pkg::eu_events_t eu_events; + logic eu_core_busy; + + // Event slots with no source + assign eu_events.timer = '0; + assign eu_events.acc[1] = 1'b0; + assign eu_events.other[11:0] = '0; + assign eu_events.other[22:13] = '0; + assign eu_events.other[27:25] = '0; + assign eu_events.other[31:30] = '0; + + assign eu_core_busy = ~core_sleep_o; + + magia_event_unit #( + .NB_CORES ( 1 ), + .NB_SW_EVT ( 1 ), + .NB_BARR ( 2 ), + .NB_HW_MUT ( 1 ), + .MUTEX_MSG_W ( 32 ), + .DISP_FIFO_DEPTH ( 1 ), + .EVNT_WIDTH ( 8 ), + .SOC_FIFO_DEPTH ( 8 ) + ) i_magia_event_unit ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .test_mode_i ( test_mode_i ), + + .acc_events_i ( eu_events.acc ), + .dma_events_i ( eu_events.dma ), + .timer_events_i ( eu_events.timer ), + .other_events_i ( eu_events.other ), + + // Pending events enabled in the EU IRQ mask + .core_irq_req_o ( eu_irq_req_o ), + .core_irq_id_o ( eu_irq_id_o ), + .core_irq_ack_i ( eu_irq_ack_i ), + .core_irq_ack_id_i ( eu_irq_ack_id_i ), + + .core_busy_i ( eu_core_busy ), + .core_clock_en_o ( eu_core_clk_en ), + + .dbg_req_i ( '0 ), + .core_dbg_req_o ( ), + + .eu_direct_req_i ( eu_direct_req_flat ), + .eu_direct_addr_i ( eu_direct_addr_flat ), + .eu_direct_wen_i ( eu_direct_wen_flat ), + .eu_direct_wdata_i ( eu_direct_wdata_flat ), + .eu_direct_be_i ( eu_direct_be_flat ), + .eu_direct_gnt_o ( eu_direct_gnt_flat ), + .eu_direct_rvalid_o ( eu_direct_rvalid_flat ), + .eu_direct_rdata_o ( eu_direct_rdata_flat ), + .eu_direct_err_o ( eu_direct_err_flat ), + + .obi_req_i ( core_mem_data_req[ObiSbr.eu] ), + .obi_rsp_o ( core_mem_data_rsp[ObiSbr.eu] ) + ); + +/*******************************************************/ +/** Event Unit End **/ +/*******************************************************/ +/** Control Registers Beginning **/ +/*******************************************************/ + + // One port per enabled control unit, indexed by CtrlMap + magia_tile_pkg::core_obi_data_req_t[CtrlMap.num_units-1:0] ctrl_req; + magia_tile_pkg::core_obi_data_rsp_t[CtrlMap.num_units-1:0] ctrl_rsp; + + ctrl_demux #( + .TileCfg ( TileCfg ) + ) i_ctrl_demux ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .obi_req_i ( core_mem_data_req[ObiSbr.ctrl] ), + .obi_rsp_o ( core_mem_data_rsp[ObiSbr.ctrl] ), + .unit_req_o ( ctrl_req ), + .unit_rsp_i ( ctrl_rsp ) + ); + + logic[31:0] collective_mask; + logic[3:0] collective_op; + + if (TileCfg.EnCollective) begin: gen_collective_ctrl + obi_slave_ctrl_coll #( + .BaseAddr ( magia_tile_pkg::COLL_CTRL_ADDR_START ) + ) i_collective_ctrl ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .obi_req_i ( ctrl_req[CtrlMap.coll] ), + .obi_rsp_o ( ctrl_rsp[CtrlMap.coll] ), + .collective_mask_o ( collective_mask ), + .collective_op_o ( collective_op ) + ); + end else begin: gen_no_collective_ctrl + assign collective_mask = '0; + assign collective_op = '0; + end + +/*******************************************************/ +/** Control Registers End **/ +/*******************************************************/ +/** AXI Crossbar and NoC Ports Beginning **/ +/*******************************************************/ + + magia_tile_pkg::core_axi_data_req_t core_l2_data_req; + magia_tile_pkg::core_axi_data_rsp_t core_l2_data_rsp; + + logic[magia_tile_pkg::AXI_DATA_U_W-1:0] axi_data_user; + logic[magia_tile_pkg::RUSER_WIDTH-1:0] obi_rsp_data_user; + + assign axi_data_user = '0; + assign obi_rsp_data_user = '0; + + obi_to_axi #( + .ObiCfg ( magia_tile_pkg::obi_amo_cfg ), + .obi_req_t ( magia_tile_pkg::core_obi_data_req_t ), + .obi_rsp_t ( magia_tile_pkg::core_obi_data_rsp_t ), + .AxiLite ( ), + .AxiAddrWidth ( magia_pkg::ADDR_W ), + .AxiDataWidth ( magia_pkg::DATA_W ), + .AxiUserWidth ( magia_tile_pkg::AXI_DATA_U_W ), + .AxiBurstType ( ), + .axi_req_t ( magia_tile_pkg::core_axi_data_req_t ), + .axi_rsp_t ( magia_tile_pkg::core_axi_data_rsp_t ), + .MaxRequests ( 1 ) + ) i_core_data_obi2axi ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .obi_req_i ( core_mem_data_req[ObiSbr.l2] ), + .obi_rsp_o ( core_mem_data_rsp[ObiSbr.l2] ), + .user_i ( axi_data_user ), + .axi_req_o ( core_l2_data_req ), + .axi_rsp_i ( core_l2_data_rsp ), + .axi_rsp_channel_sel ( ), + .axi_rsp_b_user_o ( ), + .axi_rsp_r_user_o ( ), + .obi_rsp_user_i ( obi_rsp_data_user ) + ); + + // Subordinate ports: core instr/data, NoC, Spatz and cluster i$ (see AXI_SLV_*_IDX) + magia_tile_pkg::axi_xbar_slv_req_t[magia_tile_pkg::AxiXbarNoSlvPorts-1:0] axi_xbar_slv_req; + magia_tile_pkg::axi_xbar_slv_rsp_t[magia_tile_pkg::AxiXbarNoSlvPorts-1:0] axi_xbar_slv_rsp; + // Manager ports: ext, OBI crossbar and Spatz bootrom (see AxiMst) + magia_pkg::axi_xbar_mst_req_t[AxiXbarCfg.NoMstPorts-1:0] axi_xbar_mst_req; + magia_pkg::axi_xbar_mst_rsp_t[AxiXbarCfg.NoMstPorts-1:0] axi_xbar_mst_rsp; + + axi_pkg::xbar_rule_32_t[AxiXbarCfg.NoAddrRules-1:0] axi_xbar_rule; + logic[AxiXbarCfg.NoSlvPorts-1:0] en_default_mst_port; + + assign axi_xbar_slv_req[magia_tile_pkg::AXI_SLV_CORE_DATA_IDX] = core_l2_data_req; + assign core_l2_data_rsp = axi_xbar_slv_rsp[magia_tile_pkg::AXI_SLV_CORE_DATA_IDX]; + assign axi_xbar_slv_req[magia_tile_pkg::AXI_SLV_CORE_INSTR_IDX] = core_l2_instr_req; + assign core_l2_instr_rsp = axi_xbar_slv_rsp[magia_tile_pkg::AXI_SLV_CORE_INSTR_IDX]; + assign axi_xbar_slv_req[magia_tile_pkg::AXI_SLV_EXT_IDX] = axi_narrow_slv_req_i; + assign axi_narrow_slv_rsp_o = axi_xbar_slv_rsp[magia_tile_pkg::AXI_SLV_EXT_IDX]; + + // Only non-NoC destinations need a rule: L2, other tiles and collectives take the default + assign axi_xbar_rule[0] = '{idx: AxiMst.obi, start_addr: tile_l1_start_addr, end_addr: tile_l1_end_addr}; + if (TileCfg.EnSpatzCC) begin: gen_axi_bootrom_rule + assign axi_xbar_rule[1] = '{idx: AxiMst.bootrom, start_addr: magia_tile_pkg::SPATZ_BOOT_ADDR, end_addr: magia_tile_pkg::SPATZ_BOOT_ADDR + magia_tile_pkg::SPATZ_BOOTROM_SIZE}; + end + + // Other tiles and unmapped addresses go to the NoC; AxiConnectivity stops NoC traffic looping + assign en_default_mst_port = '1; + +`ifndef SYNTHESIS + for (genvar i = 0; i < AxiXbarCfg.NoSlvPorts; i++) begin: gen_decerr_assert + assert property (@(posedge sys_clk) disable iff (!rst_ni) + !(axi_xbar_slv_rsp[i].b_valid && axi_xbar_slv_rsp[i].b.resp == axi_pkg::RESP_DECERR)) + else $fatal(1, "magia_isle: write to unmapped address from AXI port %0d (axi_xbar_slv_idx_e)", i); + assert property (@(posedge sys_clk) disable iff (!rst_ni) + !(axi_xbar_slv_rsp[i].r_valid && axi_xbar_slv_rsp[i].r.resp == axi_pkg::RESP_DECERR)) + else $fatal(1, "magia_isle: read from unmapped address from AXI port %0d (axi_xbar_slv_idx_e)", i); + end +`endif + + axi_xbar #( + .Cfg ( AxiXbarCfg ), + .ATOPs ( ), + .Connectivity ( AxiConnectivity ), + .slv_aw_chan_t ( magia_tile_pkg::axi_xbar_slv_aw_chan_t ), + .mst_aw_chan_t ( magia_pkg::axi_xbar_mst_aw_chan_t ), + .w_chan_t ( magia_pkg::axi_xbar_mst_w_chan_t ), + .slv_b_chan_t ( magia_tile_pkg::axi_xbar_slv_b_chan_t ), + .mst_b_chan_t ( magia_pkg::axi_xbar_mst_b_chan_t ), + .slv_ar_chan_t ( magia_tile_pkg::axi_xbar_slv_ar_chan_t ), + .mst_ar_chan_t ( magia_pkg::axi_xbar_mst_ar_chan_t ), + .slv_r_chan_t ( magia_tile_pkg::axi_xbar_slv_r_chan_t ), + .mst_r_chan_t ( magia_pkg::axi_xbar_mst_r_chan_t ), + .slv_req_t ( magia_tile_pkg::axi_xbar_slv_req_t ), + .mst_req_t ( magia_pkg::axi_xbar_mst_req_t ), + .slv_resp_t ( magia_tile_pkg::axi_xbar_slv_rsp_t ), + .mst_resp_t ( magia_pkg::axi_xbar_mst_rsp_t ), + .rule_t ( axi_pkg::xbar_rule_32_t ) + ) i_axi_xbar ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .test_i ( test_mode_i ), + .slv_ports_req_i ( axi_xbar_slv_req ), + .slv_ports_resp_o ( axi_xbar_slv_rsp ), + .mst_ports_req_o ( axi_xbar_mst_req ), + .mst_ports_resp_i ( axi_xbar_mst_rsp ), + .addr_map_i ( axi_xbar_rule ), + .en_default_mst_port_i ( en_default_mst_port ), + .default_mst_port_i ( '0 ) + ); + + // Writes to the collective window get the mask and op from the collective registers + if (TileCfg.EnCollective) begin: gen_collective_gen + collective_gen i_coll_gen ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .collective_mask_i ( collective_mask ), + .collective_op_i ( collective_op ), + .data_req_i ( axi_xbar_mst_req[AxiMst.ext] ), + .data_req_o ( axi_narrow_mst_req_o ) + ); + end else begin: gen_no_collective_gen + assign axi_narrow_mst_req_o = axi_xbar_mst_req[AxiMst.ext]; + end + + assign axi_xbar_mst_rsp[AxiMst.ext] = axi_narrow_mst_rsp_i; + + // Remote accesses to this tile's L1 and reserved region reach the OBI crossbar + logic[magia_tile_pkg::AID_WIDTH-1:0] axi2obi_req_write_aid; + logic[magia_tile_pkg::AUSER_WIDTH-1:0] axi2obi_req_write_auser; + logic[magia_tile_pkg::WUSER_WIDTH-1:0] axi2obi_req_write_wuser; + logic[magia_tile_pkg::AID_WIDTH-1:0] axi2obi_req_read_aid; + logic[magia_tile_pkg::AUSER_WIDTH-1:0] axi2obi_req_read_auser; + logic[magia_pkg::AXI_NOC_U_W-1:0] axi2obi_rsp_b_user; + logic[magia_pkg::AXI_NOC_U_W-1:0] axi2obi_rsp_r_user; + + assign axi2obi_req_write_aid = '0; + assign axi2obi_req_write_auser = '0; + assign axi2obi_req_write_wuser = '0; + assign axi2obi_req_read_aid = '0; + assign axi2obi_req_read_auser = '0; + assign axi2obi_rsp_b_user = '0; + assign axi2obi_rsp_r_user = '0; + + axi_to_obi #( + .ObiCfg ( magia_tile_pkg::obi_amo_cfg ), + .obi_req_t ( magia_tile_pkg::core_obi_data_req_t ), + .obi_rsp_t ( magia_tile_pkg::core_obi_data_rsp_t ), + .obi_a_chan_t ( magia_tile_pkg::core_data_obi_a_chan_t ), + .obi_r_chan_t ( magia_tile_pkg::core_data_obi_r_chan_t ), + .AxiAddrWidth ( magia_pkg::ADDR_W ), + .AxiDataWidth ( magia_pkg::DATA_W ), + .AxiIdWidth ( magia_pkg::AXI_NOC_ID_W ), + .AxiUserWidth ( magia_pkg::AXI_NOC_U_W ), + .MaxTrans ( 8 ), + .axi_req_t ( magia_pkg::axi_xbar_mst_req_t ), + .axi_rsp_t ( magia_pkg::axi_xbar_mst_rsp_t ) + ) i_ext_data_axi2obi ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .testmode_i ( test_mode_i ), + .axi_req_i ( axi_xbar_mst_req[AxiMst.obi] ), + .axi_rsp_o ( axi_xbar_mst_rsp[AxiMst.obi] ), + .obi_req_o ( ext_obi_data_req ), + .obi_rsp_i ( ext_obi_data_rsp ), + .req_aw_id_o ( ), + .req_aw_user_o ( ), + .req_w_user_o ( ), + .req_write_aid_i ( axi2obi_req_write_aid ), + .req_write_auser_i ( axi2obi_req_write_auser ), + .req_write_wuser_i ( axi2obi_req_write_wuser ), + .req_ar_id_o ( ), + .req_ar_user_o ( ), + .req_read_aid_i ( axi2obi_req_read_aid ), + .req_read_auser_i ( axi2obi_req_read_auser ), + .rsp_write_aw_user_o ( ), + .rsp_write_w_user_o ( ), + .rsp_write_bank_strb_o ( ), + .rsp_write_rid_o ( ), + .rsp_write_ruser_o ( ), + .rsp_write_last_o ( ), + .rsp_write_hs_o ( ), + .rsp_b_user_i ( axi2obi_rsp_b_user ), + .rsp_read_ar_user_o ( ), + .rsp_read_size_enable_o ( ), + .rsp_read_rid_o ( ), + .rsp_read_ruser_o ( ), + .rsp_r_user_i ( axi2obi_rsp_r_user ) + ); + +/*******************************************************/ +/** AXI Crossbar and NoC Ports End **/ +/*******************************************************/ +/** L1 Memory Beginning **/ +/*******************************************************/ + + localparam hci_package::hci_size_parameter_t `HCI_SIZE_PARAM(hci_tcdm_sram_if) = '{ + DW: magia_tile_pkg::DW_LIC, + AW: L1BankAddrW, + BW: hci_package::DEFAULT_BW, + UW: magia_tile_pkg::UW_LIC, + IW: TileIW, + EW: hci_package::DEFAULT_EW, + EHW: hci_package::DEFAULT_EHW + }; + `HCI_INTF_ARRAY(hci_tcdm_sram_if, sys_clk, 0:NumMemBanks-1); + + // Core ports: [0] control core, then Spatz, then cluster cores + localparam hci_package::hci_size_parameter_t `HCI_SIZE_PARAM(hci_core_if) = '{ + DW: magia_tile_pkg::DW_LIC, + AW: magia_tile_pkg::AWC, + BW: magia_pkg::BYTE_W, + UW: magia_tile_pkg::UW_LIC, + IW: TileIW, + EW: hci_package::DEFAULT_EW, + EHW: hci_package::DEFAULT_EHW + }; + `HCI_INTF_ARRAY(hci_core_if, sys_clk, 0:NumHciCore-1); + + localparam hci_package::hci_size_parameter_t `HCI_SIZE_PARAM(hci_redmule_if) = '{ + DW: RedmuleDataW, + AW: magia_tile_pkg::AWH, + BW: hci_package::DEFAULT_BW, + UW: magia_tile_pkg::REDMULE_UW, + IW: TileIW, + EW: hci_package::DEFAULT_EW, + EHW: hci_package::DEFAULT_EHW + }; + `HCI_INTF_ARRAY(hci_redmule_if, sys_clk, 0:NumHwpe-1); + + localparam hci_package::hci_size_parameter_t `HCI_SIZE_PARAM(hci_dma_if) = '{ + DW: magia_tile_pkg::iDMA_DataWidth, + AW: magia_tile_pkg::iDMA_AddrWidth, + BW: hci_package::DEFAULT_BW, + UW: magia_tile_pkg::iDMA_UserWidth, + IW: TileIW, + EW: hci_package::DEFAULT_EW, + EHW: hci_package::DEFAULT_EHW + }; + `HCI_INTF_ARRAY(hci_dma_if, sys_clk, 0:NumDma-1); + + localparam hci_package::hci_size_parameter_t `HCI_SIZE_PARAM(hci_ext_if) = '{ + DW: magia_tile_pkg::DW_LIC, + AW: magia_tile_pkg::AWC, + BW: hci_package::DEFAULT_BW, + UW: magia_tile_pkg::UW_LIC, + IW: hci_package::DEFAULT_IW, + EW: hci_package::DEFAULT_EW, + EHW: hci_package::DEFAULT_EHW + }; + if (NumExt > 0) begin: gen_hci_ext_if + `HCI_INTF_ARRAY(hci_ext_if, sys_clk, 0:NumExt-1); + end + + // Control core L1 port: atomics are resolved before HCI + magia_tile_pkg::core_obi_data_req_t core_l1_data_amo_req; + magia_tile_pkg::core_obi_data_rsp_t core_l1_data_amo_rsp; + tile_hci_data_req_t core_l1_data_req; + tile_hci_data_rsp_t core_l1_data_rsp; + + obi_atop_resolver #( + .SbrPortObiCfg ( magia_tile_pkg::obi_amo_cfg ), + .MgrPortObiCfg ( obi_pkg::ObiDefaultConfig ), + .sbr_port_obi_req_t ( magia_tile_pkg::core_obi_data_req_t ), + .sbr_port_obi_rsp_t ( magia_tile_pkg::core_obi_data_rsp_t ), + .mgr_port_obi_req_t ( ), + .mgr_port_obi_rsp_t ( ), + .mgr_port_obi_a_optional_t ( magia_tile_pkg::core_data_obi_a_optional_t ), + .mgr_port_obi_r_optional_t ( magia_tile_pkg::core_data_obi_r_optional_t ), + .LrScEnable ( ), + .RegisterAmo ( magia_tile_pkg::RegisterAmo ) + ) i_obi_atomics ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .testmode_i ( test_mode_i ), + .sbr_port_req_i ( core_mem_data_req[ObiSbr.l1] ), + .sbr_port_rsp_o ( core_mem_data_rsp[ObiSbr.l1] ), + .mgr_port_req_o ( core_l1_data_amo_req ), + .mgr_port_rsp_i ( core_l1_data_amo_rsp ) + ); + + obi2hci_req #( + .obi_req_t ( magia_tile_pkg::core_obi_data_req_t ), + .hci_req_t ( tile_hci_data_req_t ) + ) i_core_data_obi2hci_req ( + .obi_req_i ( core_l1_data_amo_req ), + .hci_req_o ( core_l1_data_req ) + ); + + hci2obi_rsp #( + .hci_rsp_t ( tile_hci_data_rsp_t ), + .obi_rsp_t ( magia_tile_pkg::core_obi_data_rsp_t ) + ) i_core_data_hci2obi_rsp ( + .hci_rsp_i ( core_l1_data_rsp ), + .obi_rsp_o ( core_l1_data_amo_rsp ) + ); + + `HCI_ASSIGN_TO_INTF(hci_core_if[0], core_l1_data_req, core_l1_data_rsp) + + logic hci_clear; + hci_package::hci_interconnect_ctrl_t hci_ctrl; + + assign hci_clear = 1'b0; + assign hci_ctrl = '0; + + local_interconnect #( + .N_HWPE ( NumHwpe ), + .N_DMA ( NumDma ), + .N_CORE ( NumHciCore ), + .N_MEM ( NumMemBanks ), + .EXPFIFO ( magia_tile_pkg::EXPFIFO ), + .MEM_DATA_W ( magia_tile_pkg::DW_LIC ), + .MEM_ADDR_W ( L1BankAddrW ), + .MEM_BYTE_W ( magia_tile_pkg::BW_LIC ), + .MEM_USER_W ( magia_tile_pkg::UW_LIC ), + .MEM_ID_W ( TileIW ), + .HCI_SIZE_hwpe ( `HCI_SIZE_PARAM(hci_redmule_if) ), + .HCI_SIZE_dma ( `HCI_SIZE_PARAM(hci_dma_if) ), + .HCI_SIZE_core ( `HCI_SIZE_PARAM(hci_core_if) ), + .HCI_SIZE_mem ( `HCI_SIZE_PARAM(hci_tcdm_sram_if)) + ) i_local_interconnect ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .clear_i ( hci_clear ), + .ctrl_i ( hci_ctrl ), + .hwpe ( hci_redmule_if ), + .dma ( hci_dma_if ), + .core ( hci_core_if ), + .mem ( hci_tcdm_sram_if ) + ); + + l1_spm #( + .N_BANK ( NumMemBanks ), + .N_WORDS ( NumWordsBank ), + .DATA_W ( magia_pkg::DATA_W ), + .ID_W ( TileIW ), + .SIM_INIT ( "zeros" ) + ) i_l1_spm ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .tcdm_slave ( hci_tcdm_sram_if ) + ); + +`ifndef SYNTHESIS + // spatz_tcdm_addr_t is sized from the package-level L1 geometry, shared by all tiles + if (TileCfg.EnSpatzCC && + $clog2(NumMemBanks * NumWordsBank * magia_pkg::DATA_W / 8) > magia_tile_pkg::SPATZ_TCDM_ADDR_WIDTH) begin: gen_err_spatz_tcdm_addr_w + $fatal(1, "magia_isle: TileCfg.L1 (%0d banks x %0d words) exceeds SPATZ_TCDM_ADDR_WIDTH=%0d", + NumMemBanks, NumWordsBank, magia_tile_pkg::SPATZ_TCDM_ADDR_WIDTH); + end +`endif + +/*******************************************************/ +/** L1 Memory End **/ +/*******************************************************/ +/** iDMA Beginning **/ +/*******************************************************/ + + // "out": L1 to NoC, "in": NoC to L1 + magia_tile_pkg::idma_axi_req_t idma_axi_read_req_out; + magia_tile_pkg::idma_axi_rsp_t idma_axi_read_rsp_out; + magia_tile_pkg::idma_axi_req_t idma_axi_write_req_out; + magia_tile_pkg::idma_axi_rsp_t idma_axi_write_rsp_out; + magia_tile_pkg::idma_obi_req_t idma_obi_read_req_out; + magia_tile_pkg::idma_obi_rsp_t idma_obi_read_rsp_out; + magia_tile_pkg::idma_obi_req_t idma_obi_write_req_out; + magia_tile_pkg::idma_obi_rsp_t idma_obi_write_rsp_out; + + logic idma_clear; + logic idma_axi2obi_start; + logic idma_axi2obi_done; + logic idma_obi2axi_start; + logic idma_obi2axi_done; + + assign idma_clear = 1'b0; + + assign eu_events.dma[magia_tile_pkg::EU_DMA_A2O_DONE] = idma_axi2obi_done; + assign eu_events.dma[magia_tile_pkg::EU_DMA_O2A_DONE] = idma_obi2axi_done; + assign eu_events.other[magia_tile_pkg::EU_OTHER_A2O_START] = idma_axi2obi_start; + assign eu_events.other[magia_tile_pkg::EU_OTHER_O2A_START] = idma_obi2axi_start; + + idma_ctrl_mm #( + .ERROR_CAP ( TileCfg.IDma.ErrorCap ) + ) i_idma_ctrl_mm ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .test_en_i ( test_mode_i ), + .clear_i ( idma_clear ), + + .obi_req_i ( ctrl_req[CtrlMap.idma] ), + .obi_rsp_o ( ctrl_rsp[CtrlMap.idma] ), + + .axi_read_req_o ( idma_axi_read_req_out ), + .axi_read_rsp_i ( idma_axi_read_rsp_out ), + .axi_write_req_o ( idma_axi_write_req_out ), + .axi_write_rsp_i ( idma_axi_write_rsp_out ), + + .obi_read_req_o ( idma_obi_read_req_out ), + .obi_read_rsp_i ( idma_obi_read_rsp_out ), + .obi_write_req_o ( idma_obi_write_req_out ), + .obi_write_rsp_i ( idma_obi_write_rsp_out ), + + .irq_a2o_busy_o ( ), + .irq_a2o_start_o ( idma_axi2obi_start ), + .irq_a2o_done_o ( idma_axi2obi_done ), + .irq_a2o_error_o ( ), + .irq_o2a_busy_o ( ), + .irq_o2a_start_o ( idma_obi2axi_start ), + .irq_o2a_done_o ( idma_obi2axi_done ), + .irq_o2a_error_o ( ) + ); + + axi_rw_join #( + .axi_req_t ( magia_tile_pkg::idma_axi_req_t ), + .axi_resp_t ( magia_tile_pkg::idma_axi_rsp_t ) + ) i_axi_rw_join ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .slv_read_req_i ( idma_axi_read_req_out ), + .slv_read_resp_o ( idma_axi_read_rsp_out ), + .slv_write_req_i ( idma_axi_write_req_out ), + .slv_write_resp_o ( idma_axi_write_rsp_out ), + .mst_req_o ( axi_wide_mst_req_o ), + .mst_resp_i ( axi_wide_mst_rsp_i ) + ); + + magia_tile_pkg::idma_axi_req_t idma_axi_read_req_in; + magia_tile_pkg::idma_axi_rsp_t idma_axi_read_rsp_in; + magia_tile_pkg::idma_axi_req_t idma_axi_write_req_in; + magia_tile_pkg::idma_axi_rsp_t idma_axi_write_rsp_in; + magia_tile_pkg::idma_obi_req_t idma_obi_read_req_in; + magia_tile_pkg::idma_obi_rsp_t idma_obi_read_rsp_in; + magia_tile_pkg::idma_obi_req_t idma_obi_write_req_in; + magia_tile_pkg::idma_obi_rsp_t idma_obi_write_rsp_in; + + axi_rw_split #( + .axi_req_t ( magia_tile_pkg::idma_axi_req_t ), + .axi_resp_t ( magia_tile_pkg::idma_axi_rsp_t ) + ) i_axi_rw_split ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .slv_req_i ( axi_wide_slv_req_i ), + .slv_resp_o ( axi_wide_slv_rsp_o ), + .mst_read_req_o ( idma_axi_read_req_in ), + .mst_read_resp_i ( idma_axi_read_rsp_in ), + .mst_write_req_o ( idma_axi_write_req_in ), + .mst_write_resp_i ( idma_axi_write_rsp_in ) + ); + + axi_to_obi #( + .ObiCfg ( magia_tile_pkg::obi_idma_cfg ), + .obi_req_t ( magia_tile_pkg::idma_obi_req_t ), + .obi_rsp_t ( magia_tile_pkg::idma_obi_rsp_t ), + .obi_a_chan_t ( magia_tile_pkg::idma_obi_a_chan_t ), + .obi_r_chan_t ( magia_tile_pkg::idma_obi_r_chan_t ), + .AxiAddrWidth ( iDMA_AddrWidth ), + .AxiDataWidth ( iDMA_DataWidth ), + .AxiIdWidth ( iDMA_AxiIdWidth ), + .AxiUserWidth ( iDMA_UserWidth ), + .MaxTrans ( 8 ), + .axi_req_t ( magia_tile_pkg::idma_axi_req_t ), + .axi_rsp_t ( magia_tile_pkg::idma_axi_rsp_t ) + ) i_idma_read_in_axi2obi ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .testmode_i ( test_mode_i ), + .axi_req_i ( idma_axi_read_req_in ), + .axi_rsp_o ( idma_axi_read_rsp_in ), + .obi_req_o ( idma_obi_read_req_in ), + .obi_rsp_i ( idma_obi_read_rsp_in ), + .req_aw_id_o ( ), + .req_aw_user_o ( ), + .req_w_user_o ( ), + .req_write_aid_i ( '0 ), + .req_write_auser_i ( '0 ), + .req_write_wuser_i ( '0 ), + .req_ar_id_o ( ), + .req_ar_user_o ( ), + .req_read_aid_i ( '0 ), + .req_read_auser_i ( '0 ), + .rsp_write_aw_user_o ( ), + .rsp_write_w_user_o ( ), + .rsp_write_bank_strb_o ( ), + .rsp_write_rid_o ( ), + .rsp_write_ruser_o ( ), + .rsp_write_last_o ( ), + .rsp_write_hs_o ( ), + .rsp_b_user_i ( '0 ), + .rsp_read_ar_user_o ( ), + .rsp_read_size_enable_o ( ), + .rsp_read_rid_o ( ), + .rsp_read_ruser_o ( ), + .rsp_r_user_i ( '0 ) + ); + + axi_to_obi #( + .ObiCfg ( magia_tile_pkg::obi_idma_cfg ), + .obi_req_t ( magia_tile_pkg::idma_obi_req_t ), + .obi_rsp_t ( magia_tile_pkg::idma_obi_rsp_t ), + .obi_a_chan_t ( magia_tile_pkg::idma_obi_a_chan_t ), + .obi_r_chan_t ( magia_tile_pkg::idma_obi_r_chan_t ), + .AxiAddrWidth ( iDMA_AddrWidth ), + .AxiDataWidth ( iDMA_DataWidth ), + .AxiIdWidth ( iDMA_AxiIdWidth ), + .AxiUserWidth ( iDMA_UserWidth ), + .MaxTrans ( 8 ), + .axi_req_t ( magia_tile_pkg::idma_axi_req_t ), + .axi_rsp_t ( magia_tile_pkg::idma_axi_rsp_t ) + ) i_idma_write_in_axi2obi ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .testmode_i ( test_mode_i ), + .axi_req_i ( idma_axi_write_req_in ), + .axi_rsp_o ( idma_axi_write_rsp_in ), + .obi_req_o ( idma_obi_write_req_in ), + .obi_rsp_i ( idma_obi_write_rsp_in ), + .req_aw_id_o ( ), + .req_aw_user_o ( ), + .req_w_user_o ( ), + .req_write_aid_i ( '0 ), + .req_write_auser_i ( '0 ), + .req_write_wuser_i ( '0 ), + .req_ar_id_o ( ), + .req_ar_user_o ( ), + .req_read_aid_i ( '0 ), + .req_read_auser_i ( '0 ), + .rsp_write_aw_user_o ( ), + .rsp_write_w_user_o ( ), + .rsp_write_bank_strb_o ( ), + .rsp_write_rid_o ( ), + .rsp_write_ruser_o ( ), + .rsp_write_last_o ( ), + .rsp_write_hs_o ( ), + .rsp_b_user_i ( '0 ), + .rsp_read_ar_user_o ( ), + .rsp_read_size_enable_o ( ), + .rsp_read_rid_o ( ), + .rsp_read_ruser_o ( ), + .rsp_r_user_i ( '0 ) + ); + + // Four L1 channels: out/in times read/write + tile_idma_hci_req_t idma_hci_read_req_out; + tile_idma_hci_rsp_t idma_hci_read_rsp_out; + tile_idma_hci_req_t idma_hci_write_req_out; + tile_idma_hci_rsp_t idma_hci_write_rsp_out; + tile_idma_hci_req_t idma_hci_read_req_in; + tile_idma_hci_rsp_t idma_hci_read_rsp_in; + tile_idma_hci_req_t idma_hci_write_req_in; + tile_idma_hci_rsp_t idma_hci_write_rsp_in; + + obi2hci_req #( + .obi_req_t ( magia_tile_pkg::idma_obi_req_t ), + .hci_req_t ( tile_idma_hci_req_t ) + ) i_idma_out_obi2hci_req ( + .obi_req_i ( idma_obi_read_req_out ), + .hci_req_o ( idma_hci_read_req_out ) + ); + + hci2obi_rsp #( + .hci_rsp_t ( tile_idma_hci_rsp_t ), + .obi_rsp_t ( magia_tile_pkg::idma_obi_rsp_t ) + ) i_idma_out_hci2obi_rsp ( + .hci_rsp_i ( idma_hci_read_rsp_out ), + .obi_rsp_o ( idma_obi_read_rsp_out ) + ); + + obi2hci_req #( + .obi_req_t ( magia_tile_pkg::idma_obi_req_t ), + .hci_req_t ( tile_idma_hci_req_t ) + ) i_idma_out_obi2hci_write_req ( + .obi_req_i ( idma_obi_write_req_out ), + .hci_req_o ( idma_hci_write_req_out ) + ); + + hci2obi_rsp #( + .hci_rsp_t ( tile_idma_hci_rsp_t ), + .obi_rsp_t ( magia_tile_pkg::idma_obi_rsp_t ) + ) i_idma_out_hci2obi_write_rsp ( + .hci_rsp_i ( idma_hci_write_rsp_out ), + .obi_rsp_o ( idma_obi_write_rsp_out ) + ); + + obi2hci_req #( + .obi_req_t ( magia_tile_pkg::idma_obi_req_t ), + .hci_req_t ( tile_idma_hci_req_t ) + ) i_idma_in_obi2hci_req ( + .obi_req_i ( idma_obi_read_req_in ), + .hci_req_o ( idma_hci_read_req_in ) + ); + + hci2obi_rsp #( + .hci_rsp_t ( tile_idma_hci_rsp_t ), + .obi_rsp_t ( magia_tile_pkg::idma_obi_rsp_t ) + ) i_idma_in_hci2obi_rsp ( + .hci_rsp_i ( idma_hci_read_rsp_in ), + .obi_rsp_o ( idma_obi_read_rsp_in ) + ); + + obi2hci_req #( + .obi_req_t ( magia_tile_pkg::idma_obi_req_t ), + .hci_req_t ( tile_idma_hci_req_t ) + ) i_idma_in_obi2hci_write_req ( + .obi_req_i ( idma_obi_write_req_in ), + .hci_req_o ( idma_hci_write_req_in ) + ); + + hci2obi_rsp #( + .hci_rsp_t ( tile_idma_hci_rsp_t ), + .obi_rsp_t ( magia_tile_pkg::idma_obi_rsp_t ) + ) i_idma_in_hci2obi_write_rsp ( + .hci_rsp_i ( idma_hci_write_rsp_in ), + .obi_rsp_o ( idma_obi_write_rsp_in ) + ); + + `HCI_ASSIGN_TO_INTF(hci_dma_if[magia_tile_pkg::HCI_DMA_OUT_CH_READ_IDX], idma_hci_read_req_out, idma_hci_read_rsp_out) + `HCI_ASSIGN_TO_INTF(hci_dma_if[magia_tile_pkg::HCI_DMA_OUT_CH_WRITE_IDX], idma_hci_write_req_out, idma_hci_write_rsp_out) + `HCI_ASSIGN_TO_INTF(hci_dma_if[magia_tile_pkg::HCI_DMA_IN_CH_READ_IDX], idma_hci_read_req_in, idma_hci_read_rsp_in) + `HCI_ASSIGN_TO_INTF(hci_dma_if[magia_tile_pkg::HCI_DMA_IN_CH_WRITE_IDX], idma_hci_write_req_in, idma_hci_write_rsp_in) + +/*******************************************************/ +/** iDMA End **/ +/*******************************************************/ +/** RedMulE Beginning **/ +/*******************************************************/ + + if (TileCfg.EnRedMule) begin: gen_redmule + magia_tile_pkg::redmule_ctrl_req_t redmule_ctrl_req; + magia_tile_pkg::redmule_ctrl_rsp_t redmule_ctrl_rsp; + tile_redmule_data_req_t redmule_data_req; + tile_redmule_data_rsp_t redmule_data_rsp; + magia_tile_pkg::redmule_events_t redmule_events; + + assign redmule_events.evt[1] = 1'b0; + + assign eu_events.acc[magia_tile_pkg::EU_ACC_REDMULE_EVT_0] = redmule_events.evt[0]; + assign eu_events.acc[magia_tile_pkg::EU_ACC_REDMULE_EVT_1] = redmule_events.evt[1]; + + obi2hwpe_ctrl obi2hwpe_ctrl_inst ( + .obi_req_i ( ctrl_req[CtrlMap.redmule] ), + .obi_rsp_o ( ctrl_rsp[CtrlMap.redmule] ), + .ctrl_req_o ( redmule_ctrl_req ), + .ctrl_rsp_i ( redmule_ctrl_rsp ) + ); + + `HCI_ASSIGN_TO_INTF(hci_redmule_if[0], redmule_data_req, redmule_data_rsp) + + magia_redmule_wrap #( + .CtrlIntfConfig ( redmule_pkg::HWPE_TARGET ), + .DataW ( RedmuleDataW ), + .Height ( TileCfg.RedMule.Height ), + .Width ( TileCfg.RedMule.Width ), + .NumPipeRegs ( TileCfg.RedMule.NumPipeRegs ), + .redmule_data_req_t ( tile_redmule_data_req_t ), + .redmule_data_rsp_t ( tile_redmule_data_rsp_t ), + .`HCI_SIZE_PARAM(tcdm) ( `HCI_SIZE_PARAM(hci_redmule_if) ) + ) i_redmule_wrap ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .test_mode_i ( test_mode_i ), + + .busy_o ( ), + .evt_o ( redmule_events.evt[0] ), + + // Xif ports are unused in HWPE mode + .x_issue_req_i ( ), + .x_issue_resp_o ( ), + .x_issue_valid_i ( 1'b0 ), + .x_issue_ready_o ( ), + .x_register_i ( ), + .x_register_valid_i ( 1'b0 ), + .x_register_ready_o ( ), + .x_commit_i ( ), + .x_commit_valid_i ( 1'b0 ), + .x_result_o ( ), + .x_result_valid_o ( ), + .x_result_ready_i ( 1'b0 ), + + .data_req_o ( redmule_data_req ), + .data_rsp_i ( redmule_data_rsp ), + .ctrl_req_i ( redmule_ctrl_req ), + .ctrl_rsp_o ( redmule_ctrl_rsp ) + ); + end else begin: gen_no_redmule + tile_redmule_data_req_t redmule_data_req_quiet; + tile_redmule_data_rsp_t redmule_data_rsp_unused; + + // The HWPE port stays: local_interconnect needs at least one + assign redmule_data_req_quiet = '0; + `HCI_ASSIGN_TO_INTF(hci_redmule_if[0], redmule_data_req_quiet, redmule_data_rsp_unused) + + assign eu_events.acc[magia_tile_pkg::EU_ACC_REDMULE_EVT_1 : + magia_tile_pkg::EU_ACC_REDMULE_EVT_0] = '0; + end + +/*******************************************************/ +/** RedMulE End **/ +/*******************************************************/ +/** FractalSync Beginning **/ +/*******************************************************/ + +`ifdef MAGIA_FSYNC + logic fsync_done; + + assign eu_events.other[magia_tile_pkg::EU_OTHER_FSYNC_DONE] = fsync_done; + + obi_slave_fsync #( + .BASE_ADDR ( magia_tile_pkg::FSYNC_CTRL_ADDR_START ), + .AGGR_W ( magia_tile_pkg::FSYNC_AGGR_W ), + .ID_W ( magia_tile_pkg::FSYNC_ID_W ), + .NBR_AGGR_W ( magia_tile_pkg::FSYNC_NBR_AGGR_W ), + .NBR_ID_W ( magia_tile_pkg::FSYNC_NBR_ID_W ) + ) i_fsync_mm ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .clear_i ( 1'b0 ), + .obi_req_i ( ctrl_req[CtrlMap.fsync] ), + .obi_rsp_o ( ctrl_rsp[CtrlMap.fsync] ), + .ht_fsync_if_o ( ht_fsync_if_o ), + .hn_fsync_if_o ( hn_fsync_if_o ), + .vt_fsync_if_o ( vt_fsync_if_o ), + .vn_fsync_if_o ( vn_fsync_if_o ), + .done_o ( fsync_done ), + .error_o ( ) + ); +`else + assign eu_events.other[magia_tile_pkg::EU_OTHER_FSYNC_DONE] = 1'b0; +`endif + +/*******************************************************/ +/** FractalSync End **/ +/*******************************************************/ +/** Spatz CC Beginning **/ +/*******************************************************/ + + if (TileCfg.EnSpatzCC) begin: gen_spatz_cc + logic spatz_clk_en; + logic spatz_start; + logic spatz_done; + logic spatz_clk; + + obi_slave_ctrl_spatz #( + .BaseAddr ( magia_tile_pkg::SPATZ_CTRL_ADDR_START ) + ) i_spatz_csr ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .obi_req_i ( ctrl_req[CtrlMap.spatz] ), + .obi_rsp_o ( ctrl_rsp[CtrlMap.spatz] ), + .clk_en_o ( spatz_clk_en ), + .start_o ( spatz_start ), + .done_o ( spatz_done ) + ); + + assign eu_events.acc [magia_tile_pkg::EU_ACC_SPATZ_DONE] = spatz_done; + assign eu_events.other[magia_tile_pkg::EU_OTHER_SPATZ_START] = spatz_start; + + tc_clk_gating spatz_clock_gating ( + .clk_i ( sys_clk ), + .en_i ( spatz_clk_en ), + .test_en_i ( test_mode_i ), + .clk_o ( spatz_clk ) + ); + + magia_tile_pkg::core_obi_data_req_t spatz_obi_req; + magia_tile_pkg::core_obi_data_rsp_t spatz_obi_rsp; + + assign obi_xbar_slv_req[ObiMgr.spatz] = spatz_obi_req; + assign spatz_obi_rsp = obi_xbar_slv_rsp[ObiMgr.spatz]; + + tile_hci_data_req_t [NumSpatzHciPorts-1:0] spatz_hci_req; + tile_hci_data_rsp_t [NumSpatzHciPorts-1:0] spatz_hci_rsp; + + for (genvar i = 0; i < NumSpatzHciPorts; i++) begin: gen_spatz_hci_assign + `HCI_ASSIGN_TO_INTF(hci_core_if[i+1], spatz_hci_req[i], spatz_hci_rsp[i]) + end + + logic spatz_inst_req; + logic [31:0] spatz_inst_addr; + logic spatz_inst_cacheable; + logic spatz_flush_i_valid; + logic [31:0] spatz_inst_data; + logic spatz_inst_ready; + logic spatz_inst_error; + logic spatz_flush_i_ready; + + // The Spatz CSR start pulse is the only interrupt source + snitch_pkg::interrupts_t spatz_irq; + + assign spatz_irq.msip = 1'b0; + assign spatz_irq.mtip = 1'b0; + assign spatz_irq.meip = spatz_start; + assign spatz_irq.mcip = 1'b0; + assign spatz_irq.debug = 1'b0; + + spatz_cc_wrapper #( + .SnitchPMACfg ( SpatzPmaCfg ), + .AddrWidth ( magia_pkg::ADDR_W ), + .DataWidth ( magia_tile_pkg::SPATZ_TCDM_DATA_WIDTH ), + .NumSpatzFPUs ( TileCfg.Spatz.NumFPU ), + .NumSpatzIPUs ( TileCfg.Spatz.NumIPU ), + .BootAddr ( magia_tile_pkg::SPATZ_BOOT_ADDR ), + .RVF ( TileCfg.Spatz.RVF ), + .RVD ( TileCfg.Spatz.RVD ), + .RVV ( TileCfg.Spatz.RVV ), + .XDivSqrt ( TileCfg.Spatz.XDivSqrt ), + .FPUImplementation ( magia_tile_pkg::SPATZ_FPUImplementation ), + .hci_req_t ( tile_hci_data_req_t ), + .hci_rsp_t ( tile_hci_data_rsp_t ) + ) i_spatz_cc_core ( + .clk_i ( spatz_clk ), + .rst_ni ( rst_ni ), + .test_mode_i ( test_mode_i ), + + .hart_id_i ( 32'(HartIdBase) + mhartid_i ), + .tcdm_addr_base_i ( tile_l1_start_addr ), + + .irq_i ( spatz_irq ), + + .hci_master_req_o ( spatz_hci_req ), + .hci_master_rsp_i ( spatz_hci_rsp ), + + .obi_master_req_o ( spatz_obi_req ), + .obi_master_rsp_i ( spatz_obi_rsp ), + + .inst_req_o ( spatz_inst_req ), + .inst_addr_o ( spatz_inst_addr ), + .inst_cacheable_o ( spatz_inst_cacheable ), + .flush_i_valid_o ( spatz_flush_i_valid ), + .inst_data_i ( spatz_inst_data ), + .inst_ready_i ( spatz_inst_ready ), + .inst_error_i ( spatz_inst_error ), + .flush_i_ready_i ( spatz_flush_i_ready ), + + .core_events_o ( ) + ); + + // Spatz i$ + logic spatz_enable_prefetching; + magia_tile_pkg::core_axi_instr_req_t spatz_icache_axi_req; + magia_tile_pkg::core_axi_instr_rsp_t spatz_icache_axi_rsp; + + assign spatz_enable_prefetching = 1'b0; + + assign axi_xbar_slv_req[magia_tile_pkg::AXI_SLV_SPATZ_INSTR_IDX] = spatz_icache_axi_req; + assign spatz_icache_axi_rsp = axi_xbar_slv_rsp[magia_tile_pkg::AXI_SLV_SPATZ_INSTR_IDX]; + + localparam int unsigned SpatzIcacheL0EarlyTagW = snitch_pkg::PAGE_SHIFT - $clog2(TileCfg.Spatz.ICacheLineWidth/8); + + snitch_icache #( + .NR_FETCH_PORTS ( 1 ), + .L0_LINE_COUNT ( TileCfg.Spatz.ICacheL0LineCount ), + .LINE_WIDTH ( TileCfg.Spatz.ICacheLineWidth ), + .LINE_COUNT ( TileCfg.Spatz.ICacheLineCount ), + .WAY_COUNT ( TileCfg.Spatz.ICacheWays ), + .FETCH_AW ( magia_pkg::ADDR_W ), + .FETCH_DW ( 32 ), + .FILL_AW ( magia_pkg::ADDR_W ), + .FILL_DW ( magia_pkg::DATA_W ), + .SERIAL_LOOKUP ( 0 ), + .L1_TAG_SCM ( 0 ), + .NUM_AXI_OUTSTANDING ( 2 ), + .EARLY_LATCH ( 0 ), + .L0_EARLY_TAG_WIDTH ( SpatzIcacheL0EarlyTagW ), + .ISO_CROSSING ( 1'b0 ), + .axi_req_t ( magia_tile_pkg::core_axi_instr_req_t ), + .axi_rsp_t ( magia_tile_pkg::core_axi_instr_rsp_t ) + ) i_spatz_cc_icache ( + .clk_i ( spatz_clk ), + .clk_d2_i ( spatz_clk ), + .rst_ni ( rst_ni ), + .enable_prefetching_i ( spatz_enable_prefetching ), + .icache_l0_events_o ( ), + .icache_l1_events_o ( ), + .flush_valid_i ( spatz_flush_i_valid ), + .flush_ready_o ( spatz_flush_i_ready ), + .inst_addr_i ( spatz_inst_addr ), + .inst_cacheable_i ( spatz_inst_cacheable ), + .inst_data_o ( spatz_inst_data ), + .inst_valid_i ( spatz_inst_req ), + .inst_ready_o ( spatz_inst_ready ), + .inst_error_o ( spatz_inst_error ), + .sram_cfg_tag_i ( '0 ), + .sram_cfg_data_i ( '0 ), + .axi_req_o ( spatz_icache_axi_req ), + .axi_rsp_i ( spatz_icache_axi_rsp ) + ); + + // Spatz bootrom, generated from spatz_init.S, behind an AXI-to-regbus bridge + magia_tile_pkg::reg_dma_req_t bootrom_reg_req; + magia_tile_pkg::reg_dma_rsp_t bootrom_reg_rsp; + + axi_to_reg_v2 #( + .AxiAddrWidth ( magia_pkg::ADDR_W ), + .AxiDataWidth ( magia_pkg::DATA_W ), + .AxiIdWidth ( magia_pkg::AXI_NOC_ID_W ), + .AxiUserWidth ( magia_pkg::AXI_NOC_U_W ), + .RegDataWidth ( magia_pkg::DATA_W ), + .axi_req_t ( magia_pkg::axi_xbar_mst_req_t ), + .axi_rsp_t ( magia_pkg::axi_xbar_mst_rsp_t ), + .reg_req_t ( magia_tile_pkg::reg_dma_req_t ), + .reg_rsp_t ( magia_tile_pkg::reg_dma_rsp_t ) + ) i_axi_to_reg_bootrom ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .axi_req_i ( axi_xbar_mst_req[AxiMst.bootrom] ), + .axi_rsp_o ( axi_xbar_mst_rsp[AxiMst.bootrom] ), + .reg_req_o ( bootrom_reg_req ), + .reg_rsp_i ( bootrom_reg_rsp ), + .reg_id_o ( ), + .busy_o ( ) + ); + + spatz_bootrom i_spatz_bootrom ( + .clk_i ( sys_clk ), + .req_i ( bootrom_reg_req.valid ), + .addr_i ( bootrom_reg_req.addr ), + .rdata_o ( bootrom_reg_rsp.rdata ) + ); + + always_ff @(posedge sys_clk or negedge rst_ni) begin + if (!rst_ni) begin + bootrom_reg_rsp.ready <= 1'b0; + end else begin + bootrom_reg_rsp.ready <= bootrom_reg_req.valid; + end + end + + assign bootrom_reg_rsp.error = 1'b0; + end else begin: gen_no_spatz_cc + assign eu_events.acc [magia_tile_pkg::EU_ACC_SPATZ_DONE] = 1'b0; + assign eu_events.other[magia_tile_pkg::EU_OTHER_SPATZ_START] = 1'b0; + + assign axi_xbar_slv_req[magia_tile_pkg::AXI_SLV_SPATZ_INSTR_IDX] = '0; + end + +/*******************************************************/ +/** Spatz CC End **/ +/*******************************************************/ +/** PULP Cluster Beginning **/ +/*******************************************************/ + + if (TileCfg.EnCluster) begin: gen_pulp_cluster + localparam int unsigned ClusterIcacheL0LineCount = TileCfg.Cluster.IcachePrivateSize / (TileCfg.Cluster.IcacheLineWidth/8); + localparam int unsigned ClusterIcacheLineCount = TileCfg.Cluster.IcacheSharedSize / (TileCfg.Cluster.IcacheLineWidth/8) / TileCfg.Cluster.IcacheNumWays; + + logic [31:0] cluster_boot_addr [NClusterCores-1:0]; + logic [NClusterCores-1:0] cluster_clk_en; + logic [NClusterCores-1:0] cluster_fetch_enable; + logic [NClusterCores-1:0] cluster_start_irq; + logic cluster_done; + logic [NClusterCores-1:0] cluster_clk; + + obi_slave_ctrl_cluster #( + .TileCfg ( TileCfg ), + .BaseAddr ( magia_tile_pkg::CLUSTER_CTRL_ADDR_START ) + ) i_cluster_csr ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .obi_req_i ( ctrl_req[CtrlMap.cluster] ), + .obi_rsp_o ( ctrl_rsp[CtrlMap.cluster] ), + .clk_en_o ( cluster_clk_en ), + .boot_addr_o ( cluster_boot_addr ), + .fetch_en_o ( cluster_fetch_enable ), + .done_o ( cluster_done ), + .start_irq_o ( cluster_start_irq ) + ); + + assign eu_events.other[magia_tile_pkg::EU_OTHER_CLUSTER_DONE] = cluster_done; + + for (genvar j = 0; j < NClusterCores; j++) begin: gen_cluster_clk_gate + tc_clk_gating i_cluster_clk_gate ( + .clk_i ( sys_clk ), + .en_i ( cluster_clk_en[j] ), + .test_en_i ( test_mode_i ), + .clk_o ( cluster_clk[j] ) + ); + end + + // Each core reaches L1 through HCI and everything else through the OBI crossbar + magia_tile_pkg::core_obi_data_req_t [NClusterCores-1:0] cluster_obi_data_req; + magia_tile_pkg::core_obi_data_rsp_t [NClusterCores-1:0] cluster_obi_data_rsp; + tile_hci_data_req_t [NClusterCores-1:0] cluster_hci_data_req; + tile_hci_data_rsp_t [NClusterCores-1:0] cluster_hci_data_rsp; + magia_tile_pkg::core_instr_req_t [NClusterCores-1:0] cluster_instr_req; + magia_tile_pkg::core_instr_rsp_t [NClusterCores-1:0] cluster_instr_rsp; + + magia_cluster_wrap #( + .TileCfg ( TileCfg ), + .HartIdBase ( HartIdBase ), + .InstanceCount ( InstanceCount ), + .hci_req_t ( tile_hci_data_req_t ), + .hci_rsp_t ( tile_hci_data_rsp_t ) + ) i_cluster ( + .sys_clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .test_mode_i ( test_mode_i ), + .cluster_clk_i ( cluster_clk ), + .debug_req_i ( debug_req_i[NClusterCores:1] ), + .mhartid_i ( mhartid_i ), + .tcdm_rules_i ( tcdm_rules ), + .cluster_boot_addr_i ( cluster_boot_addr ), + .cluster_fetch_enable_i ( cluster_fetch_enable ), + .cluster_start_irq_i ( cluster_start_irq ), + .cluster_obi_data_req_o ( cluster_obi_data_req ), + .cluster_obi_data_rsp_i ( cluster_obi_data_rsp ), + .cluster_hci_data_req_o ( cluster_hci_data_req ), + .cluster_hci_data_rsp_i ( cluster_hci_data_rsp ), + .cluster_instr_req_o ( cluster_instr_req ), + .cluster_instr_rsp_i ( cluster_instr_rsp ) + ); + + for (genvar idx_core = 0; idx_core < NClusterCores; idx_core++) begin: gen_cluster_obi_port + assign obi_xbar_slv_req[ObiMgr.cluster_base + idx_core] = cluster_obi_data_req[idx_core]; + assign cluster_obi_data_rsp[idx_core] = obi_xbar_slv_rsp[ObiMgr.cluster_base + idx_core]; + end + + for (genvar idx_core = 0; idx_core < NClusterCores; idx_core++) begin: gen_cluster_hci_assign + `HCI_ASSIGN_TO_INTF(hci_core_if[1 + NumSpatzHciPorts + idx_core], cluster_hci_data_req[idx_core], cluster_hci_data_rsp[idx_core]) + end + + // Shared cluster i$ + logic [NClusterCores-1:0] cluster_cache_req; + logic [NClusterCores-1:0][magia_tile_pkg::CLUSTER_FETCH_AW-1:0] cluster_cache_addr; + logic [NClusterCores-1:0] cluster_cache_gnt; + logic [NClusterCores-1:0] cluster_cache_rvalid; + logic [NClusterCores-1:0][magia_tile_pkg::CLUSTER_FETCH_DW-1:0] cluster_cache_rdata; + logic [NClusterCores-1:0] cluster_cache_rerror; + + logic cluster_enable_prefetching; + logic [NClusterCores-1:0] cluster_icache_flush_valid; + + magia_tile_pkg::core_axi_instr_req_t cluster_l2_instr_req; + magia_tile_pkg::core_axi_instr_rsp_t cluster_l2_instr_rsp; + + assign cluster_enable_prefetching = 1'b0; + assign cluster_icache_flush_valid = '0; + + for (genvar i = 0; i < NClusterCores; i++) begin: gen_cluster_icache_assign + assign cluster_cache_req[i] = cluster_instr_req[i].req; + assign cluster_cache_addr[i] = cluster_instr_req[i].addr; + assign cluster_instr_rsp[i].gnt = cluster_cache_gnt[i]; + assign cluster_instr_rsp[i].rvalid = cluster_cache_rvalid[i]; + assign cluster_instr_rsp[i].rdata = cluster_cache_rdata[i]; + assign cluster_instr_rsp[i].err = cluster_cache_rerror[i]; + end + + assign axi_xbar_slv_req[magia_tile_pkg::AXI_SLV_CLUSTER_INSTR_IDX] = cluster_l2_instr_req; + assign cluster_l2_instr_rsp = axi_xbar_slv_rsp[magia_tile_pkg::AXI_SLV_CLUSTER_INSTR_IDX]; + + magia_tile_icache_wrap #( + .CachedRegionBase ( 32'(CodeRegionBase) ), + .CachedRegionMask ( CodeRegionMask ), + .NumFetchPorts ( NClusterCores ), + .L0_LINE_COUNT ( ClusterIcacheL0LineCount ), + .LINE_WIDTH ( TileCfg.Cluster.IcacheLineWidth ), + .LINE_COUNT ( ClusterIcacheLineCount ), + .WAY_COUNT ( TileCfg.Cluster.IcacheNumWays ), + .FetchAddrWidth ( magia_tile_pkg::CLUSTER_FETCH_AW ), + .FetchDataWidth ( magia_tile_pkg::CLUSTER_FETCH_DW ), + .AxiAddrWidth ( magia_tile_pkg::CLUSTER_FILL_AW ), + .AxiDataWidth ( magia_tile_pkg::CLUSTER_FILL_DW ) + ) cluster_icache_top_i ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .fetch_req_i ( cluster_cache_req ), + .fetch_addr_i ( cluster_cache_addr ), + .fetch_gnt_o ( cluster_cache_gnt ), + .fetch_rvalid_o ( cluster_cache_rvalid ), + .fetch_rdata_o ( cluster_cache_rdata ), + .fetch_rerror_o ( cluster_cache_rerror ), + + .enable_prefetching_i ( cluster_enable_prefetching ), + .icache_l0_events_o ( ), + .icache_l1_events_o ( ), + .flush_valid_i ( cluster_icache_flush_valid ), + .flush_ready_o ( ), + + .sram_cfg_data_i ( '0 ), + .sram_cfg_tag_i ( '0 ), + + .axi_req_o ( cluster_l2_instr_req ), + .axi_rsp_i ( cluster_l2_instr_rsp ) + ); + end else begin: gen_no_pulp_cluster + assign eu_events.other[magia_tile_pkg::EU_OTHER_CLUSTER_DONE] = 1'b0; + + assign axi_xbar_slv_req[magia_tile_pkg::AXI_SLV_CLUSTER_INSTR_IDX] = '0; + end + +/*******************************************************/ +/** PULP Cluster End **/ +/*******************************************************/ +/** Verilator Observation Beginning **/ +/*******************************************************/ + +`ifdef MAGIA_ISLE_OBSERVE + // A Verilator hierarchical block cannot be probed from outside, so the VIP reads these ports + always_comb begin + observe_o = '0; + observe_o.axi_aw_addr = axi_xbar_mst_req[magia_tile_pkg::AXI_MST_EXT_IDX].aw.addr; + observe_o.axi_aw_id = axi_xbar_mst_req[magia_tile_pkg::AXI_MST_EXT_IDX].aw.id; + observe_o.axi_aw_valid = axi_xbar_mst_req[magia_tile_pkg::AXI_MST_EXT_IDX].aw_valid; + observe_o.axi_w_data = axi_xbar_mst_req[magia_tile_pkg::AXI_MST_EXT_IDX].w.data; + observe_o.axi_w_valid = axi_xbar_mst_req[magia_tile_pkg::AXI_MST_EXT_IDX].w_valid; +`ifdef CV32E40X + observe_o.instr_ex = i_cv32e40x_ctrl_core.core_i.id_stage_i.id_ex_pipe_o.instr.bus_resp.rdata; + observe_o.instr_id = i_cv32e40x_ctrl_core.core_i.id_stage_i.if_id_pipe_i.instr.bus_resp.rdata; + observe_o.instr_wb = i_cv32e40x_ctrl_core.core_i.wb_stage_i.ex_wb_pipe_i.instr_valid ? + i_cv32e40x_ctrl_core.core_i.wb_stage_i.ex_wb_pipe_i.instr.bus_resp.rdata : '0; + observe_o.wb_data = observe_o.instr_wb; +`else + // magia_dv always defines CORE_TRACES, so the control core is a cv32e40p_wrapper + observe_o.instr_ex = i_cv32e40p_ctrl_core.cv32e40p_top_i.core_i.ex_valid ? + i_cv32e40p_ctrl_core.cv32e40p_top_i.core_i.id_stage_i.instr_rdata_i : '0; + observe_o.instr_id = i_cv32e40p_ctrl_core.cv32e40p_top_i.core_i.id_stage_i.instr_rdata_i; + observe_o.instr_wb = i_cv32e40p_ctrl_core.cv32e40p_top_i.core_i.wb_valid ? + i_cv32e40p_ctrl_core.cv32e40p_top_i.core_i.instr_rdata_id : '0; + observe_o.wb_data = i_cv32e40p_ctrl_core.cv32e40p_top_i.core_i.wb_valid ? + i_cv32e40p_ctrl_core.cv32e40p_top_i.core_i.regfile_wdata : '0; +`endif + end +`endif + +/*******************************************************/ +/** Verilator Observation End **/ +/*******************************************************/ + +endmodule: magia_isle diff --git a/hw/tile/magia_redmule_wrap.sv b/hw/tile/magia_redmule_wrap.sv index dfe727d8..9adbe999 100644 --- a/hw/tile/magia_redmule_wrap.sv +++ b/hw/tile/magia_redmule_wrap.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -56,15 +56,8 @@ module magia_redmule_wrap parameter int unsigned XifNumHarts = 1, parameter int unsigned XifIdWidth = 1, parameter int unsigned XifIssueRegisterSplit = 0, - parameter type x_issue_req_t = logic, - parameter type x_issue_resp_t = logic, - parameter type x_register_t = logic, - parameter type x_commit_t = logic, - parameter type x_result_t = logic, parameter type redmule_data_req_t = magia_tile_pkg::redmule_data_req_t, parameter type redmule_data_rsp_t = magia_tile_pkg::redmule_data_rsp_t, - parameter type redmule_ctrl_req_t = magia_tile_pkg::redmule_ctrl_req_t, - parameter type redmule_ctrl_rsp_t = magia_tile_pkg::redmule_ctrl_rsp_t, parameter hci_size_parameter_t `HCI_SIZE_PARAM(tcdm) = '{ DW: DataW, AW: magia_pkg::ADDR_W, @@ -81,24 +74,24 @@ module magia_redmule_wrap output logic busy_o, output logic evt_o, // XIF ports (unused if CtrlIntfConfig = HWPE_TARGET) - input x_issue_req_t x_issue_req_i, - output x_issue_resp_t x_issue_resp_o, + input logic x_issue_req_i, + output logic x_issue_resp_o, input logic x_issue_valid_i, output logic x_issue_ready_o, - input x_register_t x_register_i, + input logic x_register_i, input logic x_register_valid_i, output logic x_register_ready_o, - input x_commit_t x_commit_i, + input logic x_commit_i, input logic x_commit_valid_i, - output x_result_t x_result_o, + output logic x_result_o, output logic x_result_valid_o, input logic x_result_ready_i, // Struct-based HCI data ports output redmule_data_req_t data_req_o, input redmule_data_rsp_t data_rsp_i, // Struct-based HWPE-ctrl ports - input redmule_ctrl_req_t ctrl_req_i, - output redmule_ctrl_rsp_t ctrl_rsp_o + input magia_tile_pkg::redmule_ctrl_req_t ctrl_req_i, + output magia_tile_pkg::redmule_ctrl_rsp_t ctrl_rsp_o ); localparam hci_size_parameter_t `HCI_SIZE_PARAM(tcdm_filtered) = `HCI_SIZE_PARAM(tcdm); @@ -192,11 +185,11 @@ module magia_redmule_wrap .XifNumHarts ( XifNumHarts ), .XifIdWidth ( XifIdWidth ), .XifIssueRegisterSplit ( XifIssueRegisterSplit), - .x_issue_req_t ( x_issue_req_t ), - .x_issue_resp_t ( x_issue_resp_t ), - .x_register_t ( x_register_t ), - .x_commit_t ( x_commit_t ), - .x_result_t ( x_result_t ), + .x_issue_req_t ( logic ), + .x_issue_resp_t ( logic ), + .x_register_t ( logic ), + .x_commit_t ( logic ), + .x_result_t ( logic ), .`HCI_SIZE_PARAM(tcdm) ( `HCI_SIZE_PARAM(tcdm)) ) i_redmule_top ( .clk_i ( clk_i ), diff --git a/hw/tile/magia_tile.sv b/hw/tile/magia_tile.sv index 5bb96b30..36686f84 100644 --- a/hw/tile/magia_tile.sv +++ b/hw/tile/magia_tile.sv @@ -1,14 +1,14 @@ /* - * Copyright (C) 2023-2024 ETH Zurich and University of Bologna + * Copyright (C) 2023-2026 ETH Zurich and University of Bologna * - * Licensed under the Solderpad Hardware License, Version 0.51 - * (the "License"); you may not use this file except in compliance + * Licensed under the Solderpad Hardware License, Version 0.51 + * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -16,27 +16,15 @@ * * Authors: Victor Isachi * Luca Balboni - * - * MAGIA Tile + * + * MAGIA Tile: MAGIA Isle, FlooNoC network interface and router. */ - `include "axi/assign.svh" - `include "hci_helpers.svh" - `include "hwpe_ctrl_helpers.svh" +`include "fractal_sync/assign.svh" module magia_tile import magia_tile_pkg::*; import magia_pkg::*; - import redmule_pkg::*; - import hci_package::*; -`ifdef CV32E40X - import cv32e40x_pkg::*; - import fpu_ss_pkg::*; -`endif - import snitch_icache_pkg::*; - import idma_pkg::*; - import obi_pkg::*; - import axi_pkg::*; import floo_pkg::*; `ifndef TARGET_STANDALONE_TILE import magia_noc_pkg::*; @@ -44,1606 +32,313 @@ module magia_tile import floo_axi_nw_mesh_1x2_noc_pkg::*; `endif #( - // Parameters used by hci_interconnect and l1_spm - parameter int unsigned N_MEM_BANKS = magia_pkg::N_MEM_BANKS, // Number of memory banks - parameter int unsigned N_WORDS_BANK = magia_pkg::N_WORDS_BANK, // Number of words per memory bank - - // Parameters used by the core - parameter cv32e40x_pkg::rv32_e CORE_ISA = cv32e40x_pkg::RV32I, // RV32I (default) 32 registers in the RF - RV32E 16 registers in the RF - parameter cv32e40x_pkg::a_ext_e CORE_A = cv32e40x_pkg::A, // Atomic Istruction (A) support (dafault: full support) - parameter cv32e40x_pkg::b_ext_e CORE_B = cv32e40x_pkg::ZBA_ZBB_ZBC_ZBS, // Bit Manipulation support (dafault: full support) - parameter cv32e40x_pkg::m_ext_e CORE_M = cv32e40x_pkg::M, // Multiply and Divide support (dafault: full support) - - // Parameters used by the iDMA - parameter idma_pkg::error_cap_e ERROR_CAP = idma_pkg::NO_ERROR_HANDLING // Error handaling capability of the iDMA + parameter magia_tile_pkg::magia_tile_cfg_t TileCfg = magia_tile_pkg::MagiaTileDefaultCfg )( - input logic clk_i, - input logic rst_ni, - input logic test_mode_i, - input logic tile_enable_i, - - // NoC input and output links - input floo_req_t noc_south_req_i, - output floo_rsp_t noc_south_rsp_o, - input floo_wide_t noc_south_wide_i, - output floo_req_t noc_south_req_o, - input floo_rsp_t noc_south_rsp_i, - output floo_wide_t noc_south_wide_o, - - input floo_req_t noc_east_req_i, - output floo_rsp_t noc_east_rsp_o, - input floo_wide_t noc_east_wide_i, - output floo_req_t noc_east_req_o, - input floo_rsp_t noc_east_rsp_i, - output floo_wide_t noc_east_wide_o, - - input floo_req_t noc_north_req_i, - output floo_rsp_t noc_north_rsp_o, - input floo_wide_t noc_north_wide_i, - output floo_req_t noc_north_req_o, - input floo_rsp_t noc_north_rsp_i, - output floo_wide_t noc_north_wide_o, - - input floo_req_t noc_west_req_i, - output floo_rsp_t noc_west_rsp_o, - input floo_wide_t noc_west_wide_i, - output floo_req_t noc_west_req_o, - input floo_rsp_t noc_west_rsp_i, - output floo_wide_t noc_west_wide_o, - - // Tile spatial IDs - input logic [31:0] x_id_i, - input logic [31:0] y_id_i, - - // FractalSync interface - fractal_sync_if.mst_port ht_fsync_if_o, - fractal_sync_if.mst_port hn_fsync_if_o, - fractal_sync_if.mst_port vt_fsync_if_o, - fractal_sync_if.mst_port vn_fsync_if_o, + input logic clk_i, + input logic rst_ni, + input logic test_mode_i, + input logic tile_enable_i, + + input floo_req_t noc_south_req_i, + output floo_rsp_t noc_south_rsp_o, + input floo_wide_t noc_south_wide_i, + output floo_req_t noc_south_req_o, + input floo_rsp_t noc_south_rsp_i, + output floo_wide_t noc_south_wide_o, + + input floo_req_t noc_east_req_i, + output floo_rsp_t noc_east_rsp_o, + input floo_wide_t noc_east_wide_i, + output floo_req_t noc_east_req_o, + input floo_rsp_t noc_east_rsp_i, + output floo_wide_t noc_east_wide_o, + + input floo_req_t noc_north_req_i, + output floo_rsp_t noc_north_rsp_o, + input floo_wide_t noc_north_wide_i, + output floo_req_t noc_north_req_o, + input floo_rsp_t noc_north_rsp_i, + output floo_wide_t noc_north_wide_o, + + input floo_req_t noc_west_req_i, + output floo_rsp_t noc_west_rsp_o, + input floo_wide_t noc_west_wide_i, + output floo_req_t noc_west_req_o, + input floo_rsp_t noc_west_rsp_i, + output floo_wide_t noc_west_wide_o, + + // Mesh coordinates of the router + input logic [31:0] x_id_i, + input logic [31:0] y_id_i, + +`ifdef MAGIA_FSYNC + output magia_tile_pkg::ht_tile_fsync_req_t ht_fsync_req_o, + input magia_tile_pkg::ht_tile_fsync_rsp_t ht_fsync_rsp_i, + output magia_tile_pkg::hn_tile_fsync_req_t hn_fsync_req_o, + input magia_tile_pkg::hn_tile_fsync_rsp_t hn_fsync_rsp_i, + output magia_tile_pkg::vt_tile_fsync_req_t vt_fsync_req_o, + input magia_tile_pkg::vt_tile_fsync_rsp_t vt_fsync_rsp_i, + output magia_tile_pkg::vn_tile_fsync_req_t vn_fsync_req_o, + input magia_tile_pkg::vn_tile_fsync_rsp_t vn_fsync_rsp_i, +`endif - // Signals used by the core - input logic scan_cg_en_i, + input logic scan_cg_en_i, - input logic[31:0] boot_addr_i, - input logic[31:0] mtvec_addr_i, - input logic[31:0] dm_halt_addr_i, - input logic[31:0] dm_exception_addr_i, - input logic[31:0] mhartid_i, - input logic[ 3:0] mimpid_patch_i, + input logic[31:0] boot_addr_i, + input logic[31:0] mtvec_addr_i, + input logic[31:0] dm_halt_addr_i, + input logic[31:0] dm_exception_addr_i, + input logic[31:0] mhartid_i, + input logic[ 3:0] mimpid_patch_i, - output logic[63:0] mcycle_o, - input logic[63:0] time_i, + output logic[63:0] mcycle_o, + input logic[63:0] time_i, - input logic[magia_pkg::N_IRQ-1:0] irq_i, + input logic[magia_pkg::N_IRQ-1:0] irq_i, input logic[magia_tile_pkg::N_CLUSTER_CORES:0] debug_req_i, - output logic debug_havereset_o, - output logic debug_running_o, - output logic debug_halted_o, - output logic debug_pc_valid_o, - output logic[31:0] debug_pc_o, - - input logic fetch_enable_i, - output logic core_sleep_o, - input logic wu_wfe_i + output logic debug_havereset_o, + output logic debug_running_o, + output logic debug_halted_o, + output logic debug_pc_valid_o, + output logic[31:0] debug_pc_o, + + input logic fetch_enable_i, + output logic core_sleep_o, + input logic wu_wfe_i `ifdef VERILATOR - , output magia_tile_observe_t observe_o + , output magia_tile_observe_t observe_o `endif ); /*******************************************************/ -/** Internal Signal Definitions Beginning **/ +/** FractalSync Beginning **/ /*******************************************************/ -`ifdef VERILATOR - // A hierarchical block cannot be observed through parent dotted paths. - always_comb begin - observe_o = '0; - // The print peripheral (0xFFFF_0000/0xFFFF_0004) matches no address rule - // and therefore leaves through the default master port ('0), i.e. the ext - // port. This is the port the pre-hierarchy VIP snooped as - // i_axi_xbar.mst_ports_req_o[0]; observing the OBI port sees no prints. - observe_o.axi_aw_addr = axi_xbar_mst_req[magia_tile_pkg::AXI_MST_EXT_IDX].aw.addr; - observe_o.axi_aw_id = axi_xbar_mst_req[magia_tile_pkg::AXI_MST_EXT_IDX].aw.id; - observe_o.axi_aw_valid = axi_xbar_mst_req[magia_tile_pkg::AXI_MST_EXT_IDX].aw_valid; - observe_o.axi_w_data = axi_xbar_mst_req[magia_tile_pkg::AXI_MST_EXT_IDX].w.data; - observe_o.axi_w_valid = axi_xbar_mst_req[magia_tile_pkg::AXI_MST_EXT_IDX].w_valid; -`ifdef CV32E40X - observe_o.instr_ex = i_cv32e40x_ctrl_core.core_i.id_stage_i.id_ex_pipe_o.instr.bus_resp.rdata; - observe_o.instr_id = i_cv32e40x_ctrl_core.core_i.id_stage_i.if_id_pipe_i.instr.bus_resp.rdata; - observe_o.instr_wb = i_cv32e40x_ctrl_core.core_i.wb_stage_i.ex_wb_pipe_i.instr_valid ? - i_cv32e40x_ctrl_core.core_i.wb_stage_i.ex_wb_pipe_i.instr.bus_resp.rdata : '0; - observe_o.wb_data = observe_o.instr_wb; -`else - // CORE_TRACES is unconditionally defined for the magia_dv target (see - // Bender.yml), so i_cv32e40p_ctrl_core is always a cv32e40p_wrapper - // instance, which instantiates cv32e40p_top as cv32e40p_top_i, which in - // turn instantiates cv32e40p_core as core_i. - observe_o.instr_ex = i_cv32e40p_ctrl_core.cv32e40p_top_i.core_i.ex_valid ? - i_cv32e40p_ctrl_core.cv32e40p_top_i.core_i.id_stage_i.instr_rdata_i : '0; - observe_o.instr_id = i_cv32e40p_ctrl_core.cv32e40p_top_i.core_i.id_stage_i.instr_rdata_i; - observe_o.instr_wb = i_cv32e40p_ctrl_core.cv32e40p_top_i.core_i.wb_valid ? - i_cv32e40p_ctrl_core.cv32e40p_top_i.core_i.instr_rdata_id : '0; - observe_o.wb_data = i_cv32e40p_ctrl_core.cv32e40p_top_i.core_i.wb_valid ? - i_cv32e40p_ctrl_core.cv32e40p_top_i.core_i.regfile_wdata : '0; -`endif - end -`endif - - logic[magia_pkg::ADDR_W-1:0] tile_l1_start_addr; - logic[magia_pkg::ADDR_W-1:0] tile_l1_end_addr; - logic[magia_pkg::ADDR_W-1:0] tile_reserved_start_addr; - logic[magia_pkg::ADDR_W-1:0] tile_reserved_end_addr; - logic[magia_pkg::ADDR_W-1:0] tile_redmule_ctrl_start_addr; - logic[magia_pkg::ADDR_W-1:0] tile_redmule_ctrl_end_addr; - logic[magia_pkg::ADDR_W-1:0] tile_idma_ctrl_start_addr; - logic[magia_pkg::ADDR_W-1:0] tile_idma_ctrl_end_addr; - logic[magia_pkg::ADDR_W-1:0] tile_fsync_ctrl_start_addr; - logic[magia_pkg::ADDR_W-1:0] tile_fsync_ctrl_end_addr; - logic[magia_pkg::ADDR_W-1:0] tile_event_unit_start_addr; - logic[magia_pkg::ADDR_W-1:0] tile_event_unit_end_addr; - logic[magia_pkg::ADDR_W-1:0] tile_csr_start_addr; - logic[magia_pkg::ADDR_W-1:0] tile_csr_end_addr; - - magia_tile_pkg::redmule_data_req_t redmule_data_req; - magia_tile_pkg::redmule_data_rsp_t redmule_data_rsp; - - magia_tile_pkg::redmule_ctrl_req_t redmule_ctrl_req; // Can be used to manage RedMulE control at top-level - magia_tile_pkg::redmule_ctrl_rsp_t redmule_ctrl_rsp; // Can be used to manage RedMulE control at top-level - - magia_tile_pkg::core_data_req_t core_data_req; - magia_tile_pkg::core_data_rsp_t core_data_rsp; - - magia_tile_pkg::core_obi_data_req_t core_obi_data_req; - magia_tile_pkg::core_obi_data_rsp_t core_obi_data_rsp; - - magia_tile_pkg::core_obi_data_req_t[magia_tile_pkg::N_SBR-1:0] core_mem_data_req; // cv32e40p: Index 0 -> L2, Index 1 -> L1SPM, Index 2 -> RedMulE_Ctrl, Index 3 -> iDMA, Index 4 -> FSync_Ctrl, Index 5 -> Event_Unit, Index 6 -> Spatz_Ctrl - magia_tile_pkg::core_obi_data_rsp_t[magia_tile_pkg::N_SBR-1:0] core_mem_data_rsp; // cv32e40p: Index 0 -> L2, Index 1 -> L1SPM, Index 2 -> RedMulE_Ctrl, Index 3 -> iDMA, Index 4 -> FSync_Ctrl, Index 5 -> Event_Unit, Index 6 -> Spatz_Ctrl - - magia_tile_pkg::core_obi_data_req_t[magia_tile_pkg::N_SBR-1:0] core_mem_data_cut_req; // cv32e40p: Index 0 -> L2, Index 1 -> L1SPM, Index 2 -> RedMulE_Ctrl, Index 3 -> iDMA, Index 4 -> FSync_Ctrl, Index 5 -> Event_Unit, Index 6 -> Spatz_Ctrl - magia_tile_pkg::core_obi_data_rsp_t[magia_tile_pkg::N_SBR-1:0] core_mem_data_cut_rsp; // cv32e40p: Index 0 -> L2, Index 1 -> L1SPM, Index 2 -> RedMulE_Ctrl, Index 3 -> iDMA, Index 4 -> FSync_Ctrl, Index 5 -> Event_Unit, Index 6 -> Spatz_Ctrl - - magia_tile_pkg::core_obi_data_req_t core_l1_data_amo_req; - magia_tile_pkg::core_obi_data_rsp_t core_l1_data_amo_rsp; - - magia_tile_pkg::core_obi_data_req_t[magia_tile_pkg::N_MGR-1:0] obi_xbar_slv_req; // Index 0 -> core request, Index 1 -> ext request, Index 2 -> Spatz request, Index 3-3+N_CLUSTER_CORES -> cluster cores - magia_tile_pkg::core_obi_data_rsp_t[magia_tile_pkg::N_MGR-1:0] obi_xbar_slv_rsp; // Index 0 -> core request, Index 1 -> ext request, Index 2 -> Spatz request, Index 3-3+N_CLUSTER_CORES -> cluster cores - - magia_tile_pkg::core_obi_data_req_t[magia_tile_pkg::N_MGR-1:0] obi_xbar_slv_cut_req; // Index 0 -> core request, Index 1 -> ext request, Index 2 -> Spatz request, Index 3-3+N_CLUSTER_CORES -> cluster cores - magia_tile_pkg::core_obi_data_rsp_t[magia_tile_pkg::N_MGR-1:0] obi_xbar_slv_cut_rsp; // Index 0 -> core request, Index 1 -> ext request, Index 2 -> Spatz request, Index 3-3+N_CLUSTER_CORES -> cluster cores - - magia_tile_pkg::core_obi_data_req_t ext_obi_data_req; - magia_tile_pkg::core_obi_data_rsp_t ext_obi_data_rsp; - - magia_tile_pkg::core_hci_data_req_t core_l1_data_req; - magia_tile_pkg::core_hci_data_rsp_t core_l1_data_rsp; - - magia_tile_pkg::core_axi_data_req_t core_l2_data_req; - magia_tile_pkg::core_axi_data_rsp_t core_l2_data_rsp; - - magia_tile_pkg::core_instr_req_t core_instr_req; - magia_tile_pkg::core_instr_rsp_t core_instr_rsp; - - magia_tile_pkg::core_cache_instr_req_t core_cache_instr_req; - magia_tile_pkg::core_cache_instr_rsp_t core_cache_instr_rsp; - - magia_tile_pkg::core_axi_instr_req_t core_l2_instr_req; - magia_tile_pkg::core_axi_instr_rsp_t core_l2_instr_rsp; - - magia_tile_pkg::idma_axi_req_t idma_axi_read_req_out; - magia_tile_pkg::idma_axi_rsp_t idma_axi_read_rsp_out; - - magia_tile_pkg::idma_axi_req_t idma_axi_write_req_out; - magia_tile_pkg::idma_axi_rsp_t idma_axi_write_rsp_out; - - magia_tile_pkg::idma_axi_req_t idma_axi_req_out; - magia_tile_pkg::idma_axi_rsp_t idma_axi_rsp_out; - - magia_tile_pkg::idma_axi_req_t idma_axi_read_req_in; - magia_tile_pkg::idma_axi_rsp_t idma_axi_read_rsp_in; - - magia_tile_pkg::idma_axi_req_t idma_axi_write_req_in; - magia_tile_pkg::idma_axi_rsp_t idma_axi_write_rsp_in; - - magia_tile_pkg::idma_axi_req_t idma_axi_req_in; - magia_tile_pkg::idma_axi_rsp_t idma_axi_rsp_in; - - magia_tile_pkg::idma_obi_req_t idma_obi_read_req_out; - magia_tile_pkg::idma_obi_rsp_t idma_obi_read_rsp_out; - - magia_tile_pkg::idma_obi_req_t idma_obi_write_req_out; - magia_tile_pkg::idma_obi_rsp_t idma_obi_write_rsp_out; - - magia_tile_pkg::idma_obi_req_t idma_obi_read_req_in; - magia_tile_pkg::idma_obi_rsp_t idma_obi_read_rsp_in; - - magia_tile_pkg::idma_obi_req_t idma_obi_write_req_in; - magia_tile_pkg::idma_obi_rsp_t idma_obi_write_rsp_in; - - magia_tile_pkg::idma_hci_req_t idma_hci_read_req_out; - magia_tile_pkg::idma_hci_rsp_t idma_hci_read_rsp_out; - - magia_tile_pkg::idma_hci_req_t idma_hci_write_req_out; - magia_tile_pkg::idma_hci_rsp_t idma_hci_write_rsp_out; - - magia_tile_pkg::idma_hci_req_t idma_hci_read_req_in; - magia_tile_pkg::idma_hci_rsp_t idma_hci_read_rsp_in; - - magia_tile_pkg::idma_hci_req_t idma_hci_write_req_in; - magia_tile_pkg::idma_hci_rsp_t idma_hci_write_rsp_in; - - magia_tile_pkg::axi_xbar_slv_req_t[magia_tile_pkg::AxiXbarNoSlvPorts-1:0] axi_xbar_slv_req; // Index 2 -> ext, Index 1 -> Core Data, Index 0 -> Core Instruction - magia_tile_pkg::axi_xbar_slv_rsp_t[magia_tile_pkg::AxiXbarNoSlvPorts-1:0] axi_xbar_slv_rsp; // Index 2 -> ext, Index 1 -> Core Data, Index 0 -> Core Instruction - - magia_pkg::axi_xbar_mst_req_t[magia_tile_pkg::AxiXbarNoMstPorts-1:0] axi_xbar_mst_req; // Index 0 -> ext, Index 1 -> OBI XBAR, Index 2 -> Spatz bootrom - magia_pkg::axi_xbar_mst_rsp_t[magia_tile_pkg::AxiXbarNoMstPorts-1:0] axi_xbar_mst_rsp; // Index 0 -> ext, Index 1 -> OBI XBAR, Index 2 -> Spatz bootrom - - magia_pkg::axi_xbar_mst_req_t collective_filter; - - logic[magia_tile_pkg::axi_xbar_cfg.NoSlvPorts-1:0] en_default_mst_port; - - logic hci_clear; // Can be used to manage HCI clear at top-level - hci_package::hci_interconnect_ctrl_t hci_ctrl; // Can be used to manage HCI control at top-level - - magia_tile_pkg::obi_xbar_rule_t[magia_tile_pkg::N_ADDR_RULE-1:0] obi_xbar_rule; - - axi_pkg::xbar_rule_32_t[magia_tile_pkg::axi_xbar_cfg.NoAddrRules-1:0] axi_xbar_rule; - - logic[magia_tile_pkg::N_MGR-1:0] obi_xbar_en_default_idx; - logic[magia_tile_pkg::N_MGR-1:0][magia_tile_pkg::N_BIT_SBR-1:0] obi_xbar_default_idx; - - logic[magia_tile_pkg::AXI_DATA_U_W-1:0] axi_data_user; - logic[magia_tile_pkg::RUSER_WIDTH-1:0] obi_rsp_data_user; - - logic[magia_tile_pkg::AXI_INSTR_U_W-1:0] axi_instr_user; - logic[magia_tile_pkg::RUSER_WIDTH-1:0] obi_rsp_instr_user; - - logic[magia_tile_pkg::AID_WIDTH-1:0] axi2obi_req_write_aid; - logic[magia_tile_pkg::AUSER_WIDTH-1:0] axi2obi_req_write_auser; - logic[magia_tile_pkg::WUSER_WIDTH-1:0] axi2obi_req_write_wuser; - - logic[magia_tile_pkg::AID_WIDTH-1:0] axi2obi_req_read_aid; - logic[magia_tile_pkg::AUSER_WIDTH-1:0] axi2obi_req_read_auser; - - logic[magia_pkg::AXI_NOC_U_W-1:0] axi2obi_rsp_b_user; - logic[magia_pkg::AXI_NOC_U_W-1:0] axi2obi_rsp_r_user; - - logic idma_clear; // Can be used to manage iDMA clear at top-level - logic idma_axi2obi_start; - logic idma_axi2obi_busy; - logic idma_axi2obi_done; - logic idma_axi2obi_error; - logic idma_obi2axi_start; - logic idma_obi2axi_busy; - logic idma_obi2axi_done; - logic idma_obi2axi_error; - - - logic sys_clk; - logic sys_clk_en; - - // Core clock gating signals - logic core_clk; // Clock gated per il core - logic core_clk_en; // Enable dal tile (sempre attivo) - - // Core output signals - logic core_busy_o; - - logic[magia_pkg::N_IRQ-1:0] irq; - logic redmule_busy; - logic[magia_tile_pkg::N_CORE-1:0][1:0] redmule_evt; - - logic clic_irq; - logic[magia_tile_pkg::CLIC_ID_W-1:0] clic_irq_id; - logic[7:0] clic_irq_level; - logic[1:0] clic_irq_priv; - logic clic_irq_shv; - - logic fencei_flush_req; - logic fencei_flush_ack; - - logic enable_prefetching; - snitch_icache_pkg::icache_l0_events_t[magia_tile_pkg::NR_FETCH_PORTS-1:0] icache_l0_events; // Can be used to implement i$ IRQs - snitch_icache_pkg::icache_l1_events_t icache_l1_events; // Can be used to implement i$ IRQs - logic[magia_tile_pkg::NR_FETCH_PORTS-1:0] flush_valid; - logic[magia_tile_pkg::NR_FETCH_PORTS-1:0] flush_ready; - - logic fsync_clear; // Can be used to manage iDMA clear at top-level - logic fsync_done; - logic fsync_error; - - // The Event Unit serves only the control core - logic [3:0] eu_acc_events; - logic [1:0] eu_dma_events; - logic [1:0] eu_timer_events; - logic [31:0] eu_other_events; - - // FlooNoC connections between NI and router - id_t floo_id; - floo_req_t [4:0] floo_router_req_in; - floo_rsp_t [4:0] floo_router_rsp_in; - floo_wide_t [4:0] floo_router_wide_in; - floo_req_t [4:0] floo_router_req_out; - floo_rsp_t [4:0] floo_router_rsp_out; - floo_wide_t [4:0] floo_router_wide_out; - - logic x_compressed_valid; - logic x_compressed_ready; - fpu_ss_pkg::x_compressed_req_t x_compressed_req; - fpu_ss_pkg::x_compressed_resp_t x_compressed_resp; - logic x_issue_valid; - logic x_issue_ready; - fpu_ss_pkg::x_issue_req_t x_issue_req; - fpu_ss_pkg::x_issue_resp_t x_issue_resp; - logic x_commit_valid; - fpu_ss_pkg::x_commit_t x_commit; - logic x_mem_valid; - logic x_mem_ready; - fpu_ss_pkg::x_mem_req_t x_mem_req; - fpu_ss_pkg::x_mem_resp_t x_mem_resp; - logic x_mem_result_valid; - fpu_ss_pkg::x_mem_result_t x_mem_result; - logic x_result_valid; - logic x_result_ready; - fpu_ss_pkg::x_result_t x_result; - - // Event Unit signals - logic eu_core_clk_en; - logic [31:0] core_irq_vec; - - // Core data demux signals - magia_tile_pkg::core_data_req_t core_data_req_to_xbar; - magia_tile_pkg::core_data_rsp_t core_data_rsp_from_xbar; - magia_tile_pkg::eu_direct_req_t eu_direct_req; - magia_tile_pkg::eu_direct_rsp_t eu_direct_rsp; - - // Cluster core data interface (converted directly to OBI xbar) - magia_tile_pkg::cv32e40p_core_data_req_t [magia_tile_pkg::N_CLUSTER_CORES-1:0] cluster_data_req; - magia_tile_pkg::cv32e40p_core_data_rsp_t [magia_tile_pkg::N_CLUSTER_CORES-1:0] cluster_data_rsp; - - // Cluster core OBI data interface (output from demux data2obi) - magia_tile_pkg::core_obi_data_req_t [magia_tile_pkg::N_CLUSTER_CORES-1:0] cluster_obi_data_req; - magia_tile_pkg::core_obi_data_rsp_t [magia_tile_pkg::N_CLUSTER_CORES-1:0] cluster_obi_data_rsp; - - // Single control-core EU direct link, before and after the pipeline cut. - magia_tile_pkg::eu_direct_req_t eu_direct_req_cut; - magia_tile_pkg::eu_direct_rsp_t eu_direct_rsp_cut; - - // Flat EU direct signals for event unit connection - logic eu_direct_req_flat; - logic [31:0] eu_direct_addr_flat; - logic eu_direct_wen_flat; - logic [31:0] eu_direct_wdata_flat; - logic [3:0] eu_direct_be_flat; - logic eu_direct_gnt_flat; - logic eu_direct_rvalid_flat; - logic [31:0] eu_direct_rdata_flat; - logic eu_direct_err_flat; - - logic eu_core_busy; - - // Spatz CC signals - snitch_pkg::interrupts_t spatz_irq; - magia_tile_pkg::core_hci_data_req_t [magia_tile_pkg::SPATZ_HCI_PORTS-1:0] spatz_hci_req; - magia_tile_pkg::core_hci_data_rsp_t [magia_tile_pkg::SPATZ_HCI_PORTS-1:0] spatz_hci_rsp; - magia_tile_pkg::core_obi_data_req_t spatz_obi_req; - magia_tile_pkg::core_obi_data_rsp_t spatz_obi_rsp; - logic spatz_inst_req; - logic [31:0] spatz_inst_addr; - logic spatz_inst_cacheable; - logic spatz_flush_i_valid; - logic [31:0] spatz_inst_data; - logic spatz_inst_ready; - logic spatz_inst_error; - logic spatz_flush_i_ready; - logic spatz_enable_prefetching; - snitch_pkg::core_events_t spatz_core_events; - magia_tile_pkg::core_axi_instr_req_t spatz_icache_axi_req; - magia_tile_pkg::core_axi_instr_rsp_t spatz_icache_axi_rsp; - logic spatz_start; - logic spatz_done; - logic spatz_clk_en; - logic spatz_clk; - - // Collective signals - logic[31:0] collective_mask; - logic[3:0] collective_op; - - // Cluster signals - logic [magia_tile_pkg::N_CLUSTER_CORES-1:0] cluster_clk; - logic [magia_tile_pkg::N_CLUSTER_CORES-1:0] cluster_clk_en; - logic [31:0] cluster_boot_addr [magia_tile_pkg::N_CLUSTER_CORES-1:0]; - logic [magia_tile_pkg::N_CLUSTER_CORES-1:0] cluster_setback; - magia_tile_pkg::core_instr_req_t [magia_tile_pkg::N_CLUSTER_CORES-1:0] cluster_instr_req; - magia_tile_pkg::core_instr_rsp_t [magia_tile_pkg::N_CLUSTER_CORES-1:0] cluster_instr_rsp; - logic [magia_tile_pkg::N_CLUSTER_CORES-1:0] cluster_fetch_enable; - logic [magia_tile_pkg::N_CLUSTER_CORES-1:0] cluster_core_sleep; - logic cluster_done; - // Per-core dispatch IRQ pulse from tile_csr. CV32E40P IRQ inputs are level - // sensitive, so the pulse is stretched until the worker acknowledges MEI. - // PULP cluster cores remain disconnected from the event-unit IRQ port. - logic [magia_tile_pkg::N_CLUSTER_CORES-1:0] cluster_start_irq; - logic [magia_tile_pkg::N_CLUSTER_CORES-1:0] cluster_start_irq_pending; - logic [magia_tile_pkg::N_CLUSTER_CORES-1:0] cluster_irq_ack; - logic [magia_tile_pkg::N_CLUSTER_CORES-1:0][magia_tile_pkg::CLIC_ID_W_CLUSTER-1:0] cluster_irq_id; - logic [magia_tile_pkg::N_CLUSTER_CORES-1:0][31:0] cluster_irq_vec; - - - // Cluster icache interface (raw signals - struct type uses NR_FETCH_PORTS=1, not N_CLUSTER_CORES) - logic [magia_tile_pkg::N_CLUSTER_CORES-1:0] cluster_cache_req; - logic [magia_tile_pkg::N_CLUSTER_CORES-1:0][magia_tile_pkg::CLUSTER_FETCH_AW-1:0] cluster_cache_addr; - logic [magia_tile_pkg::N_CLUSTER_CORES-1:0] cluster_cache_gnt; - logic [magia_tile_pkg::N_CLUSTER_CORES-1:0] cluster_cache_rvalid; - logic [magia_tile_pkg::N_CLUSTER_CORES-1:0][magia_tile_pkg::CLUSTER_FETCH_DW-1:0] cluster_cache_rdata; - logic [magia_tile_pkg::N_CLUSTER_CORES-1:0] cluster_cache_rerror; - - logic cluster_enable_prefetching; - snitch_icache_pkg::icache_l0_events_t [magia_tile_pkg::N_CLUSTER_CORES-1:0] cluster_icache_l0_events; - snitch_icache_pkg::icache_l1_events_t cluster_icache_l1_events; - logic [magia_tile_pkg::N_CLUSTER_CORES-1:0] cluster_icache_flush_valid; - logic [magia_tile_pkg::N_CLUSTER_CORES-1:0] cluster_icache_flush_ready; - - magia_tile_pkg::core_axi_instr_req_t cluster_l2_instr_req; - magia_tile_pkg::core_axi_instr_rsp_t cluster_l2_instr_rsp; - +`ifdef MAGIA_FSYNC + // The isle drives FractalSync interfaces, the tile boundary carries structs + fractal_sync_if #(.AGGR_WIDTH(magia_tile_pkg::FSYNC_AGGR_W), .LVL_WIDTH(magia_tile_pkg::FSYNC_LVL_W), .ID_WIDTH(magia_tile_pkg::FSYNC_ID_W)) ht_fsync_if(); + fractal_sync_if #(.AGGR_WIDTH(magia_tile_pkg::FSYNC_NBR_AGGR_W), .LVL_WIDTH(magia_tile_pkg::FSYNC_NBR_LVL_W), .ID_WIDTH(magia_tile_pkg::FSYNC_NBR_ID_W)) hn_fsync_if(); + fractal_sync_if #(.AGGR_WIDTH(magia_tile_pkg::FSYNC_AGGR_W), .LVL_WIDTH(magia_tile_pkg::FSYNC_LVL_W), .ID_WIDTH(magia_tile_pkg::FSYNC_ID_W)) vt_fsync_if(); + fractal_sync_if #(.AGGR_WIDTH(magia_tile_pkg::FSYNC_NBR_AGGR_W), .LVL_WIDTH(magia_tile_pkg::FSYNC_NBR_LVL_W), .ID_WIDTH(magia_tile_pkg::FSYNC_NBR_ID_W)) vn_fsync_if(); + `FSYNC_ASSIGN_I2S_REQ(ht_fsync_if, ht_fsync_req_o) + `FSYNC_ASSIGN_S2I_RSP(ht_fsync_rsp_i, ht_fsync_if) + `FSYNC_ASSIGN_I2S_REQ(hn_fsync_if, hn_fsync_req_o) + `FSYNC_ASSIGN_S2I_RSP(hn_fsync_rsp_i, hn_fsync_if) + `FSYNC_ASSIGN_I2S_REQ(vt_fsync_if, vt_fsync_req_o) + `FSYNC_ASSIGN_S2I_RSP(vt_fsync_rsp_i, vt_fsync_if) + `FSYNC_ASSIGN_I2S_REQ(vn_fsync_if, vn_fsync_req_o) + `FSYNC_ASSIGN_S2I_RSP(vn_fsync_rsp_i, vn_fsync_if) +`endif /*******************************************************/ -/** Internal Signal Definitions End **/ +/** FractalSync End **/ /*******************************************************/ -/** Hardwired Signals Beginning **/ +/** MAGIA Isle Beginning **/ /*******************************************************/ - assign tile_redmule_ctrl_start_addr = magia_tile_pkg::REDMULE_CTRL_ADDR_START; - assign tile_redmule_ctrl_end_addr = magia_tile_pkg::REDMULE_CTRL_ADDR_END; - assign tile_idma_ctrl_start_addr = magia_tile_pkg::IDMA_CTRL_ADDR_START; - assign tile_idma_ctrl_end_addr = magia_tile_pkg::IDMA_CTRL_ADDR_END; - assign tile_fsync_ctrl_start_addr = magia_tile_pkg::FSYNC_CTRL_ADDR_START; - assign tile_fsync_ctrl_end_addr = magia_tile_pkg::FSYNC_CTRL_ADDR_END; - assign tile_event_unit_start_addr = magia_tile_pkg::EVENT_UNIT_ADDR_START; - assign tile_event_unit_end_addr = magia_tile_pkg::EVENT_UNIT_ADDR_END; - assign tile_csr_start_addr = magia_tile_pkg::TILE_CSR_START; - assign tile_csr_end_addr = magia_tile_pkg::TILE_CSR_END; - assign tile_reserved_start_addr = magia_tile_pkg::RESERVED_ADDR_START + mhartid_i*magia_tile_pkg::L1_TILE_OFFSET; - assign tile_reserved_end_addr = magia_tile_pkg::RESERVED_ADDR_END + mhartid_i*magia_tile_pkg::L1_TILE_OFFSET; - assign tile_l1_start_addr = magia_tile_pkg::L1_ADDR_START + mhartid_i*magia_tile_pkg::L1_TILE_OFFSET; - assign tile_l1_end_addr = magia_tile_pkg::L1_ADDR_END + mhartid_i*magia_tile_pkg::L1_TILE_OFFSET; - - assign obi_xbar_rule[magia_tile_pkg::OBI_XBAR_L2_IDX] = '{idx: 32'd0, start_addr: magia_tile_pkg::L2_ADDR_START, end_addr: magia_tile_pkg::L2_ADDR_END }; - assign obi_xbar_rule[magia_tile_pkg::OBI_XBAR_L1SPM_IDX] = '{idx: 32'd1, start_addr: tile_l1_start_addr, end_addr: tile_l1_end_addr }; - assign obi_xbar_rule[magia_tile_pkg::OBI_XBAR_RESERVED_IDX] = '{idx: 32'd1, start_addr: tile_reserved_start_addr, end_addr: tile_reserved_end_addr }; - assign obi_xbar_rule[magia_tile_pkg::OBI_XBAR_STACK_IDX] = '{idx: 32'd1, start_addr: magia_tile_pkg::STACK_ADDR_START, end_addr: magia_tile_pkg::STACK_ADDR_END }; - assign obi_xbar_rule[magia_tile_pkg::OBI_XBAR_REDMULE_CTRL_IDX] = '{idx: 32'd2, start_addr: tile_redmule_ctrl_start_addr, end_addr: tile_redmule_ctrl_end_addr }; - assign obi_xbar_rule[magia_tile_pkg::OBI_XBAR_IDMA_IDX] = '{idx: 32'd3, start_addr: tile_idma_ctrl_start_addr, end_addr: tile_idma_ctrl_end_addr }; - assign obi_xbar_rule[magia_tile_pkg::OBI_XBAR_FSYNC_CTRL_IDX] = '{idx: 32'd4, start_addr: tile_fsync_ctrl_start_addr, end_addr: tile_fsync_ctrl_end_addr }; - assign obi_xbar_rule[magia_tile_pkg::OBI_XBAR_EVENT_UNIT_IDX] = '{idx: 32'd5, start_addr: tile_event_unit_start_addr, end_addr: tile_event_unit_end_addr }; - assign obi_xbar_rule[magia_tile_pkg::OBI_XBAR_TILE_CSR_IDX] = '{idx: 32'd6, start_addr: tile_csr_start_addr, end_addr: tile_csr_end_addr }; - - assign axi_xbar_rule[magia_tile_pkg::AXI_XBAR_L2_IDX] = '{idx: 32'd0, start_addr: magia_tile_pkg::L2_ADDR_START, end_addr: magia_tile_pkg::L2_ADDR_END }; - assign axi_xbar_rule[magia_tile_pkg::AXI_XBAR_L1SPM_IDX] = '{idx: 32'd1, start_addr: tile_l1_start_addr, end_addr: tile_l1_end_addr }; - assign axi_xbar_rule[magia_tile_pkg::AXI_XBAR_RESERVED_IDX] = '{idx: 32'd1, start_addr: tile_reserved_start_addr, end_addr: tile_reserved_end_addr }; - assign axi_xbar_rule[magia_tile_pkg::AXI_XBAR_BOOTROM_IDX] = '{idx: 32'd2, start_addr: magia_tile_pkg::SPATZ_BOOT_ADDR, end_addr: magia_tile_pkg::SPATZ_BOOT_ADDR + magia_tile_pkg::SPATZ_BOOTROM_SIZE}; - assign obi_xbar_en_default_idx = '1; // Routing to the AXI Xbar all requests with an address outside the range of the internal L1 and the external L2 - assign obi_xbar_default_idx = '0; - - assign axi_xbar_slv_req[magia_tile_pkg::AXI_SLV_CORE_DATA_IDX] = core_l2_data_req; - assign core_l2_data_rsp = axi_xbar_slv_rsp[magia_tile_pkg::AXI_SLV_CORE_DATA_IDX]; - assign axi_xbar_slv_req[magia_tile_pkg::AXI_SLV_CORE_INSTR_IDX] = core_l2_instr_req; - assign core_l2_instr_rsp = axi_xbar_slv_rsp[magia_tile_pkg::AXI_SLV_CORE_INSTR_IDX]; - assign axi_xbar_slv_req[magia_tile_pkg::AXI_SLV_SPATZ_INSTR_IDX] = spatz_icache_axi_req; - assign spatz_icache_axi_rsp = axi_xbar_slv_rsp[magia_tile_pkg::AXI_SLV_SPATZ_INSTR_IDX]; - assign axi_xbar_slv_req[magia_tile_pkg::AXI_SLV_CLUSTER_INSTR_IDX] = cluster_l2_instr_req; - assign cluster_l2_instr_rsp = axi_xbar_slv_rsp[magia_tile_pkg::AXI_SLV_CLUSTER_INSTR_IDX]; - - assign obi_xbar_slv_req[magia_tile_pkg::OBI_CORE_IDX] = core_obi_data_req; - assign core_obi_data_rsp = obi_xbar_slv_rsp[magia_tile_pkg::OBI_CORE_IDX]; - assign obi_xbar_slv_req[magia_tile_pkg::OBI_EXT_IDX] = ext_obi_data_req; - assign ext_obi_data_rsp = obi_xbar_slv_rsp[magia_tile_pkg::OBI_EXT_IDX]; - assign obi_xbar_slv_req[magia_tile_pkg::OBI_SPATZ_IDX] = spatz_obi_req; - assign spatz_obi_rsp = obi_xbar_slv_rsp[magia_tile_pkg::OBI_SPATZ_IDX]; - - - - generate - for (genvar idx_core = 0; idx_core < magia_tile_pkg::N_CLUSTER_CORES; idx_core++) begin - assign obi_xbar_slv_req[magia_tile_pkg::OBI_SPATZ_IDX + 1 + idx_core] = cluster_obi_data_req[idx_core]; - assign cluster_obi_data_rsp[idx_core] = obi_xbar_slv_rsp[magia_tile_pkg::OBI_SPATZ_IDX + 1 + idx_core]; - end - endgenerate - - assign axi_data_user = '0; - assign obi_rsp_data_user = '0; - - assign axi_instr_user = '0; - assign obi_rsp_instr_user = '0; - - assign axi2obi_req_write_aid = '0; - assign axi2obi_req_write_auser = '0; - assign axi2obi_req_write_wuser = '0; - - assign axi2obi_req_read_aid = '0; - assign axi2obi_req_read_auser = '0; - - assign axi2obi_rsp_b_user = '0; - assign axi2obi_rsp_r_user = '0; - - assign en_default_mst_port = '1; - - assign floo_id = '{x: x_id_i, y: y_id_i, port_id: 0}; - - assign hci_clear = 1'b0; - assign hci_ctrl = '0; - - assign idma_clear = 1'b0; - - assign fsync_clear = 1'b0; - - assign redmule_evt[0][1] = 1'b0; - - // Control core uses EU polling / event loads, with no CPU interrupts. - assign irq = '0; + magia_pkg::axi_xbar_mst_req_t isle_narrow_mst_req; + magia_pkg::axi_xbar_mst_rsp_t isle_narrow_mst_rsp; + magia_tile_pkg::axi_xbar_slv_req_t isle_narrow_slv_req; + magia_tile_pkg::axi_xbar_slv_rsp_t isle_narrow_slv_rsp; + magia_tile_pkg::idma_axi_req_t isle_wide_mst_req; + magia_tile_pkg::idma_axi_rsp_t isle_wide_mst_rsp; + magia_tile_pkg::idma_axi_req_t isle_wide_slv_req; + magia_tile_pkg::idma_axi_rsp_t isle_wide_slv_rsp; + // No debug module in the mesh: the cv32e40p jumps to DM_HALT_ADDR + logic[31:0] isle_dm_halt_addr; + logic[31:0] isle_dm_exception_addr; `ifdef CV32E40X - assign enable_prefetching = 1'b0; - assign flush_valid[0] = fencei_flush_req; // Single port i$ - assign fencei_flush_ack = flush_ready[0]; // Signle port i$ - - // CLIC unused - assign clic_irq = 1'b0; - assign clic_irq_id = '0; - assign clic_irq_level = '0; - assign clic_irq_priv = '0; - assign clic_irq_shv = 1'b0; + assign isle_dm_halt_addr = dm_halt_addr_i; + assign isle_dm_exception_addr = dm_exception_addr_i; `else - // Icache control signals - assign enable_prefetching = 1'b0; - assign flush_valid = '0; + assign isle_dm_halt_addr = magia_tile_pkg::DM_HALT_ADDR; + assign isle_dm_exception_addr = magia_tile_pkg::DM_HALT_ADDR + 32'h0000_000C; `endif -/*******************************************************/ -/** Hardwired Signals End **/ -/*******************************************************/ -/** Type Conversions Beginning **/ -/*******************************************************/ + magia_isle #( + .TileCfg ( TileCfg ) + ) i_magia_isle ( + .clk_i , + .rst_ni , + .test_mode_i , + .tile_enable_i , + + .axi_narrow_mst_req_o ( isle_narrow_mst_req ), + .axi_narrow_mst_rsp_i ( isle_narrow_mst_rsp ), + .axi_narrow_slv_req_i ( isle_narrow_slv_req ), + .axi_narrow_slv_rsp_o ( isle_narrow_slv_rsp ), + .axi_wide_mst_req_o ( isle_wide_mst_req ), + .axi_wide_mst_rsp_i ( isle_wide_mst_rsp ), + .axi_wide_slv_req_i ( isle_wide_slv_req ), + .axi_wide_slv_rsp_o ( isle_wide_slv_rsp ), + +`ifdef MAGIA_FSYNC + .ht_fsync_if_o ( ht_fsync_if ), + .hn_fsync_if_o ( hn_fsync_if ), + .vt_fsync_if_o ( vt_fsync_if ), + .vn_fsync_if_o ( vn_fsync_if ), +`endif - // Convert control core data interface to OBI for crossbar + .mhartid_i , + .boot_addr_i , + .mcycle_o , + // No external interrupt controller in the mesh + .eu_irq_req_o ( ), + .eu_irq_id_o ( ), + .eu_irq_ack_i ( 1'b0 ), + .eu_irq_ack_id_i ( '0 ), + .debug_req_i , + .debug_havereset_o , + .debug_running_o , + .debug_halted_o , + .debug_pc_valid_o , + .debug_pc_o , + .fetch_enable_i , + .core_sleep_o , + .dm_halt_addr_i ( isle_dm_halt_addr ), + .dm_exception_addr_i ( isle_dm_exception_addr ) `ifdef CV32E40X - cv32e40x_data2obi_req i_core_data2obi_req ( - .data_req_i ( core_data_req_to_xbar ), - .obi_req_o ( core_obi_data_req ) - ); - - cv32e40x_obi2data_rsp i_core_obi2data_rsp ( - .obi_rsp_i ( core_obi_data_rsp ), - .data_rsp_o ( core_data_rsp_from_xbar ) - ); -`else - cv32e40p_data2obi_req i_core_data2obi_req ( - .data_req_i ( core_data_req_to_xbar ), - .obi_req_o ( core_obi_data_req ) - ); - - cv32e40p_obi2data_rsp i_core_obi2data_rsp ( - .obi_rsp_i ( core_obi_data_rsp ), - .data_rsp_o ( core_data_rsp_from_xbar ) - ); + , .scan_cg_en_i , + .mtvec_addr_i , + .mimpid_patch_i , + .time_i , + .wu_wfe_i +`endif +`ifdef VERILATOR + , .observe_o `endif - - obi2hci_req #( - .obi_req_t ( magia_tile_pkg::core_obi_data_req_t ), - .hci_req_t ( magia_tile_pkg::core_hci_data_req_t ) - ) i_core_data_obi2hci_req ( - .obi_req_i ( core_l1_data_amo_req ), - .hci_req_o ( core_l1_data_req ) - ); - - hci2obi_rsp #( - .hci_rsp_t ( magia_tile_pkg::core_hci_data_rsp_t ), - .obi_rsp_t ( magia_tile_pkg::core_obi_data_rsp_t ) - ) i_core_data_hci2obi_rsp ( - .hci_rsp_i ( core_l1_data_rsp ), - .obi_rsp_o ( core_l1_data_amo_rsp ) - ); - - obi_to_axi #( - .ObiCfg ( magia_tile_pkg::obi_amo_cfg ), - .obi_req_t ( magia_tile_pkg::core_obi_data_req_t ), - .obi_rsp_t ( magia_tile_pkg::core_obi_data_rsp_t ), - .AxiLite ( ), - .AxiAddrWidth ( magia_pkg::ADDR_W ), - .AxiDataWidth ( magia_pkg::DATA_W ), - .AxiUserWidth ( magia_tile_pkg::AXI_DATA_U_W ), - .AxiBurstType ( ), - .axi_req_t ( magia_tile_pkg::core_axi_data_req_t ), - .axi_rsp_t ( magia_tile_pkg::core_axi_data_rsp_t ), - .MaxRequests ( 1 ) - ) i_core_data_obi2axi ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - .obi_req_i ( core_mem_data_req[magia_tile_pkg::OBI_XBAR_L2_IDX] ), - .obi_rsp_o ( core_mem_data_rsp[magia_tile_pkg::OBI_XBAR_L2_IDX] ), - .user_i ( axi_data_user ), - .axi_req_o ( core_l2_data_req ), - .axi_rsp_i ( core_l2_data_rsp ), - .axi_rsp_channel_sel ( ), - .axi_rsp_b_user_o ( ), - .axi_rsp_r_user_o ( ), - .obi_rsp_user_i ( obi_rsp_data_user ) - ); - - instr2cache_req i_core_instr2cache_req ( - .instr_req_i ( core_instr_req ), - .cache_req_o ( core_cache_instr_req ) - ); - - cache2instr_rsp i_core_cache2instr_rsp ( - .cache_rsp_i ( core_cache_instr_rsp ), - .instr_rsp_o ( core_instr_rsp ) - ); - - obi2hci_req #( - .obi_req_t ( magia_tile_pkg::idma_obi_req_t ), - .hci_req_t ( magia_tile_pkg::idma_hci_req_t ) - ) i_idma_out_obi2hci_req ( - .obi_req_i ( idma_obi_read_req_out ), - .hci_req_o ( idma_hci_read_req_out ) - ); - - hci2obi_rsp #( - .hci_rsp_t ( magia_tile_pkg::idma_hci_rsp_t ), - .obi_rsp_t ( magia_tile_pkg::idma_obi_rsp_t ) - ) i_idma_out_hci2obi_rsp ( - .hci_rsp_i ( idma_hci_read_rsp_out ), - .obi_rsp_o ( idma_obi_read_rsp_out ) - ); - - obi2hci_req #( - .obi_req_t ( magia_tile_pkg::idma_obi_req_t ), - .hci_req_t ( magia_tile_pkg::idma_hci_req_t ) - ) i_idma_out_obi2hci_write_req ( - .obi_req_i ( idma_obi_write_req_out ), - .hci_req_o ( idma_hci_write_req_out ) - ); - - hci2obi_rsp #( - .hci_rsp_t ( magia_tile_pkg::idma_hci_rsp_t ), - .obi_rsp_t ( magia_tile_pkg::idma_obi_rsp_t ) - ) i_idma_out_hci2obi_write_rsp ( - .hci_rsp_i ( idma_hci_write_rsp_out ), - .obi_rsp_o ( idma_obi_write_rsp_out ) - ); - - obi2hci_req #( - .obi_req_t ( magia_tile_pkg::idma_obi_req_t ), - .hci_req_t ( magia_tile_pkg::idma_hci_req_t ) - ) i_idma_in_obi2hci_req ( - .obi_req_i ( idma_obi_read_req_in ), - .hci_req_o ( idma_hci_read_req_in ) - ); - - hci2obi_rsp #( - .hci_rsp_t ( magia_tile_pkg::idma_hci_rsp_t ), - .obi_rsp_t ( magia_tile_pkg::idma_obi_rsp_t ) - ) i_idma_in_hci2obi_rsp ( - .hci_rsp_i ( idma_hci_read_rsp_in ), - .obi_rsp_o ( idma_obi_read_rsp_in ) - ); - - obi2hci_req #( - .obi_req_t ( magia_tile_pkg::idma_obi_req_t ), - .hci_req_t ( magia_tile_pkg::idma_hci_req_t ) - ) i_idma_in_obi2hci_write_req ( - .obi_req_i ( idma_obi_write_req_in ), - .hci_req_o ( idma_hci_write_req_in ) - ); - - hci2obi_rsp #( - .hci_rsp_t ( magia_tile_pkg::idma_hci_rsp_t ), - .obi_rsp_t ( magia_tile_pkg::idma_obi_rsp_t ) - ) i_idma_in_hci2obi_write_rsp ( - .hci_rsp_i ( idma_hci_write_rsp_in ), - .obi_rsp_o ( idma_obi_write_rsp_in ) - ); - - axi_to_obi #( - .ObiCfg ( magia_tile_pkg::obi_amo_cfg ), - .obi_req_t ( magia_tile_pkg::core_obi_data_req_t ), - .obi_rsp_t ( magia_tile_pkg::core_obi_data_rsp_t ), - .obi_a_chan_t ( magia_tile_pkg::core_data_obi_a_chan_t ), - .obi_r_chan_t ( magia_tile_pkg::core_data_obi_r_chan_t ), - .AxiAddrWidth ( magia_pkg::ADDR_W ), - .AxiDataWidth ( magia_pkg::DATA_W ), - .AxiIdWidth ( magia_pkg::AXI_NOC_ID_W ), - .AxiUserWidth ( magia_pkg::AXI_NOC_U_W ), - .MaxTrans ( 8 ), - .axi_req_t ( magia_pkg::axi_xbar_mst_req_t ), - .axi_rsp_t ( magia_pkg::axi_xbar_mst_rsp_t ) - ) i_ext_data_axi2obi ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - .testmode_i ( test_mode_i ), - .axi_req_i ( axi_xbar_mst_req[magia_tile_pkg::AXI_MST_OBI_IDX] ), - .axi_rsp_o ( axi_xbar_mst_rsp[magia_tile_pkg::AXI_MST_OBI_IDX] ), - .obi_req_o ( ext_obi_data_req ), - .obi_rsp_i ( ext_obi_data_rsp ), - .req_aw_id_o ( ), - .req_aw_user_o ( ), - .req_w_user_o ( ), - .req_write_aid_i ( axi2obi_req_write_aid ), - .req_write_auser_i ( axi2obi_req_write_auser ), - .req_write_wuser_i ( axi2obi_req_write_wuser ), - .req_ar_id_o ( ), - .req_ar_user_o ( ), - .req_read_aid_i ( axi2obi_req_read_aid ), - .req_read_auser_i ( axi2obi_req_read_auser ), - .rsp_write_aw_user_o ( ), - .rsp_write_w_user_o ( ), - .rsp_write_bank_strb_o ( ), - .rsp_write_rid_o ( ), - .rsp_write_ruser_o ( ), - .rsp_write_last_o ( ), - .rsp_write_hs_o ( ), - .rsp_b_user_i ( axi2obi_rsp_b_user ), - .rsp_read_ar_user_o ( ), - .rsp_read_size_enable_o ( ), - .rsp_read_rid_o ( ), - .rsp_read_ruser_o ( ), - .rsp_r_user_i ( axi2obi_rsp_r_user ) - ); - - axi_to_obi #( - .ObiCfg ( magia_tile_pkg::obi_idma_cfg ), - .obi_req_t ( magia_tile_pkg::idma_obi_req_t ), - .obi_rsp_t ( magia_tile_pkg::idma_obi_rsp_t ), - .obi_a_chan_t ( magia_tile_pkg::idma_obi_a_chan_t ), - .obi_r_chan_t ( magia_tile_pkg::idma_obi_r_chan_t ), - .AxiAddrWidth ( iDMA_AddrWidth ), - .AxiDataWidth ( iDMA_DataWidth ), - .AxiIdWidth ( iDMA_AxiIdWidth ), - .AxiUserWidth ( iDMA_UserWidth ), - .MaxTrans ( 8 ), - .axi_req_t ( magia_tile_pkg::idma_axi_req_t ), - .axi_rsp_t ( magia_tile_pkg::idma_axi_rsp_t ) - ) i_idma_read_in_axi2obi ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - .testmode_i ( test_mode_i ), - .axi_req_i ( idma_axi_read_req_in ), - .axi_rsp_o ( idma_axi_read_rsp_in ), - .obi_req_o ( idma_obi_read_req_in ), - .obi_rsp_i ( idma_obi_read_rsp_in ), - .req_aw_id_o ( ), - .req_aw_user_o ( ), - .req_w_user_o ( ), - .req_write_aid_i ( '0 ), - .req_write_auser_i ( '0 ), - .req_write_wuser_i ( '0 ), - .req_ar_id_o ( ), - .req_ar_user_o ( ), - .req_read_aid_i ( '0 ), - .req_read_auser_i ( '0 ), - .rsp_write_aw_user_o ( ), - .rsp_write_w_user_o ( ), - .rsp_write_bank_strb_o ( ), - .rsp_write_rid_o ( ), - .rsp_write_ruser_o ( ), - .rsp_write_last_o ( ), - .rsp_write_hs_o ( ), - .rsp_b_user_i ( '0 ), - .rsp_read_ar_user_o ( ), - .rsp_read_size_enable_o ( ), - .rsp_read_rid_o ( ), - .rsp_read_ruser_o ( ), - .rsp_r_user_i ( '0 ) - ); - - axi_to_obi #( - .ObiCfg ( magia_tile_pkg::obi_idma_cfg ), - .obi_req_t ( magia_tile_pkg::idma_obi_req_t ), - .obi_rsp_t ( magia_tile_pkg::idma_obi_rsp_t ), - .obi_a_chan_t ( magia_tile_pkg::idma_obi_a_chan_t ), - .obi_r_chan_t ( magia_tile_pkg::idma_obi_r_chan_t ), - .AxiAddrWidth ( iDMA_AddrWidth ), - .AxiDataWidth ( iDMA_DataWidth ), - .AxiIdWidth ( iDMA_AxiIdWidth ), - .AxiUserWidth ( iDMA_UserWidth ), - .MaxTrans ( 8 ), - .axi_req_t ( magia_tile_pkg::idma_axi_req_t ), - .axi_rsp_t ( magia_tile_pkg::idma_axi_rsp_t ) - ) i_idma_write_in_axi2obi ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - .testmode_i ( test_mode_i ), - .axi_req_i ( idma_axi_write_req_in ), - .axi_rsp_o ( idma_axi_write_rsp_in ), - .obi_req_o ( idma_obi_write_req_in ), - .obi_rsp_i ( idma_obi_write_rsp_in ), - .req_aw_id_o ( ), - .req_aw_user_o ( ), - .req_w_user_o ( ), - .req_write_aid_i ( '0 ), - .req_write_auser_i ( '0 ), - .req_write_wuser_i ( '0 ), - .req_ar_id_o ( ), - .req_ar_user_o ( ), - .req_read_aid_i ( '0 ), - .req_read_auser_i ( '0 ), - .rsp_write_aw_user_o ( ), - .rsp_write_w_user_o ( ), - .rsp_write_bank_strb_o ( ), - .rsp_write_rid_o ( ), - .rsp_write_ruser_o ( ), - .rsp_write_last_o ( ), - .rsp_write_hs_o ( ), - .rsp_b_user_i ( '0 ), - .rsp_read_ar_user_o ( ), - .rsp_read_size_enable_o ( ), - .rsp_read_rid_o ( ), - .rsp_read_ruser_o ( ), - .rsp_r_user_i ( '0 ) - ); - - // RedMule controller OBI-to-HWPE control interface - obi2hwpe_ctrl obi2hwpe_ctrl_inst ( - .obi_req_i ( core_mem_data_req[magia_tile_pkg::OBI_XBAR_REDMULE_CTRL_IDX] ), - .obi_rsp_o ( core_mem_data_rsp[magia_tile_pkg::OBI_XBAR_REDMULE_CTRL_IDX] ), - .ctrl_req_o ( redmule_ctrl_req ), - .ctrl_rsp_i ( redmule_ctrl_rsp ) ); -/*********************** Cluster **********************************/ - - - - // Cluster icache interface: direct signal assignments - generate - for (genvar i = 0; i < magia_tile_pkg::N_CLUSTER_CORES; i++) begin : gen_cluster_icache_assign - assign cluster_cache_req[i] = cluster_instr_req[i].req; - assign cluster_cache_addr[i] = cluster_instr_req[i].addr; - assign cluster_instr_rsp[i].gnt = cluster_cache_gnt[i]; - assign cluster_instr_rsp[i].rvalid = cluster_cache_rvalid[i]; - assign cluster_instr_rsp[i].rdata = cluster_cache_rdata[i]; - assign cluster_instr_rsp[i].err = cluster_cache_rerror[i]; - end - endgenerate - - - - /*******************************************************/ -/** Type Conversions End **/ +/** MAGIA Isle End **/ /*******************************************************/ -/** Core Data Demux Beginning **/ +/** NoC Clock Gating Beginning **/ /*******************************************************/ - // Core data demux: splits requests between regular crossbar and EU direct link - core_data_demux_eu_direct i_core_data_demux_eu_direct ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - .core_clock_en_i ( core_clk_en ), - - // Core interface - .core_data_req_i ( core_data_req ), - .core_data_rsp_o ( core_data_rsp ), - - // Regular crossbar interface - .xbar_data_req_o ( core_data_req_to_xbar ), - .xbar_data_rsp_i ( core_data_rsp_from_xbar ), - - // EU direct link interface - .eu_direct_req_o ( eu_direct_req ), - .eu_direct_rsp_i ( eu_direct_rsp ) - ); - - // EU direct pipeline cut - eu_direct_cut #( - .eu_direct_req_t ( magia_tile_pkg::eu_direct_req_t ), - .eu_direct_rsp_t ( magia_tile_pkg::eu_direct_rsp_t ), - .Bypass ( 1'b0 ), - .BypassReq ( 1'b0 ), - .BypassRsp ( 1'b0 ), - .NB_CORES ( 1 ) - ) i_eu_direct_cut ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - .sbr_req_i ( eu_direct_req ), - .sbr_rsp_o ( eu_direct_rsp ), - .mgr_req_o ( eu_direct_req_cut ), - .mgr_rsp_i ( eu_direct_rsp_cut ) - ); - - // Flatten the control-core EU direct link. - assign eu_direct_req_flat = eu_direct_req_cut.req; - assign eu_direct_addr_flat = eu_direct_req_cut.addr; - assign eu_direct_wen_flat = eu_direct_req_cut.wen; - assign eu_direct_wdata_flat = eu_direct_req_cut.wdata; - assign eu_direct_be_flat = eu_direct_req_cut.be; - assign eu_direct_rsp_cut.gnt = eu_direct_gnt_flat; - assign eu_direct_rsp_cut.rvalid = eu_direct_rvalid_flat; - assign eu_direct_rsp_cut.rdata = eu_direct_rdata_flat; - assign eu_direct_rsp_cut.err = eu_direct_err_flat; + // Same enable as the isle system clock + logic noc_clk_en; + logic noc_clk; -/*******************************************************/ -/** Core Data Demux End **/ -/*******************************************************/ -/** Clock Gating Beginning **/ -/*******************************************************/ - - always_ff @(posedge clk_i, negedge rst_ni) begin: sys_clk_en_ff - if (~rst_ni) sys_clk_en <= 1'b0; - else sys_clk_en <= tile_enable_i; + always_ff @(posedge clk_i or negedge rst_ni) begin: noc_clk_en_ff + if (!rst_ni) begin + noc_clk_en <= 1'b0; + end else begin + noc_clk_en <= tile_enable_i; + end end - tc_clk_gating sys_clock_gating ( + tc_clk_gating noc_clock_gating ( .clk_i , - .en_i ( sys_clk_en ), + .en_i ( noc_clk_en ), .test_en_i ( test_mode_i ), - .clk_o ( sys_clk ) + .clk_o ( noc_clk ) ); - // Core clock gating controlled by Event Unit - assign core_clk_en = eu_core_clk_en; // Event Unit controls core clock - - tc_clk_gating core_clock_gating ( - .clk_i ( sys_clk ), - .en_i ( core_clk_en ), - .test_en_i ( test_mode_i ), - .clk_o ( core_clk ) - ); - - // Spatz clock gating controlled by obi_slave_ctrl_spatz - tc_clk_gating spatz_clock_gating ( - .clk_i ( sys_clk ), - .en_i ( spatz_clk_en ), - .test_en_i ( test_mode_i ), - .clk_o ( spatz_clk ) - ); /*******************************************************/ -/** Clock Gating End **/ +/** NoC Clock Gating End **/ /*******************************************************/ -/** Interface Definitions Beginning **/ +/** Network Interface Beginning **/ /*******************************************************/ - localparam hci_package::hci_size_parameter_t `HCI_SIZE_PARAM(hci_tcdm_sram_if) = '{ - DW: magia_tile_pkg::DW_LIC, - AW: magia_tile_pkg::AWM, - BW: hci_package::DEFAULT_BW, - UW: magia_tile_pkg::UW_LIC, - IW: magia_tile_pkg::IW, - EW: hci_package::DEFAULT_EW, - EHW: hci_package::DEFAULT_EHW - }; - `HCI_INTF_ARRAY(hci_tcdm_sram_if, sys_clk, 0:N_MEM_BANKS-1); - - localparam hci_package::hci_size_parameter_t `HCI_SIZE_PARAM(hci_core_if) = '{ - DW: magia_tile_pkg::DW_LIC, - AW: magia_tile_pkg::AWC, - BW: magia_pkg::BYTE_W, - UW: magia_tile_pkg::UW_LIC, - IW: magia_tile_pkg::IW, - EW: hci_package::DEFAULT_EW, - EHW: hci_package::DEFAULT_EHW - }; - `HCI_INTF_ARRAY(hci_core_if, sys_clk, 0:magia_tile_pkg::N_CORE-1); - - localparam hci_package::hci_size_parameter_t `HCI_SIZE_PARAM(hci_redmule_if) = '{ - DW: magia_tile_pkg::REDMULE_DW, - AW: magia_tile_pkg::AWH, - BW: hci_package::DEFAULT_BW, - UW: magia_tile_pkg::REDMULE_UW, - IW: magia_tile_pkg::IW, - EW: hci_package::DEFAULT_EW, - EHW: hci_package::DEFAULT_EHW - }; - `HCI_INTF_ARRAY(hci_redmule_if, sys_clk, 0:magia_tile_pkg::N_HWPE-1); - - localparam hci_package::hci_size_parameter_t `HCI_SIZE_PARAM(hci_dma_if) = '{ - DW: magia_tile_pkg::iDMA_DataWidth, - AW: magia_tile_pkg::iDMA_AddrWidth, - BW: hci_package::DEFAULT_BW, - UW: magia_tile_pkg::iDMA_UserWidth, - IW: magia_tile_pkg::IW, - EW: hci_package::DEFAULT_EW, - EHW: hci_package::DEFAULT_EHW - }; - `HCI_INTF_ARRAY(hci_dma_if, sys_clk, 0:magia_tile_pkg::N_DMA-1); - - localparam hci_package::hci_size_parameter_t `HCI_SIZE_PARAM(hci_ext_if) = '{ - DW: magia_tile_pkg::DW_LIC, - AW: magia_tile_pkg::AWC, - BW: hci_package::DEFAULT_BW, - UW: magia_tile_pkg::UW_LIC, - IW: hci_package::DEFAULT_IW, - EW: hci_package::DEFAULT_EW, - EHW: hci_package::DEFAULT_EHW - }; - generate; - if (N_EXT > 0) begin - `HCI_INTF_ARRAY(hci_ext_if, sys_clk, 0:magia_tile_pkg::N_EXT-1); - end else if (N_EXT == 0) begin - `HCI_INTF_ARRAY(hci_ext_if, sys_clk, 0:0); - end - endgenerate - - // Single Xif interface shared between core (cpu_*) and FPU (coproc_*) - cv32e40x_if_xif #( - .X_NUM_RS ( magia_tile_pkg::X_NUM_RS ), - .X_ID_WIDTH ( magia_tile_pkg::X_ID_W ), - .X_MEM_WIDTH ( magia_tile_pkg::X_MEM_W ), - .X_RFR_WIDTH ( magia_tile_pkg::X_RFR_W ), - .X_RFW_WIDTH ( magia_tile_pkg::X_RFW_W ), - .X_MISA ( magia_tile_pkg::X_MISA ), - .X_ECS_XS ( magia_tile_pkg::X_ECS_XS ) - ) xif_if (); - - - -/*******************************************************/ -/** Interface Definitions End **/ -/*******************************************************/ -/** Interface Assignments Beginning **/ -/*******************************************************/ - - `HCI_ASSIGN_TO_INTF(hci_core_if[0], core_l1_data_req, core_l1_data_rsp) // Only 1 core supported - generate - for (genvar i = 0; i < magia_tile_pkg::SPATZ_HCI_PORTS; i++) begin : gen_spatz_hci_assign - `HCI_ASSIGN_TO_INTF(hci_core_if[i+1], spatz_hci_req[i], spatz_hci_rsp[i]) // Spatz CC HCI ports - end - endgenerate - `HCI_ASSIGN_TO_INTF(hci_redmule_if[0], redmule_data_req, redmule_data_rsp) // Only 1 RedMulE supported - `HCI_ASSIGN_TO_INTF(hci_dma_if[magia_tile_pkg::HCI_DMA_OUT_CH_READ_IDX], idma_hci_read_req_out, idma_hci_read_rsp_out) // iDMA out HCI read channel - `HCI_ASSIGN_TO_INTF(hci_dma_if[magia_tile_pkg::HCI_DMA_OUT_CH_WRITE_IDX], idma_hci_write_req_out, idma_hci_write_rsp_out) // iDMA out HCI write channel - `HCI_ASSIGN_TO_INTF(hci_dma_if[magia_tile_pkg::HCI_DMA_IN_CH_READ_IDX], idma_hci_read_req_in, idma_hci_read_rsp_in) // iDMA in HCI read channel - `HCI_ASSIGN_TO_INTF(hci_dma_if[magia_tile_pkg::HCI_DMA_IN_CH_WRITE_IDX], idma_hci_write_req_in, idma_hci_write_rsp_in) // iDMA in HCI write channel - -/*******************************************************/ -/** Interface Assignments End **/ -/*******************************************************/ -/** RedMulE Beginning **/ -/*******************************************************/ - - magia_redmule_wrap #( - .CtrlIntfConfig ( redmule_pkg::HWPE_TARGET ), - .Height ( magia_tile_pkg::REDMULE_HEIGHT ), - .Width ( magia_tile_pkg::REDMULE_WIDTH ), - .NumPipeRegs ( magia_tile_pkg::REDMULE_NUM_PIPE_REGS ) - ) i_redmule_wrap ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - .test_mode_i ( test_mode_i ), - - .busy_o ( redmule_busy ), - .evt_o ( redmule_evt[0][0] ), - .x_issue_req_i ( ), // Not used in HWPE mode - .x_issue_resp_o ( ), // Not used in HWPE mode - .x_issue_valid_i ( 1'b0 ), // Not used in HWPE mode - .x_issue_ready_o ( ), // Not used in HWPE mode - .x_register_i ( ), // Not used in HWPE mode - .x_register_valid_i ( 1'b0 ), // Not used in HWPE mode - .x_register_ready_o ( ), // Not used in HWPE mode - .x_commit_i ( ), // Not used in HWPE mode - .x_commit_valid_i ( 1'b0 ), // Not used in HWPE mode - .x_result_o ( ), // Not used in HWPE mode - .x_result_valid_o ( ), // Not used in HWPE mode - .x_result_ready_i ( 1'b0 ), // Not used in HWPE mode - .data_req_o ( redmule_data_req ), - .data_rsp_i ( redmule_data_rsp ), - - .ctrl_req_i ( redmule_ctrl_req ), - .ctrl_rsp_o ( redmule_ctrl_rsp ) - ); + id_t floo_id; + assign floo_id = '{x: ($bits(floo_id.x))'(x_id_i), y: ($bits(floo_id.y))'(y_id_i), port_id: '0}; -/*******************************************************/ -/** RedMulE End **/ -/*******************************************************/ -/** Core Beginning **/ -/*******************************************************/ - -`ifdef CV32E40X - // Documentation of cv32e40x_core's design parameters and interface is available at: - // https://docs.openhwgroup.org/projects/cv32e40x-user-manual/en/latest/integration.html#core-integration - -`ifndef CORE_TRACES - cv32e40x_core #( -`else - cv32e40x_wrapper #( -`endif - .RV32 ( CORE_ISA ), - .A_EXT ( CORE_A ), - .B_EXT ( CORE_B ), - .M_EXT ( CORE_M ), - .X_EXT ( magia_tile_pkg::X_EXT_EN ), // Support for eXtension Interface (X) - .X_NUM_RS ( magia_tile_pkg::X_NUM_RS ), // RF read ports that can be used by the eXtension interface - .X_ID_WIDTH ( magia_tile_pkg::X_ID_W ), // ID width of eXtension interface - .X_MEM_WIDTH ( magia_tile_pkg::X_MEM_W ), // MEM width for loads/stores of eXtension interface - .X_RFR_WIDTH ( magia_tile_pkg::X_RFR_W ), // RF read width of eXtension interface - .X_RFW_WIDTH ( magia_tile_pkg::X_RFW_W ), // RF write width of eXtension interface - .X_MISA ( magia_tile_pkg::X_MISA ), // MISA extensions implemented on the eXtension interface - .X_ECS_XS ( magia_tile_pkg::X_ECS_XS ), // Default value for mstatus.XS if X_EXT = 1 - .NUM_MHPMCOUNTERS ( 1 ), // 1 MHPMCOUNTER performance counter - .DEBUG ( 1 ), // Enable debug support - .DM_REGION_START ( magia_tile_pkg::DM_REGION_START ), // Start address of Debug Module region - .DM_REGION_END ( magia_tile_pkg::DM_REGION_END ), // End address of Debug Module region - .DBG_NUM_TRIGGERS ( 1 ), // 1 debug trigger - .PMA_NUM_REGIONS ( 0 ), // No PMA (Physical Memory Attribution) regions - .PMA_CFG ( ), // No array of PMA configurations - .CLIC ( magia_tile_pkg::CLIC_EN ), // Support for Smclic, Smclicshv and Smclicconfig - .CLIC_ID_WIDTH ( magia_tile_pkg::CLIC_ID_W ) // Width of clic_irq_id_i and clic_irq_id_o - ) i_cv32e40x_ctrl_core ( - // Clock and reset - .clk_i ( core_clk ), - .rst_ni ( rst_ni ), - .scan_cg_en_i , - - // Configuration - .boot_addr_i , // instead of exposing these outside the tile, they could be managed with a configuration ROM/RAM - .mtvec_addr_i , // instead of exposing these outside the tile, they could be managed with a configuration ROM/RAM - .dm_halt_addr_i , // instead of exposing these outside the tile, they could be managed with a configuration ROM/RAM - .dm_exception_addr_i , // instead of exposing these outside the tile, they could be managed with a configuration ROM/RAM - .mhartid_i , // instead of exposing these outside the tile, they could be managed with a configuration ROM/RAM - .mimpid_patch_i , // instead of exposing these outside the tile, they could be managed with a configuration ROM/RAM - - // Instruction memory interface - .instr_req_o ( core_instr_req.req ), - .instr_gnt_i ( core_instr_rsp.gnt ), - .instr_addr_o ( core_instr_req.addr ), - .instr_memtype_o ( core_instr_req.memtype ), - .instr_prot_o ( core_instr_req.prot ), - .instr_dbg_o ( core_instr_req.dbg ), - .instr_rvalid_i ( core_instr_rsp.rvalid ), - .instr_rdata_i ( core_instr_rsp.rdata ), - .instr_err_i ( core_instr_rsp.err ), - - // Data memory interface - .data_req_o ( core_data_req.req ), - .data_gnt_i ( core_data_rsp.gnt ), - .data_addr_o ( core_data_req.addr ), - .data_atop_o ( core_data_req.atop ), - .data_be_o ( core_data_req.be ), - .data_memtype_o ( core_data_req.memtype ), - .data_prot_o ( core_data_req.prot ), - .data_dbg_o ( core_data_req.dbg ), - .data_wdata_o ( core_data_req.wdata ), - .data_we_o ( core_data_req.we ), - .data_rvalid_i ( core_data_rsp.rvalid ), - .data_rdata_i ( core_data_rsp.rdata ), - .data_err_i ( core_data_rsp.err ), - .data_exokay_i ( core_data_rsp.exokay ), - - // Cycle, Time - .mcycle_o , - .time_i , - - // eXtension interface - .xif_compressed_if ( xif_if.cpu_compressed ), - .xif_issue_if ( xif_if.cpu_issue ), - .xif_commit_if ( xif_if.cpu_commit ), - .xif_mem_if ( xif_if.cpu_mem ), - .xif_mem_result_if ( xif_if.cpu_mem_result ), - .xif_result_if ( xif_if.cpu_result ), - - // Interrupt interface - .irq_i ( irq ), - - .clic_irq_i ( clic_irq ), - .clic_irq_id_i ( clic_irq_id ), - .clic_irq_level_i ( clic_irq_level ), - .clic_irq_priv_i ( clic_irq_priv ), - .clic_irq_shv_i ( clic_irq_shv ), - - // Fence.i flush handshake - .fencei_flush_req_o ( fencei_flush_req ), - .fencei_flush_ack_i ( fencei_flush_ack ), - - // Debug interface - .debug_req_i , - .debug_havereset_o , - .debug_running_o , - .debug_halted_o , - .debug_pc_valid_o , - .debug_pc_o , + // Router port 4 is the local port + floo_req_t [4:0] floo_router_req_in; + floo_rsp_t [4:0] floo_router_rsp_in; + floo_wide_t [4:0] floo_router_wide_in; + floo_req_t [4:0] floo_router_req_out; + floo_rsp_t [4:0] floo_router_rsp_out; + floo_wide_t [4:0] floo_router_wide_out; - // Special control signals - .fetch_enable_i , - .core_sleep_o , - .wu_wfe_i - ); -`else -`ifndef CORE_TRACES - cv32e40p_top #( + floo_nw_chimney #( + .AxiCfgN ( AxiCfgN ), + .AxiCfgW ( AxiCfgW ), + .ChimneyCfgN ( set_ports(ChimneyDefaultCfg, 1'b1, 1'b1) ), + .ChimneyCfgW ( set_ports(ChimneyDefaultCfg, 1'b1, 1'b1) ), + .RouteCfg ( RouteCfg ), + .id_t ( id_t ), + .rob_idx_t ( rob_idx_t ), + .hdr_t ( hdr_t ), +`ifndef TARGET_STANDALONE_TILE + .sam_rule_t ( collective_sam_rule_t ), + .sam_idx_t ( collective_idx_t ), + .mask_sel_t ( collective_mask_sel_t ), + .Sam ( CollectiveSam ), `else - cv32e40p_wrapper #( -`endif - .COREV_PULP ( 1 ), // For now this is a no - .COREV_CLUSTER ( 1 ), - .FPU ( FPU ), - .ZFINX ( magia_tile_pkg::ZFINX_CTRL ), - .FPU_ADDMUL_LAT ( 1 ), // Match C_LAT_FP32=1 in fpnew wrapper - .FPU_OTHERS_LAT ( 1 ), // Match C_LAT_NONCOMP=1 in fpnew wrapper - .NUM_MHPMCOUNTERS ( 29 ) - ) i_cv32e40p_ctrl_core ( - // Clock and Reset - .clk_i ( core_clk ), // Use gated clock for core - .rst_ni ( rst_ni ), - - // Clock Interface - .pulp_clock_en_i ( core_clk_en ), - .scan_cg_en_i ( test_mode_i ), - .boot_addr_i ( boot_addr_i ), - .mtvec_addr_i ( boot_addr_i ), // mtvec defaults to boot vector; SW can override via csrw - .dm_halt_addr_i ( magia_tile_pkg::DM_HALT_ADDR), - .hart_id_i ( mhartid_i ), - .dm_exception_addr_i ( magia_tile_pkg::DM_HALT_ADDR + 16'h000C), //to be checked - // Instruction interface - .instr_req_o ( core_instr_req.req ), - .instr_gnt_i ( core_instr_rsp.gnt ), - .instr_rvalid_i ( core_instr_rsp.rvalid ), - .instr_addr_o ( core_instr_req.addr ), - .instr_rdata_i ( core_instr_rsp.rdata ), - // Data interface - .data_req_o ( core_data_req.req ), - .data_gnt_i ( core_data_rsp.gnt ), - .data_rvalid_i ( core_data_rsp.rvalid ), - .data_addr_o ( core_data_req.addr ), - .data_be_o ( core_data_req.be ), - .data_wdata_o ( core_data_req.wdata ), - .data_we_o ( core_data_req.we ), - .data_rdata_i ( core_data_rsp.rdata ), - // Control-core interrupt inputs are disabled. - .irq_i ( core_irq_vec ), - .irq_ack_o ( ), - .irq_id_o ( ), - // Debug interface - .debug_req_i ( debug_req_i[0] ), - .debug_havereset_o ( debug_havereset_o ), - .debug_running_o ( debug_running_o ), - .debug_halted_o ( debug_halted_o ), - // CPU control - .fetch_enable_i ( fetch_enable_i ), - .core_sleep_o ( core_sleep_o ) - ); - - - - assign core_instr_req.memtype = 2'b00; - assign core_instr_req.prot = 3'b000; - assign core_instr_req.dbg = 1'b0; - - assign mcycle_o = 64'h0; - assign debug_pc_valid_o = 1'b0; - assign debug_pc_o = 32'h0; + .sam_rule_t ( sam_rule_t ), + .Sam ( Sam ), `endif - -/*******************************************************/ -/** Core End **/ -/*******************************************************/ -/** Core Data Demuxing (OBI XBAR) Beginning **/ -/*******************************************************/ - // OBI cut instances for EXT and SPATZ master ports - for (genvar i = magia_tile_pkg::OBI_EXT_IDX; i <= magia_tile_pkg::OBI_SPATZ_IDX; i++) begin : gen_obi_cut - obi_cut #( - .ObiCfg ( magia_tile_pkg::obi_amo_cfg ), - .obi_a_chan_t ( magia_tile_pkg::core_data_obi_a_chan_t ), - .obi_r_chan_t ( magia_tile_pkg::core_data_obi_r_chan_t ), - .obi_req_t ( magia_tile_pkg::core_obi_data_req_t ), - .obi_rsp_t ( magia_tile_pkg::core_obi_data_rsp_t ) - ) i_obi_cut_sbr ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - .sbr_port_req_i ( obi_xbar_slv_req[i] ), - .sbr_port_rsp_o ( obi_xbar_slv_rsp[i] ), - .mgr_port_req_o ( obi_xbar_slv_cut_req[i] ), - .mgr_port_rsp_i ( obi_xbar_slv_cut_rsp[i] ) - ); - end - - assign obi_xbar_slv_cut_req[magia_tile_pkg::OBI_CORE_IDX] = obi_xbar_slv_req[magia_tile_pkg::OBI_CORE_IDX]; - assign obi_xbar_slv_rsp[magia_tile_pkg::OBI_CORE_IDX] = obi_xbar_slv_cut_rsp[magia_tile_pkg::OBI_CORE_IDX]; - - - generate - for (genvar idx_core = 0; idx_core < magia_tile_pkg::N_CLUSTER_CORES; idx_core++) begin - assign obi_xbar_slv_cut_req[magia_tile_pkg::OBI_SPATZ_IDX + 1 + idx_core] = obi_xbar_slv_req[magia_tile_pkg::OBI_SPATZ_IDX + 1 + idx_core]; - assign obi_xbar_slv_rsp[magia_tile_pkg::OBI_SPATZ_IDX + 1 + idx_core] = obi_xbar_slv_cut_rsp[magia_tile_pkg::OBI_SPATZ_IDX + 1 + idx_core]; - end - endgenerate - - - obi_xbar #( - .SbrPortObiCfg ( magia_tile_pkg::obi_amo_cfg ), - .MgrPortObiCfg ( ), - .sbr_port_obi_req_t ( magia_tile_pkg::core_obi_data_req_t ), - .sbr_port_a_chan_t ( magia_tile_pkg::core_data_obi_a_chan_t ), - .sbr_port_obi_rsp_t ( magia_tile_pkg::core_obi_data_rsp_t ), - .sbr_port_r_chan_t ( magia_tile_pkg::core_data_obi_r_chan_t ), - .mgr_port_obi_req_t ( ), - .mgr_port_obi_rsp_t ( ), - .NumSbrPorts ( magia_tile_pkg::N_MGR ), - .NumMgrPorts ( magia_tile_pkg::N_SBR ), - .NumMaxTrans ( magia_tile_pkg::N_MAX_TRAN ), - .NumAddrRules ( magia_tile_pkg::N_ADDR_RULE ), - .addr_map_rule_t ( magia_tile_pkg::obi_xbar_rule_t ), - .UseIdForRouting ( ), - .Connectivity ( ) - ) i_obi_xbar ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - .testmode_i ( test_mode_i ), - .sbr_ports_req_i ( obi_xbar_slv_cut_req ), - .sbr_ports_rsp_o ( obi_xbar_slv_cut_rsp ), - .mgr_ports_req_o ( core_mem_data_cut_req ), - .mgr_ports_rsp_i ( core_mem_data_cut_rsp ), - .addr_map_i ( obi_xbar_rule ), - .en_default_idx_i ( obi_xbar_en_default_idx ), - .default_idx_i ( obi_xbar_default_idx ) - ); - - for (genvar i = 0; i < magia_tile_pkg::N_SBR; i++) begin: gen_obi_xbar_mgr_cut - obi_cut #( - .ObiCfg ( magia_tile_pkg::obi_amo_cfg ), - .obi_a_chan_t ( magia_tile_pkg::core_data_obi_a_chan_t ), - .obi_r_chan_t ( magia_tile_pkg::core_data_obi_r_chan_t ), - .obi_req_t ( magia_tile_pkg::core_obi_data_req_t ), - .obi_rsp_t ( magia_tile_pkg::core_obi_data_rsp_t ) - ) i_obi_xbar_mgr_cut ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - .sbr_port_req_i ( core_mem_data_cut_req[i] ), - .sbr_port_rsp_o ( core_mem_data_cut_rsp[i] ), - .mgr_port_req_o ( core_mem_data_req[i] ), - .mgr_port_rsp_i ( core_mem_data_rsp[i] ) - ); - end - - obi_atop_resolver #( - .SbrPortObiCfg ( magia_tile_pkg::obi_amo_cfg ), - .MgrPortObiCfg ( obi_pkg::ObiDefaultConfig ), - .sbr_port_obi_req_t ( magia_tile_pkg::core_obi_data_req_t ), - .sbr_port_obi_rsp_t ( magia_tile_pkg::core_obi_data_rsp_t ), - .mgr_port_obi_req_t ( ), - .mgr_port_obi_rsp_t ( ), - .mgr_port_obi_a_optional_t ( magia_tile_pkg::core_data_obi_a_optional_t ), - .mgr_port_obi_r_optional_t ( magia_tile_pkg::core_data_obi_r_optional_t ), - .LrScEnable ( ), - .RegisterAmo ( magia_tile_pkg::RegisterAmo ) - ) i_obi_atomics ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - .testmode_i ( test_mode_i ), - .sbr_port_req_i ( core_mem_data_req[magia_tile_pkg::OBI_XBAR_L1SPM_IDX] ), - .sbr_port_rsp_o ( core_mem_data_rsp[magia_tile_pkg::OBI_XBAR_L1SPM_IDX] ), - .mgr_port_req_o ( core_l1_data_amo_req ), - .mgr_port_rsp_i ( core_l1_data_amo_rsp ) - ); - -/*******************************************************/ -/** Core Data Demuxing (OBI XBAR) End **/ -/*******************************************************/ -/** Local Interconnect (HCI) Beginning **/ -/*******************************************************/ - - local_interconnect #( - .N_HWPE ( magia_tile_pkg::N_HWPE ), - .N_DMA ( magia_tile_pkg::N_DMA ), - .N_CORE ( magia_tile_pkg::N_CORE ), - .N_MEM ( N_MEM_BANKS ), - .EXPFIFO ( magia_tile_pkg::EXPFIFO ), - .FILTER_WRITE_R_VALID ( /*DO NOT OVERWRITE*/ ), - .MEM_DATA_W ( magia_tile_pkg::DW_LIC ), - .MEM_ADDR_W ( magia_tile_pkg::AWM ), - .MEM_BYTE_W ( magia_tile_pkg::BW_LIC ), - .MEM_USER_W ( magia_tile_pkg::UW_LIC ), - .MEM_ID_W ( magia_tile_pkg::IW ), - .HCI_SIZE_hwpe (`HCI_SIZE_PARAM(hci_redmule_if) ), - .HCI_SIZE_dma (`HCI_SIZE_PARAM(hci_dma_if) ), - .HCI_SIZE_core (`HCI_SIZE_PARAM(hci_core_if) ), - .HCI_SIZE_mem (`HCI_SIZE_PARAM(hci_tcdm_sram_if)) - ) i_local_interconnect ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - - .clear_i ( hci_clear ), - .ctrl_i ( hci_ctrl ), - - .hwpe ( hci_redmule_if ), - .dma ( hci_dma_if ), - .core ( hci_core_if ), - .mem ( hci_tcdm_sram_if ) - ); - -/*******************************************************/ -/** Local Interconnect (HCI) End **/ -/*******************************************************/ -/** L1 SPM (TCDM) Beginning **/ -/*******************************************************/ - - l1_spm #( - .N_BANK ( N_MEM_BANKS ), - .N_WORDS ( N_WORDS_BANK ), - .DATA_W ( magia_pkg::DATA_W ), - .ID_W ( magia_tile_pkg::IW ), - .SIM_INIT ( "zeros" ) - ) i_l1_spm ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - - .tcdm_slave ( hci_tcdm_sram_if ) - ); - -/*******************************************************/ -/** L1 SPM (TCDM) End **/ -/*******************************************************/ -/** iDMA Beginning **/ -/*******************************************************/ - - idma_ctrl_mm #( - .ERROR_CAP ( ERROR_CAP ), - .obi_req_t ( magia_tile_pkg::core_obi_data_req_t ), - .obi_rsp_t ( magia_tile_pkg::core_obi_data_rsp_t ), - .idma_fe_reg_req_t ( magia_tile_pkg::idma_fe_reg_req_t ), - .idma_fe_reg_rsp_t ( magia_tile_pkg::idma_fe_reg_rsp_t ), - .axi_req_t ( magia_tile_pkg::idma_axi_req_t ), - .axi_rsp_t ( magia_tile_pkg::idma_axi_rsp_t ), - .idma_obi_req_t ( magia_tile_pkg::idma_obi_req_t ), - .idma_obi_rsp_t ( magia_tile_pkg::idma_obi_rsp_t ) - ) i_idma_ctrl_mm ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - .test_en_i ( test_mode_i ), - .clear_i ( idma_clear ), - - // OBI Slave Interface (CPU memory-mapped access) - .obi_req_i ( core_mem_data_req[magia_tile_pkg::OBI_XBAR_IDMA_IDX] ), - .obi_rsp_o ( core_mem_data_rsp[magia_tile_pkg::OBI_XBAR_IDMA_IDX] ), - - // AXI Master Interfaces (to L2 memory) - .axi_read_req_o ( idma_axi_read_req_out ), - .axi_read_rsp_i ( idma_axi_read_rsp_out ), - .axi_write_req_o ( idma_axi_write_req_out ), - .axi_write_rsp_i ( idma_axi_write_rsp_out ), - - // OBI Master Interfaces (to L1 memory) - .obi_read_req_o ( idma_obi_read_req_out ), - .obi_read_rsp_i ( idma_obi_read_rsp_out ), - .obi_write_req_o ( idma_obi_write_req_out ), - .obi_write_rsp_i ( idma_obi_write_rsp_out ), - - // Serialized IRQ outputs - .irq_a2o_busy_o ( idma_axi2obi_busy ), - .irq_a2o_start_o ( idma_axi2obi_start ), - .irq_a2o_done_o ( idma_axi2obi_done ), - .irq_a2o_error_o ( idma_axi2obi_error ), - .irq_o2a_busy_o ( idma_obi2axi_busy ), - .irq_o2a_start_o ( idma_obi2axi_start ), - .irq_o2a_done_o ( idma_obi2axi_done ), - .irq_o2a_error_o ( idma_obi2axi_error ) - ); - - axi_rw_join #( - .axi_req_t ( magia_tile_pkg::idma_axi_req_t ), - .axi_resp_t ( magia_tile_pkg::idma_axi_rsp_t ) - ) i_axi_rw_join ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - .slv_read_req_i ( idma_axi_read_req_out ), - .slv_read_resp_o ( idma_axi_read_rsp_out ), - .slv_write_req_i ( idma_axi_write_req_out ), - .slv_write_resp_o ( idma_axi_write_rsp_out ), - .mst_req_o ( idma_axi_req_out ), - .mst_resp_i ( idma_axi_rsp_out ) - ); - -/*******************************************************/ -/** iDMA End **/ -/*******************************************************/ -/** i$ Beginning **/ -/*******************************************************/ - - magia_tile_icache_wrap #( - .NumFetchPorts ( magia_tile_pkg::NR_FETCH_PORTS ), - .L0_LINE_COUNT ( magia_tile_pkg::L0_LINE_COUNT ), - .LINE_WIDTH ( magia_tile_pkg::LINE_WIDTH ), - .LINE_COUNT ( magia_tile_pkg::LINE_COUNT ), - .WAY_COUNT ( magia_tile_pkg::WAY_COUNT ), - .FetchAddrWidth ( magia_tile_pkg::FETCH_AW ), - .FetchDataWidth ( magia_tile_pkg::FETCH_DW ), - .AxiAddrWidth ( magia_tile_pkg::FILL_AW ), - .AxiDataWidth ( magia_tile_pkg::FILL_DW ), - .sram_cfg_data_t ( /* Not Used */ ), - .sram_cfg_tag_t ( /* Not Used */ ), - .axi_req_t ( magia_tile_pkg::core_axi_instr_req_t ), - .axi_rsp_t ( magia_tile_pkg::core_axi_instr_rsp_t ) - ) i_icache ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - - .fetch_req_i ( core_cache_instr_req.req ), - .fetch_addr_i ( core_cache_instr_req.addr ), - .fetch_gnt_o ( core_cache_instr_rsp.gnt ), - .fetch_rvalid_o ( core_cache_instr_rsp.rvalid ), - .fetch_rdata_o ( core_cache_instr_rsp.rdata ), - .fetch_rerror_o ( core_cache_instr_rsp.rerror ), - - .enable_prefetching_i ( enable_prefetching ), - .icache_l0_events_o ( icache_l0_events ), - .icache_l1_events_o ( icache_l1_events ), - .flush_valid_i ( flush_valid ), - .flush_ready_o ( flush_ready ), - - .sram_cfg_data_i ( '0 ), - .sram_cfg_tag_i ( '0 ), - - .axi_req_o ( core_l2_instr_req ), - .axi_rsp_i ( core_l2_instr_rsp ) - ); - -/*******************************************************/ -/** i$ End **/ -/*******************************************************/ -/** Data Out - L2 (AXI XBAR) Beginning **/ -/*******************************************************/ - - axi_xbar #( - .Cfg ( magia_tile_pkg::axi_xbar_cfg ), - .ATOPs ( ), - .Connectivity ( ), - .slv_aw_chan_t ( magia_tile_pkg::axi_xbar_slv_aw_chan_t ), - .mst_aw_chan_t ( magia_pkg::axi_xbar_mst_aw_chan_t ), - .w_chan_t ( magia_pkg::axi_xbar_mst_w_chan_t ), - .slv_b_chan_t ( magia_tile_pkg::axi_xbar_slv_b_chan_t ), - .mst_b_chan_t ( magia_pkg::axi_xbar_mst_b_chan_t ), - .slv_ar_chan_t ( magia_tile_pkg::axi_xbar_slv_ar_chan_t ), - .mst_ar_chan_t ( magia_pkg::axi_xbar_mst_ar_chan_t ), - .slv_r_chan_t ( magia_tile_pkg::axi_xbar_slv_r_chan_t ), - .mst_r_chan_t ( magia_pkg::axi_xbar_mst_r_chan_t ), - .slv_req_t ( magia_tile_pkg::axi_xbar_slv_req_t ), - .mst_req_t ( magia_pkg::axi_xbar_mst_req_t ), - .slv_resp_t ( magia_tile_pkg::axi_xbar_slv_rsp_t ), - .mst_resp_t ( magia_pkg::axi_xbar_mst_rsp_t ), - .rule_t ( axi_pkg::xbar_rule_32_t ) - ) i_axi_xbar ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - .test_i ( test_mode_i ), - .slv_ports_req_i ( axi_xbar_slv_req ), - .slv_ports_resp_o ( axi_xbar_slv_rsp ), - .mst_ports_req_o ( axi_xbar_mst_req ), - .mst_ports_resp_i ( axi_xbar_mst_rsp ), - .addr_map_i ( axi_xbar_rule ), - .en_default_mst_port_i ( en_default_mst_port ), - .default_mst_port_i ( '0 ) - ); - -/*******************************************************/ -/** Data Out - L2 (AXI XBAR) End **/ -/*******************************************************/ -/** FlooNoC Modules Beginning **/ -/*******************************************************/ - -red_wide_req_t offload_wide_req; -red_wide_rsp_t offload_wide_rsp; - -red_narrow_req_t offload_narrow_req; -red_narrow_rsp_t offload_narrow_rsp; - -logic[63:0] narrow_alu_result; - -floo_reduction_alu i_narrow_floo_alu ( - .clk_i(sys_clk), - .rst_ni(rst_ni), - .flush_i(1'b0), - .alu_req_op1_i({{32{1'b0}},offload_narrow_req.req.operand1}), - .alu_req_op2_i({{32{1'b0}},offload_narrow_req.req.operand2}), - .alu_req_type_i(offload_narrow_req.req.op), - .alu_req_valid_i(offload_narrow_req.valid), - .alu_req_ready_o(offload_narrow_rsp.ready), - .alu_resp_data_o(narrow_alu_result), - .alu_resp_valid_o(offload_narrow_rsp.valid), - .alu_resp_ready_i(offload_narrow_req.ready) -); - -assign offload_narrow_rsp.rsp.result = narrow_alu_result[31:0]; + .user_wide_struct_t ( axi_wide_data_slv_user_t ), + .user_narrow_struct_t ( axi_narrow_data_slv_user_t ), + .axi_narrow_in_req_t ( axi_narrow_data_slv_req_t ), + .axi_narrow_in_rsp_t ( axi_narrow_data_slv_rsp_t ), + .axi_narrow_out_req_t ( axi_narrow_data_mst_req_t ), + .axi_narrow_out_rsp_t ( axi_narrow_data_mst_rsp_t ), + .axi_wide_in_req_t ( axi_wide_data_slv_req_t ), + .axi_wide_in_rsp_t ( axi_wide_data_slv_rsp_t ), + .axi_wide_out_req_t ( axi_wide_data_mst_req_t ), + .axi_wide_out_rsp_t ( axi_wide_data_mst_rsp_t ), + .floo_req_t ( floo_req_t ), + .floo_rsp_t ( floo_rsp_t ), + .floo_wide_t ( floo_wide_t ) + ) i_magia_tile_ni ( + .clk_i ( noc_clk ), + .rst_ni ( rst_ni ), + .test_enable_i ( test_mode_i ), + .sram_cfg_i ( '0 ), + .axi_narrow_in_req_i ( isle_narrow_mst_req ), + .axi_narrow_in_rsp_o ( isle_narrow_mst_rsp ), + .axi_narrow_out_req_o ( isle_narrow_slv_req ), + .axi_narrow_out_rsp_i ( isle_narrow_slv_rsp ), + .axi_wide_in_req_i ( isle_wide_mst_req ), + .axi_wide_in_rsp_o ( isle_wide_mst_rsp ), + .axi_wide_out_req_o ( isle_wide_slv_req ), + .axi_wide_out_rsp_i ( isle_wide_slv_rsp ), + .id_i ( floo_id ), + .route_table_i ( '0 ), + .floo_req_o ( floo_router_req_in[4] ), + .floo_rsp_i ( floo_router_rsp_out[4] ), + .floo_wide_o ( floo_router_wide_in[4] ), + .floo_req_i ( floo_router_req_out[4] ), + .floo_rsp_o ( floo_router_rsp_in[4] ), + .floo_wide_i ( floo_router_wide_out[4] ) + ); + +/*******************************************************/ +/** Network Interface End **/ +/*******************************************************/ +/** Router Beginning **/ +/*******************************************************/ + + // Narrow reductions run on a local ALU, wide ones are not offloaded + red_wide_req_t offload_wide_req; + red_wide_rsp_t offload_wide_rsp; + red_narrow_req_t offload_narrow_req; + red_narrow_rsp_t offload_narrow_rsp; + logic[63:0] narrow_alu_result; + + assign offload_wide_rsp = '0; + + floo_reduction_alu i_narrow_floo_alu ( + .clk_i ( noc_clk ), + .rst_ni ( rst_ni ), + .flush_i ( 1'b0 ), + .alu_req_op1_i ( {{32{1'b0}}, offload_narrow_req.req.operand1} ), + .alu_req_op2_i ( {{32{1'b0}}, offload_narrow_req.req.operand2} ), + .alu_req_type_i ( offload_narrow_req.req.op ), + .alu_req_valid_i ( offload_narrow_req.valid ), + .alu_req_ready_o ( offload_narrow_rsp.ready ), + .alu_resp_data_o ( narrow_alu_result ), + .alu_resp_valid_o ( offload_narrow_rsp.valid ), + .alu_resp_ready_i ( offload_narrow_req.ready ) + ); + + assign offload_narrow_rsp.rsp.result = narrow_alu_result[31:0]; floo_nw_router #( .AxiCfgN ( AxiCfgN ), @@ -1666,7 +361,7 @@ assign offload_narrow_rsp.rsp.result = narrow_alu_result[31:0]; .red_narrow_req_t ( red_narrow_req_t ), .red_narrow_rsp_t ( red_narrow_rsp_t ) ) i_magia_tile_router ( - .clk_i ( sys_clk ), + .clk_i ( noc_clk ), .rst_ni ( rst_ni ), .test_enable_i ( test_mode_i ), .id_i ( floo_id ), @@ -1680,644 +375,40 @@ assign offload_narrow_rsp.rsp.result = narrow_alu_result[31:0]; .offload_wide_req_o ( offload_wide_req ), .offload_wide_rsp_i ( offload_wide_rsp ), .offload_narrow_req_o ( offload_narrow_req ), - .offload_narrow_rsp_i ( offload_narrow_rsp ) + .offload_narrow_rsp_i ( offload_narrow_rsp ) ); - // Output requests - assign noc_south_req_o = floo_router_req_out[0]; - assign floo_router_rsp_in[0] = noc_south_rsp_i; - assign noc_south_wide_o = floo_router_wide_out[0]; - - assign noc_east_req_o = floo_router_req_out[1]; - assign floo_router_rsp_in[1] = noc_east_rsp_i; - assign noc_east_wide_o = floo_router_wide_out[1]; - - assign noc_north_req_o = floo_router_req_out[2]; - assign floo_router_rsp_in[2] = noc_north_rsp_i; - assign noc_north_wide_o = floo_router_wide_out[2]; - - assign noc_west_req_o = floo_router_req_out[3]; - assign floo_router_rsp_in[3] = noc_west_rsp_i; - assign noc_west_wide_o = floo_router_wide_out[3]; - - // Input requests - assign floo_router_req_in[0] = noc_south_req_i; - assign noc_south_rsp_o = floo_router_rsp_out[0]; + // Router ports: 0 south, 1 east, 2 north, 3 west + assign noc_south_req_o = floo_router_req_out[0]; + assign floo_router_rsp_in[0] = noc_south_rsp_i; + assign noc_south_wide_o = floo_router_wide_out[0]; + assign floo_router_req_in[0] = noc_south_req_i; + assign noc_south_rsp_o = floo_router_rsp_out[0]; assign floo_router_wide_in[0] = noc_south_wide_i; - assign floo_router_req_in[1] = noc_east_req_i; - assign noc_east_rsp_o = floo_router_rsp_out[1]; + assign noc_east_req_o = floo_router_req_out[1]; + assign floo_router_rsp_in[1] = noc_east_rsp_i; + assign noc_east_wide_o = floo_router_wide_out[1]; + assign floo_router_req_in[1] = noc_east_req_i; + assign noc_east_rsp_o = floo_router_rsp_out[1]; assign floo_router_wide_in[1] = noc_east_wide_i; - assign floo_router_req_in[2] = noc_north_req_i; - assign noc_north_rsp_o = floo_router_rsp_out[2]; + assign noc_north_req_o = floo_router_req_out[2]; + assign floo_router_rsp_in[2] = noc_north_rsp_i; + assign noc_north_wide_o = floo_router_wide_out[2]; + assign floo_router_req_in[2] = noc_north_req_i; + assign noc_north_rsp_o = floo_router_rsp_out[2]; assign floo_router_wide_in[2] = noc_north_wide_i; - assign floo_router_req_in[3] = noc_west_req_i; - assign noc_west_rsp_o = floo_router_rsp_out[3]; + assign noc_west_req_o = floo_router_req_out[3]; + assign floo_router_rsp_in[3] = noc_west_rsp_i; + assign noc_west_wide_o = floo_router_wide_out[3]; + assign floo_router_req_in[3] = noc_west_req_i; + assign noc_west_rsp_o = floo_router_rsp_out[3]; assign floo_router_wide_in[3] = noc_west_wide_i; - - collective_gen i_coll_gen ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - .collective_mask_i ( collective_mask ), - .collective_op_i ( collective_op ), - .data_req_i ( axi_xbar_mst_req[magia_tile_pkg::AXI_MST_EXT_IDX] ), - .data_req_o ( collective_filter ) - ); - floo_nw_chimney #( - .AxiCfgN ( AxiCfgN ), - .AxiCfgW ( AxiCfgW ), - .ChimneyCfgN ( set_ports(ChimneyDefaultCfg, 1'b1, 1'b1) ), - .ChimneyCfgW ( set_ports(ChimneyDefaultCfg, 1'b1, 1'b1) ), - .RouteCfg ( RouteCfg ), - .id_t ( id_t ), - .rob_idx_t ( rob_idx_t ), - .hdr_t ( hdr_t ), -`ifndef TARGET_STANDALONE_TILE - .sam_rule_t ( collective_sam_rule_t ), - .sam_idx_t ( collective_idx_t ), - .mask_sel_t ( collective_mask_sel_t ), - .Sam ( CollectiveSam ), -`else - .sam_rule_t ( sam_rule_t ), - .Sam ( Sam ), -`endif - .user_wide_struct_t ( axi_wide_data_slv_user_t ), - .user_narrow_struct_t ( axi_narrow_data_slv_user_t ), - .axi_narrow_in_req_t ( axi_narrow_data_slv_req_t ), - .axi_narrow_in_rsp_t ( axi_narrow_data_slv_rsp_t ), - .axi_narrow_out_req_t ( axi_narrow_data_mst_req_t ), - .axi_narrow_out_rsp_t ( axi_narrow_data_mst_rsp_t ), - .axi_wide_in_req_t ( axi_wide_data_slv_req_t ), - .axi_wide_in_rsp_t ( axi_wide_data_slv_rsp_t ), - .axi_wide_out_req_t ( axi_wide_data_mst_req_t ), - .axi_wide_out_rsp_t ( axi_wide_data_mst_rsp_t ), - .floo_req_t ( floo_req_t ), - .floo_rsp_t ( floo_rsp_t ), - .floo_wide_t ( floo_wide_t ) - ) i_magia_tile_ni ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - .test_enable_i ( test_mode_i ), - .sram_cfg_i ( '0 ), - .axi_narrow_in_req_i ( collective_filter ), - .axi_narrow_in_rsp_o ( axi_xbar_mst_rsp[magia_tile_pkg::AXI_MST_EXT_IDX] ), - .axi_narrow_out_req_o ( axi_xbar_slv_req[magia_tile_pkg::AXI_SLV_EXT_IDX] ), - .axi_narrow_out_rsp_i ( axi_xbar_slv_rsp[magia_tile_pkg::AXI_SLV_EXT_IDX] ), - .axi_wide_in_req_i ( idma_axi_req_out ), - .axi_wide_in_rsp_o ( idma_axi_rsp_out ), - .axi_wide_out_req_o ( idma_axi_req_in ), - .axi_wide_out_rsp_i ( idma_axi_rsp_in ), - .id_i ( floo_id ), - .route_table_i ( '0 ), - .floo_req_o ( floo_router_req_in[4] ), - .floo_rsp_i ( floo_router_rsp_out[4] ), - .floo_wide_o ( floo_router_wide_in[4] ), - .floo_req_i ( floo_router_req_out[4] ), - .floo_rsp_o ( floo_router_rsp_in[4] ), - .floo_wide_i ( floo_router_wide_out[4] ) - ); - - axi_rw_split #( - .axi_req_t ( magia_tile_pkg::idma_axi_req_t ), - .axi_resp_t ( magia_tile_pkg::idma_axi_rsp_t ) - ) i_axi_rw_split ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - .slv_req_i ( idma_axi_req_in ), - .slv_resp_o ( idma_axi_rsp_in ), - .mst_read_req_o ( idma_axi_read_req_in ), - .mst_read_resp_i ( idma_axi_read_rsp_in ), - .mst_write_req_o ( idma_axi_write_req_in ), - .mst_write_resp_i ( idma_axi_write_rsp_in ) - ); - -/*******************************************************/ -/** FlooNoC Modules End **/ -/*******************************************************/ -/** Fractal Sync Out Beginning **/ -/*******************************************************/ - - // Fractal Sync OBI Memory-Mapped Slave - obi_slave_fsync #( - .BASE_ADDR ( magia_tile_pkg::FSYNC_CTRL_ADDR_START ), - .AGGR_W ( magia_tile_pkg::FSYNC_AGGR_W ), - .ID_W ( magia_tile_pkg::FSYNC_ID_W ), - .NBR_AGGR_W ( magia_tile_pkg::FSYNC_NBR_AGGR_W ), - .NBR_ID_W ( magia_tile_pkg::FSYNC_NBR_ID_W ) - ) i_fsync_mm ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - .clear_i ( fsync_clear ), - .obi_req_i ( core_mem_data_req[magia_tile_pkg::OBI_XBAR_FSYNC_CTRL_IDX] ), - .obi_rsp_o ( core_mem_data_rsp[magia_tile_pkg::OBI_XBAR_FSYNC_CTRL_IDX] ), - .ht_fsync_if_o ( ht_fsync_if_o ), - .hn_fsync_if_o ( hn_fsync_if_o ), - .vt_fsync_if_o ( vt_fsync_if_o ), - .vn_fsync_if_o ( vn_fsync_if_o ), - .done_o ( fsync_done ), - .error_o ( fsync_error ) - ); - -/*******************************************************/ -/** Fractal Sync Out End **/ /*******************************************************/ -/** Floating-Point Unit Beginning **/ +/** Router End **/ /*******************************************************/ -`ifdef CV32E40X - fpu_ss #( - .PULP_ZFINX ( magia_tile_pkg::ZFINX_CTRL ), - .INPUT_BUFFER_DEPTH ( magia_tile_pkg::FPU_BUFFER_DEPTH ), - .INPUT_BUFFER_FALL_THROUGH ( magia_tile_pkg::FPU_BUFFER_FT ), - .OUT_OF_ORDER ( magia_tile_pkg::FPU_OOO ), - .FORWARDING ( magia_tile_pkg::FPU_FWD ), - .PulpDivsqrt ( magia_tile_pkg::FPU_DIVSQRT ), - .FPU_FEATURES ( magia_tile_pkg::FPU_FEATURES ), - .FPU_IMPLEMENTATION ( magia_tile_pkg::FPU_IMPLEMENTATION ) - ) i_fpu ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - .x_compressed_valid_i ( x_compressed_valid ), - .x_compressed_ready_o ( x_compressed_ready ), - .x_compressed_req_i ( x_compressed_req ), - .x_compressed_resp_o ( x_compressed_resp ), - .x_issue_valid_i ( x_issue_valid ), - .x_issue_ready_o ( x_issue_ready ), - .x_issue_req_i ( x_issue_req ), - .x_issue_resp_o ( x_issue_resp ), - .x_commit_valid_i ( x_commit_valid ), - .x_commit_i ( x_commit ), - .x_mem_valid_o ( x_mem_valid ), - .x_mem_ready_i ( x_mem_ready ), - .x_mem_req_o ( x_mem_req ), - .x_mem_resp_i ( x_mem_resp ), - .x_mem_result_valid_i ( x_mem_result_valid ), - .x_mem_result_i ( x_mem_result ), - .x_result_valid_o ( x_result_valid ), - .x_result_ready_i ( x_result_ready ), - .x_result_o ( x_result ) - ); - - xif_if2struct i_xif_if2struct ( - .xif_compressed_if_i ( xif_if.coproc_compressed ), - .xif_issue_if_i ( xif_if.coproc_issue ), - .xif_commit_if_i ( xif_if.coproc_commit ), - .xif_mem_if_o ( xif_if.coproc_mem ), - .xif_mem_result_if_i ( xif_if.coproc_mem_result ), - .xif_result_if_o ( xif_if.coproc_result ), - .x_compressed_valid_o ( x_compressed_valid ), - .x_compressed_ready_i ( x_compressed_ready ), - .x_compressed_req_o ( x_compressed_req ), - .x_compressed_resp_i ( x_compressed_resp ), - .x_issue_valid_o ( x_issue_valid ), - .x_issue_ready_i ( x_issue_ready ), - .x_issue_req_o ( x_issue_req ), - .x_issue_resp_i ( x_issue_resp ), - .x_commit_valid_o ( x_commit_valid ), - .x_commit_o ( x_commit ), - .x_mem_valid_i ( x_mem_valid ), - .x_mem_ready_o ( x_mem_ready ), - .x_mem_req_i ( x_mem_req ), - .x_mem_resp_o ( x_mem_resp ), - .x_mem_result_valid_o ( x_mem_result_valid ), - .x_mem_result_o ( x_mem_result ), - .x_result_valid_i ( x_result_valid ), - .x_result_ready_o ( x_result_ready ), - .x_result_i ( x_result ) - ); -`endif - -/*******************************************************/ -/** Floating-Point Unit End **/ -/*******************************************************/ -/** Tile CSR Beginning **/ -/*******************************************************/ - - tile_csr #( - .BaseAddr ( magia_tile_pkg::TILE_CSR_START ) - ) i_tile_csr ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - .obi_req_i ( core_mem_data_req[magia_tile_pkg::OBI_XBAR_TILE_CSR_IDX] ), - .obi_rsp_o ( core_mem_data_rsp[magia_tile_pkg::OBI_XBAR_TILE_CSR_IDX] ), - .spatz_clk_en_o ( spatz_clk_en ), - .spatz_start_o ( spatz_start ), - .spatz_done_o ( spatz_done ), - .collective_mask_o ( collective_mask ), - .collective_op_o ( collective_op ), - .cluster_clk_en_o ( cluster_clk_en ), - .cluster_boot_addr_o ( cluster_boot_addr ), - .cluster_fetch_en_o ( cluster_fetch_enable ), - .cluster_done_o ( cluster_done ), - .cluster_start_irq_o ( cluster_start_irq ) - ); - - -/*******************************************************/ -/** Tile CSR End **/ -/*******************************************************/ -/** Event Unit Beginning **/ -/*******************************************************/ - - // Event array assignments for proper 2D array structure - // Per-tile shared HW event lines. PULP DONE is exposed to the CV32 Event Unit - // on event bit 12. Cluster cores are dispatched by - // tile_csr MEI pulses and do not consume EU direct-link events. - logic [3:0] acc_events_shared; - logic [1:0] dma_events_shared; - logic [1:0] timer_events_shared; - logic [31:0] other_events_shared; - - assign acc_events_shared = {redmule_evt[0][1], redmule_evt[0][0], redmule_busy, spatz_done}; - assign dma_events_shared = {idma_obi2axi_done, idma_axi2obi_done}; - assign timer_events_shared = 2'b00; - assign other_events_shared = {idma_obi2axi_busy, idma_axi2obi_busy, idma_obi2axi_start, idma_axi2obi_start, idma_obi2axi_error, idma_axi2obi_error, fsync_error, fsync_done, spatz_start, 7'b0, 3'b0, cluster_done, 12'b0}; // iDMA status [31:28] | iDMA errors [27:26] | Fsync [25:24] | Spatz start [23] | PULP done [12] - - // Event Unit inputs belong only to the control core. - assign eu_acc_events = acc_events_shared; - assign eu_dma_events = dma_events_shared; - assign eu_timer_events = timer_events_shared; - assign eu_other_events = other_events_shared; - - // Drive cluster icache control signals - assign cluster_enable_prefetching = 1'b0; - assign cluster_icache_flush_valid = '0; - - // Core busy array for Event Unit (CV32) - assign eu_core_busy = ~core_sleep_o; - - // EU events remain available through MMIO and the direct event-load path. - assign core_irq_vec = '0; - -`ifdef CV32E40X - assign core_busy_o = !core_sleep_o; -`endif - - magia_event_unit #( - .NB_CORES ( 1 ), - .NB_SW_EVT ( 1 ), - .NB_BARR ( 2 ), - .NB_HW_MUT ( 1 ), - .MUTEX_MSG_W ( 32 ), - .DISP_FIFO_DEPTH ( 1 ), - .EVNT_WIDTH ( 8 ), - .SOC_FIFO_DEPTH ( 8 ) - ) i_magia_event_unit ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - .test_mode_i ( test_mode_i ), - - // Event inputs - single control-core vectors - .acc_events_i ( eu_acc_events ), - .dma_events_i ( eu_dma_events ), - .timer_events_i ( eu_timer_events ), - .other_events_i ( eu_other_events ), - - // EU IRQ output is unused; events are cleared through EU accesses. - .core_irq_req_o ( ), - .core_irq_id_o ( ), - .core_irq_ack_i ( 1'b0 ), - .core_irq_ack_id_i( '0 ), - - // Core control - .core_busy_i ( eu_core_busy ), - .core_clock_en_o ( eu_core_clk_en ), - - // Debug - .dbg_req_i ( '0 ), - .core_dbg_req_o ( ), - - // EU Direct Link Interface (with cut for timing) - .eu_direct_req_i ( eu_direct_req_flat ), - .eu_direct_addr_i ( eu_direct_addr_flat ), - .eu_direct_wen_i ( eu_direct_wen_flat ), - .eu_direct_wdata_i ( eu_direct_wdata_flat ), - .eu_direct_be_i ( eu_direct_be_flat ), - .eu_direct_gnt_o ( eu_direct_gnt_flat ), - .eu_direct_rvalid_o ( eu_direct_rvalid_flat ), - .eu_direct_rdata_o ( eu_direct_rdata_flat ), - .eu_direct_err_o ( eu_direct_err_flat ), - - // OBI Peripheral Slave Interface - .obi_req_i ( core_mem_data_req[magia_tile_pkg::OBI_XBAR_EVENT_UNIT_IDX] ), - .obi_rsp_o ( core_mem_data_rsp[magia_tile_pkg::OBI_XBAR_EVENT_UNIT_IDX] ) - ); - -/*******************************************************/ -/** Event Unit End **/ -/*******************************************************/ - -/*******************************************************/ -/** Spatz CC Beginning **/ -/*******************************************************/ - // Spatz interrupt signals - assign spatz_irq.msip = 1'b0; // Machine software interrupt (unused - no multi-core) - assign spatz_irq.mtip = 1'b0; // Machine timer interrupt (unused) - assign spatz_irq.meip = spatz_start; // Machine external interrupt - from obi_slave_ctrl_spatz - assign spatz_irq.mcip = 1'b0; // Machine cluster-local interrupt (unused - no cluster) - assign spatz_irq.debug = 1'b0; // Debug request from external debugger - - spatz_cc_wrapper #( - .AddrWidth ( magia_pkg::ADDR_W ), - .DataWidth ( magia_tile_pkg::SPATZ_TCDM_DATA_WIDTH ), - .NumSpatzFPUs ( SPATZ_NUM_FPU ), - .NumSpatzIPUs ( SPATZ_NUM_IPU ), - .BootAddr ( magia_tile_pkg::SPATZ_BOOT_ADDR ), - .RVF ( magia_tile_pkg::SPATZ_RVF_PARAM ), - .RVD ( magia_tile_pkg::SPATZ_RVD_PARAM ), - .RVV ( magia_tile_pkg::SPATZ_RVV_PARAM ), - .XDivSqrt ( magia_tile_pkg::SPATZ_XDIVSQRT_PARAM ), - .FPUImplementation ( magia_tile_pkg::SPATZ_FPUImplementation ) - ) i_spatz_cc_core ( - .clk_i ( spatz_clk ), // Use gated clock - .rst_ni ( rst_ni ), - .test_mode_i ( test_mode_i ), - - // Hart ID - .hart_id_i ( mhartid_i ), // Same as CV32 - .tcdm_addr_base_i ( tile_l1_start_addr ), // Dynamic L1 base per tile - - // Interrupts - .irq_i ( spatz_irq ), - - // HCI Master Interface - Connect to HCI interconnect - .hci_master_req_o ( spatz_hci_req ), - .hci_master_rsp_i ( spatz_hci_rsp ), - - // OBI Master Interface - Connect to OBI crossbar - .obi_master_req_o ( spatz_obi_req ), - .obi_master_rsp_i ( spatz_obi_rsp ), - - // Instruction Cache Interface - .inst_req_o ( spatz_inst_req ), - .inst_addr_o ( spatz_inst_addr ), - .inst_cacheable_o ( spatz_inst_cacheable ), - .flush_i_valid_o ( spatz_flush_i_valid ), - .inst_data_i ( spatz_inst_data ), - .inst_ready_i ( spatz_inst_ready ), - .inst_error_i ( spatz_inst_error ), - .flush_i_ready_i ( spatz_flush_i_ready ), - - // Events and status - .core_events_o ( spatz_core_events ) - ); - -/*******************************************************/ -/** Spatz CC End **/ -/*******************************************************/ -/** Spatz ICache Beginning **/ -/*******************************************************/ - - assign spatz_enable_prefetching = 1'b0; - - snitch_icache #( - .NR_FETCH_PORTS ( 1 ), // Single Spatz CC core - .L0_LINE_COUNT ( 8 ), // L0 cache lines - .LINE_WIDTH ( magia_tile_pkg::SPATZ_ICACHE_LINE_WIDTH ), // 256 bits - .LINE_COUNT ( magia_tile_pkg::SPATZ_ICACHE_LINE_COUNT ), // 32 lines - .WAY_COUNT ( magia_tile_pkg::SPATZ_ICACHE_WAYS ), // 2-way set associative - .FETCH_AW ( magia_pkg::ADDR_W ), // Address width - .FETCH_DW ( 32 ), // 32-bit instructions - .FILL_AW ( magia_pkg::ADDR_W ), // AXI address width - .FILL_DW ( magia_pkg::DATA_W ), // AXI data width - .SERIAL_LOOKUP ( 0 ), - .L1_TAG_SCM ( 0 ), - .NUM_AXI_OUTSTANDING( 2 ), - .EARLY_LATCH ( 0 ), - .L0_EARLY_TAG_WIDTH ( magia_tile_pkg::SPATZ_L0_EARLY_TAG_W ), - .ISO_CROSSING ( 1'b0 ), - .axi_req_t ( magia_tile_pkg::core_axi_instr_req_t ), - .axi_rsp_t ( magia_tile_pkg::core_axi_instr_rsp_t ) - ) i_spatz_cc_icache ( - .clk_i ( spatz_clk ), - .clk_d2_i ( spatz_clk ), - .rst_ni ( rst_ni ), - .enable_prefetching_i ( spatz_enable_prefetching ), - .icache_l0_events_o ( ), - .icache_l1_events_o ( ), - .flush_valid_i ( spatz_flush_i_valid ), - .flush_ready_o ( spatz_flush_i_ready ), - .inst_addr_i ( spatz_inst_addr ), - .inst_cacheable_i ( spatz_inst_cacheable ), - .inst_data_o ( spatz_inst_data ), - .inst_valid_i ( spatz_inst_req ), - .inst_ready_o ( spatz_inst_ready ), - .inst_error_o ( spatz_inst_error ), - .sram_cfg_tag_i ( '0 ), - .sram_cfg_data_i ( '0 ), - .axi_req_o ( spatz_icache_axi_req ), - .axi_rsp_i ( spatz_icache_axi_rsp ) - ); - -/*******************************************************/ -/** Spatz ICache End **/ -/*******************************************************/ -/** Spatz Bootrom Beginning **/ -/*******************************************************/ - // AXI to regbus converter for bootrom - magia_tile_pkg::reg_dma_req_t bootrom_reg_req; - magia_tile_pkg::reg_dma_rsp_t bootrom_reg_rsp; - logic [magia_pkg::AXI_NOC_ID_W-1:0] bootrom_reg_id; - logic bootrom_busy; - - axi_to_reg_v2 #( - .AxiAddrWidth ( magia_pkg::ADDR_W ), - .AxiDataWidth ( magia_pkg::DATA_W ), - .AxiIdWidth ( magia_pkg::AXI_NOC_ID_W ), - .AxiUserWidth ( magia_pkg::AXI_NOC_U_W ), - .RegDataWidth ( magia_pkg::DATA_W ), - .axi_req_t ( magia_pkg::axi_xbar_mst_req_t ), - .axi_rsp_t ( magia_pkg::axi_xbar_mst_rsp_t ), - .reg_req_t ( magia_tile_pkg::reg_dma_req_t ), - .reg_rsp_t ( magia_tile_pkg::reg_dma_rsp_t ) - ) i_axi_to_reg_bootrom ( - .clk_i ( sys_clk ), - .rst_ni ( rst_ni ), - .axi_req_i ( axi_xbar_mst_req[magia_tile_pkg::AXI_MST_BOOTROM_IDX] ), - .axi_rsp_o ( axi_xbar_mst_rsp[magia_tile_pkg::AXI_MST_BOOTROM_IDX] ), - .reg_req_o ( bootrom_reg_req ), - .reg_rsp_i ( bootrom_reg_rsp ), - .reg_id_o ( bootrom_reg_id ), - .busy_o ( bootrom_busy ) - ); - - // Spatz bootrom module (generated from spatz_init.S) - spatz_bootrom i_spatz_bootrom ( - .clk_i ( sys_clk ), - .req_i ( bootrom_reg_req.valid ), - .addr_i ( bootrom_reg_req.addr ), - .rdata_o ( bootrom_reg_rsp.rdata ) - ); - - // Regbus response handling instead of macro - always_ff @(posedge sys_clk or negedge rst_ni) begin - if (!rst_ni) begin - bootrom_reg_rsp.ready <= 1'b0; - end else begin - bootrom_reg_rsp.ready <= bootrom_reg_req.valid; - end - end - - assign bootrom_reg_rsp.error = 1'b0; - -/*******************************************************/ -/** Spatz Bootrom End **/ -/*******************************************************/ - -/*******************************************************/ -/** Cluster Beginninng **/ -/*******************************************************/ - -// Gate each cluster core with the enable bit generated by tile_csr -for (genvar j = 0; j < magia_tile_pkg::N_CLUSTER_CORES; j++) begin : gen_cluster_clk_gate - tc_clk_gating i_cluster_clk_gate ( - .clk_i ( sys_clk ), - .en_i ( cluster_clk_en[j] ), - .test_en_i ( test_mode_i ), - .clk_o ( cluster_clk[j] ) - ); -end - -always_ff @(posedge sys_clk or negedge rst_ni) begin - if (!rst_ni) begin - cluster_start_irq_pending <= '0; - end else begin - for (int unsigned i = 0; i < magia_tile_pkg::N_CLUSTER_CORES; i++) begin - // Clear on any ack: cluster cores have exactly one IRQ source (the - // dispatch pulse), so irq_ack always refers to that source. - // CV32E40P acks with irq_id_o=11 (MEI, from priority encoder on irq_i[31:0]) - if (cluster_irq_ack[i]) begin - cluster_start_irq_pending[i] <= 1'b0; - end else if (cluster_start_irq[i]) begin - cluster_start_irq_pending[i] <= 1'b1; - end - end - end -end - -// Only tile_csr dispatch reaches the workers, as MEI (bit 11). -for (genvar k = 0; k < magia_tile_pkg::N_CLUSTER_CORES; k++) begin : gen_cluster_irq_vec - assign cluster_irq_vec[k] = {20'b0, cluster_start_irq_pending[k], 11'b0}; -end - -generate - for (genvar i = 0; i < magia_tile_pkg::N_CLUSTER_CORES; i++) begin : CORE - `ifndef CORE_TRACES - cv32e40p_top #( - `else - cv32e40p_wrapper #( - `endif - .COREV_PULP ( 1 ), // For now this is a no - .COREV_CLUSTER ( 0 ), // WFI sleep; cv.elw disabled - .FPU ( FPU ), - .ZFINX ( magia_tile_pkg::ZFINX_CLUSTER ), - .FPU_ADDMUL_LAT ( 1 ), // Match C_LAT_FP32=1 in fpnew wrapper - .FPU_OTHERS_LAT ( 1 ), // Match C_LAT_NONCOMP=1 in fpnew wrapper - .NUM_MHPMCOUNTERS ( 29 ) - ) i_cv32e40p_core ( - // Clock and Reset - .clk_i ( cluster_clk[i] ), // Use gated clock for core - .rst_ni ( rst_ni ), - - // Clock Interface — cluster cores always have clock enabled; rely on - // WFI / MEI (dispatch IRQ) for sleep/wake. - .pulp_clock_en_i ( 1'b0 ), // Unused with COREV_CLUSTER=0 - .scan_cg_en_i ( test_mode_i ), - .boot_addr_i ( cluster_boot_addr[i] ), // From tile CSR, dynamic per tile - .mtvec_addr_i ( cluster_boot_addr[i] ), // mtvec defaults to boot vector; SW can override via csrw - .dm_halt_addr_i ( magia_tile_pkg::DM_HALT_ADDR), - .hart_id_i ( 2 * magia_pkg::N_TILES + mhartid_i * magia_tile_pkg::N_CLUSTER_CORES + i ), - .dm_exception_addr_i ( magia_tile_pkg::DM_HALT_ADDR + 16'h000C), //to be checked - // Instruction interface - .instr_req_o ( cluster_instr_req[i].req ), - .instr_addr_o ( cluster_instr_req[i].addr ), - .instr_gnt_i ( cluster_instr_rsp[i].gnt ), - .instr_rvalid_i ( cluster_instr_rsp[i].rvalid ), - .instr_rdata_i ( cluster_instr_rsp[i].rdata ), - // Data interface (converted directly to OBI xbar) - .data_req_o ( cluster_data_req[i].req ), - .data_addr_o ( cluster_data_req[i].addr ), - .data_be_o ( cluster_data_req[i].be ), - .data_wdata_o ( cluster_data_req[i].wdata ), - .data_we_o ( cluster_data_req[i].we ), - .data_gnt_i ( cluster_data_rsp[i].gnt ), - .data_rvalid_i ( cluster_data_rsp[i].rvalid ), - .data_rdata_i ( cluster_data_rsp[i].rdata ), - // Interrupts: cluster cores receive only the per-core dispatch IRQ - // (MEI bit 11) from tile_csr. Event Unit IRQs are not connected. - .irq_i ( cluster_irq_vec[i] ), - .irq_ack_o ( cluster_irq_ack[i] ), - .irq_id_o ( cluster_irq_id[i] ), - // Debug interface - .debug_req_i ( debug_req_i[i+1] ), - // Debug status outputs unused: no tile-level output exposes per-cluster-core debug status. - .debug_havereset_o ( ), - .debug_running_o ( ), - .debug_halted_o ( ), - // CPU control - .fetch_enable_i ( cluster_fetch_enable[i] ), - .core_sleep_o ( cluster_core_sleep[i] ) - ); - end -endgenerate - - // Cluster core data demux (EU direct link) and OBI conversion - generate - for (genvar i = 0; i < magia_tile_pkg::N_CLUSTER_CORES; i++) begin : gen_cluster_data_obi - cv32e40p_data2obi_req i_cluster_data2obi ( - .data_req_i ( cluster_data_req[i] ), - .obi_req_o ( cluster_obi_data_req[i] ) - ); - - cv32e40p_obi2data_rsp i_cluster_obi2data ( - .obi_rsp_i ( cluster_obi_data_rsp[i] ), - .data_rsp_o ( cluster_data_rsp[i] ) - ); - end - endgenerate - - - - magia_tile_icache_wrap #( - .NumFetchPorts ( magia_tile_pkg::N_CLUSTER_CORES ), - .L0_LINE_COUNT ( magia_tile_pkg::CLUSTER_L0_LINE_COUNT ), - .LINE_WIDTH ( magia_tile_pkg::CLUSTER_LINE_WIDTH ), - .LINE_COUNT ( magia_tile_pkg::CLUSTER_LINE_COUNT ), - .WAY_COUNT ( magia_tile_pkg::CLUSTER_WAY_COUNT ), - .FetchAddrWidth ( magia_tile_pkg::CLUSTER_FETCH_AW ), - .FetchDataWidth ( magia_tile_pkg::CLUSTER_FETCH_DW ), - .AxiAddrWidth ( magia_tile_pkg::CLUSTER_FILL_AW ), - .AxiDataWidth ( magia_tile_pkg::CLUSTER_FILL_DW ), - .sram_cfg_data_t ( /* Not Used */ ), - .sram_cfg_tag_t ( /* Not Used */ ), - .axi_req_t ( magia_tile_pkg::core_axi_instr_req_t ), - .axi_rsp_t ( magia_tile_pkg::core_axi_instr_rsp_t ) - ) cluster_icache_top_i ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .fetch_req_i ( cluster_cache_req ), - .fetch_addr_i ( cluster_cache_addr ), - .fetch_gnt_o ( cluster_cache_gnt ), - .fetch_rvalid_o ( cluster_cache_rvalid ), - .fetch_rdata_o ( cluster_cache_rdata ), - .fetch_rerror_o ( cluster_cache_rerror ), - - .enable_prefetching_i ( cluster_enable_prefetching ), - .icache_l0_events_o ( cluster_icache_l0_events ), - .icache_l1_events_o ( cluster_icache_l1_events ), - .flush_valid_i ( cluster_icache_flush_valid ), - .flush_ready_o ( cluster_icache_flush_ready ), - - .sram_cfg_data_i ('0), - .sram_cfg_tag_i ('0), - - .axi_req_o ( cluster_l2_instr_req ), - .axi_rsp_i ( cluster_l2_instr_rsp ) - ); - - - endmodule: magia_tile diff --git a/hw/tile/magia_tile_icache_wrap.sv b/hw/tile/magia_tile_icache_wrap.sv index 3728949a..82384af8 100644 --- a/hw/tile/magia_tile_icache_wrap.sv +++ b/hw/tile/magia_tile_icache_wrap.sv @@ -1,14 +1,14 @@ /* - * Copyright (C) 2026 ETH Zurich, University of Bologna and Chips-IT + * Copyright (C) 2026 ETH Zurich, University of Bologna and Fondazione Chips-IT * * Licensed under the Solderpad Hardware License, Version 0.51 * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -40,12 +40,9 @@ parameter int AxiAddrWidth = -1, /// Fill interface data width. Power of 2; >= 8. parameter int AxiDataWidth = -1, - /// Configuration input types for memory cuts used in implementation. - parameter type sram_cfg_data_t = logic, - parameter type sram_cfg_tag_t = logic, - /// AXI request and response structures - parameter type axi_req_t = logic, - parameter type axi_rsp_t = logic + // Cacheable fetch region as base/mask; a zero mask caches every fetch + parameter logic [FetchAddrWidth-1:0] CachedRegionBase = '0, + parameter logic [FetchAddrWidth-1:0] CachedRegionMask = '0 ) ( input logic clk_i, input logic rst_ni, @@ -65,35 +62,41 @@ output logic [NumFetchPorts-1:0] flush_ready_o, // SRAM configs - input sram_cfg_data_t sram_cfg_data_i, - input sram_cfg_tag_t sram_cfg_tag_i, + input logic sram_cfg_data_i, + input logic sram_cfg_tag_i, // AXI interface - output axi_req_t axi_req_o, - input axi_rsp_t axi_rsp_i + output magia_tile_pkg::core_axi_instr_req_t axi_req_o, + input magia_tile_pkg::core_axi_instr_rsp_t axi_rsp_i ); logic [NumFetchPorts-1:0] fetch_valid, fetch_ready, fetch_rerror; logic [NumFetchPorts-1:0][FetchAddrWidth-1:0] fetch_addr; logic [NumFetchPorts-1:0][FetchDataWidth-1:0] fetch_rdata; + logic [NumFetchPorts-1:0] fetch_cacheable; + for (genvar i = 0; i < NumFetchPorts; i++) begin : gen_fetch_cacheable + assign fetch_cacheable[i] = + ((fetch_addr[i] & CachedRegionMask) == (CachedRegionBase & CachedRegionMask)); + end + for (genvar i = 0; i < NumFetchPorts; i++) begin : gen_request_cut logic gnt; assign fetch_gnt_o[i] = gnt & fetch_req_i[i]; spill_register #( - .T ( logic [FetchAddrWidth-1:0] ), - .Bypass ( 1'b0 ) + .T ( logic [FetchAddrWidth-1:0] ), + .Bypass ( 1'b0 ) ) i_spill_reg ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .valid_i ( fetch_req_i [i] ), - .ready_o ( gnt ), - .data_i ( fetch_addr_i [i] ), - .valid_o ( fetch_valid [i] ), - .ready_i ( fetch_ready [i] ), - .data_o ( fetch_addr [i] ) + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( fetch_req_i [i] ), + .ready_o ( gnt ), + .data_i ( fetch_addr_i [i] ), + .valid_o ( fetch_valid [i] ), + .ready_i ( fetch_ready [i] ), + .data_o ( fetch_addr [i] ) ); assign fetch_rdata_o [i] = fetch_rdata [i]; @@ -102,26 +105,26 @@ end snitch_icache #( - .NR_FETCH_PORTS ( NumFetchPorts ), - .L0_LINE_COUNT ( L0_LINE_COUNT ), - .LINE_WIDTH ( LINE_WIDTH ), - .LINE_COUNT ( LINE_COUNT ), - .WAY_COUNT ( WAY_COUNT ), - .FETCH_AW ( FetchAddrWidth ), - .FETCH_DW ( FetchDataWidth ), - .FILL_AW ( AxiAddrWidth ), - .FILL_DW ( AxiDataWidth ), - .FETCH_PRIORITY ( 1 ), - .MERGE_FETCHES ( 1 ), - .L1_TAG_SCM ( 1 ), - .SERIAL_LOOKUP ( 1 ), - .NUM_AXI_OUTSTANDING ( 4 ), // wouldn-t be better to expose this parameter? - .EARLY_LATCH ( 0 ), - .ISO_CROSSING ( 0 ), - .sram_cfg_data_t ( sram_cfg_data_t ), - .sram_cfg_tag_t ( sram_cfg_tag_t ), - .axi_req_t ( axi_req_t ), - .axi_rsp_t ( axi_rsp_t ) + .NR_FETCH_PORTS ( NumFetchPorts ), + .L0_LINE_COUNT ( L0_LINE_COUNT ), + .LINE_WIDTH ( LINE_WIDTH ), + .LINE_COUNT ( LINE_COUNT ), + .WAY_COUNT ( WAY_COUNT ), + .FETCH_AW ( FetchAddrWidth ), + .FETCH_DW ( FetchDataWidth ), + .FILL_AW ( AxiAddrWidth ), + .FILL_DW ( AxiDataWidth ), + .FETCH_PRIORITY ( 1 ), + .MERGE_FETCHES ( 1 ), + .L1_TAG_SCM ( 1 ), + .SERIAL_LOOKUP ( 1 ), + .NUM_AXI_OUTSTANDING ( 4 ), // wouldn-t be better to expose this parameter? + .EARLY_LATCH ( 0 ), + .ISO_CROSSING ( 0 ), + .sram_cfg_data_t ( logic ), + .sram_cfg_tag_t ( logic ), + .axi_req_t ( magia_tile_pkg::core_axi_instr_req_t ), + .axi_rsp_t ( magia_tile_pkg::core_axi_instr_rsp_t ) ) i_snitch_icache ( .clk_i ( clk_i ), .clk_d2_i ( clk_i ), @@ -135,7 +138,7 @@ .inst_addr_i ( fetch_addr ), .inst_data_o ( fetch_rdata ), - .inst_cacheable_i ( {NumFetchPorts{1'b1}} ), + .inst_cacheable_i ( fetch_cacheable ), .inst_valid_i ( fetch_valid ), .inst_ready_o ( fetch_ready ), .inst_error_o ( fetch_rerror ), diff --git a/hw/tile/magia_tile_pkg.sv b/hw/tile/magia_tile_pkg.sv index 67adcff6..df13b853 100644 --- a/hw/tile/magia_tile_pkg.sv +++ b/hw/tile/magia_tile_pkg.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -21,6 +21,15 @@ */ package magia_tile_pkg; + /*******************************************************************/ + /* Tile Configuration */ + /*******************************************************************/ + + // Selects which accelerators are instantiated inside the tile + typedef magia_pkg::magia_tile_cfg_t magia_tile_cfg_t; + + // Default: All Accelerators are instanstiated + localparam magia_tile_cfg_t MagiaTileDefaultCfg = magia_pkg::MagiaTileDefaultCfg; `include "hci_helpers.svh" `include "hwpe_ctrl_helpers.svh" @@ -35,24 +44,22 @@ package magia_tile_pkg; `include "../include/alias.svh" - // IRQ constraints - localparam int unsigned IRQ_IDX_REDMULE_EVT_0 = 31; - localparam int unsigned IRQ_IDX_REDMULE_EVT_1 = 30; - localparam int unsigned IRQ_IDX_A2O_ERROR = 29; - localparam int unsigned IRQ_IDX_O2A_ERROR = 28; - localparam int unsigned IRQ_IDX_A2O_DONE = 27; - localparam int unsigned IRQ_IDX_O2A_DONE = 26; - localparam int unsigned IRQ_IDX_A2O_START = 25; - localparam int unsigned IRQ_IDX_O2A_START = 24; - localparam int unsigned IRQ_IDX_A2O_BUSY = 23; - localparam int unsigned IRQ_IDX_O2A_BUSY = 22; - localparam int unsigned IRQ_IDX_REDMULE_BUSY = 21; - localparam int unsigned IRQ_IDX_FSYNC_DONE = 20; - localparam int unsigned IRQ_IDX_FSYNC_ERROR = 19; - localparam int unsigned IRQ_USED = 13; - // Address map - localparam logic [magia_pkg::ADDR_W-1:0] REDMULE_CTRL_ADDR_START = 32'h0000_0100; + + // Bases of the tile peripherals and of the tile window, default '0 +`ifdef MAGIA_TILE_PERIPH_BASE + localparam logic [magia_pkg::ADDR_W-1:0] TILE_PERIPH_BASE = `MAGIA_TILE_PERIPH_BASE; +`else + localparam logic [magia_pkg::ADDR_W-1:0] TILE_PERIPH_BASE = 32'h0000_0000; +`endif +`ifdef MAGIA_TILE_WINDOW_BASE + localparam logic [magia_pkg::ADDR_W-1:0] TILE_WINDOW_BASE = `MAGIA_TILE_WINDOW_BASE; +`else + localparam logic [magia_pkg::ADDR_W-1:0] TILE_WINDOW_BASE = 32'h0000_0000; +`endif + + // Peripherals (private): chained control registers + localparam logic [magia_pkg::ADDR_W-1:0] REDMULE_CTRL_ADDR_START = TILE_PERIPH_BASE + 32'h0000_0100; localparam logic [magia_pkg::ADDR_W-1:0] REDMULE_CTRL_SIZE = 32'h0000_0100; localparam logic [magia_pkg::ADDR_W-1:0] REDMULE_CTRL_ADDR_END = REDMULE_CTRL_ADDR_START + REDMULE_CTRL_SIZE; localparam logic [magia_pkg::ADDR_W-1:0] IDMA_CTRL_ADDR_START = REDMULE_CTRL_ADDR_END; @@ -64,91 +71,88 @@ package magia_tile_pkg; localparam logic [magia_pkg::ADDR_W-1:0] EVENT_UNIT_ADDR_START = FSYNC_CTRL_ADDR_END; localparam logic [magia_pkg::ADDR_W-1:0] EVENT_UNIT_SIZE = 32'h0000_1000; localparam logic [magia_pkg::ADDR_W-1:0] EVENT_UNIT_ADDR_END = EVENT_UNIT_ADDR_START + EVENT_UNIT_SIZE; - localparam logic [magia_pkg::ADDR_W-1:0] TILE_CSR_START = EVENT_UNIT_ADDR_END; - localparam logic [magia_pkg::ADDR_W-1:0] TILE_CSR_SIZE = 32'h0000_0200; - localparam logic [magia_pkg::ADDR_W-1:0] TILE_CSR_END = TILE_CSR_START + TILE_CSR_SIZE; - localparam logic [magia_pkg::ADDR_W-1:0] RESERVED_ADDR_START = TILE_CSR_END; - localparam logic [magia_pkg::ADDR_W-1:0] RESERVED_ADDR_END = 32'h0000_FFFF; + localparam logic [magia_pkg::ADDR_W-1:0] SPATZ_CTRL_ADDR_START = EVENT_UNIT_ADDR_END; + localparam logic [magia_pkg::ADDR_W-1:0] SPATZ_CTRL_SIZE = 32'h0000_0040; + localparam logic [magia_pkg::ADDR_W-1:0] SPATZ_CTRL_ADDR_END = SPATZ_CTRL_ADDR_START + SPATZ_CTRL_SIZE; + localparam logic [magia_pkg::ADDR_W-1:0] CLUSTER_CTRL_ADDR_START = SPATZ_CTRL_ADDR_END; + localparam logic [magia_pkg::ADDR_W-1:0] CLUSTER_CTRL_SIZE = 32'h0000_00C0; + localparam logic [magia_pkg::ADDR_W-1:0] CLUSTER_CTRL_ADDR_END = CLUSTER_CTRL_ADDR_START + CLUSTER_CTRL_SIZE; + localparam logic [magia_pkg::ADDR_W-1:0] COLL_CTRL_ADDR_START = CLUSTER_CTRL_ADDR_END; + localparam logic [magia_pkg::ADDR_W-1:0] COLL_CTRL_SIZE = 32'h0000_0100; + localparam logic [magia_pkg::ADDR_W-1:0] COLL_CTRL_ADDR_END = COLL_CTRL_ADDR_START + COLL_CTRL_SIZE; + localparam logic [magia_pkg::ADDR_W-1:0] TILE_PERIPH_ADDR_END = COLL_CTRL_ADDR_END; + + // Reserved (private): software scratch, such as the print buffer + localparam logic [magia_pkg::ADDR_W-1:0] RESERVED_ADDR_START = TILE_WINDOW_BASE + (TILE_PERIPH_ADDR_END - TILE_PERIPH_BASE); + localparam logic [magia_pkg::ADDR_W-1:0] RESERVED_ADDR_END = TILE_WINDOW_BASE + 32'h0001_0000; + + // Stack (private) localparam logic [magia_pkg::ADDR_W-1:0] STACK_ADDR_START = RESERVED_ADDR_END; localparam logic [magia_pkg::ADDR_W-1:0] STACK_SIZE = 32'h0001_0000; localparam logic [magia_pkg::ADDR_W-1:0] STACK_ADDR_END = STACK_ADDR_START + STACK_SIZE; + + // L1 (shared) localparam logic [magia_pkg::ADDR_W-1:0] L1_ADDR_START = STACK_ADDR_END; localparam logic [magia_pkg::ADDR_W-1:0] L1_SIZE = 32'h000E_0000; localparam logic [magia_pkg::ADDR_W-1:0] L1_ADDR_END = L1_ADDR_START + L1_SIZE; localparam logic [magia_pkg::ADDR_W-1:0] L1_TILE_OFFSET = 32'h0010_0000; - localparam logic [magia_pkg::ADDR_W-1:0] L2_ADDR_START = 32'hB000_0000; - localparam logic [magia_pkg::ADDR_W-1:0] L2_SIZE = 32'h5000_0000; + localparam logic [magia_pkg::ADDR_W-1:0] TILES_ADDR_END = TILE_WINDOW_BASE + magia_pkg::N_TILES*L1_TILE_OFFSET; // End of all tile windows + + // Collectives and L2 (global) + localparam logic [magia_pkg::ADDR_W-1:0] COLL_ADDR_START = 32'hB000_0000 + TILE_WINDOW_BASE; // collective_gen maps it onto the tile windows + localparam logic [magia_pkg::ADDR_W-1:0] COLL_ADDR_END = 32'hB000_0000 + TILES_ADDR_END; + localparam logic [magia_pkg::ADDR_W-1:0] L2_ADDR_START = 32'hC000_0000; + localparam logic [magia_pkg::ADDR_W-1:0] L2_SIZE = 32'h4000_0000; localparam logic [magia_pkg::ADDR_W-1:0] L2_ADDR_END = L2_ADDR_START + L2_SIZE; // Instruction region for Spatz code (cacheable region) localparam logic [magia_pkg::ADDR_W-1:0] INSTRRAM_ADDR_START = 32'hCC00_0000; - localparam logic [magia_pkg::ADDR_W-1:0] INSTRRAM_SIZE = 32'h0000_8000; // 32KB localparam logic [magia_pkg::ADDR_W-1:0] INSTRRAM_PMA_MASK = 32'hFFFF_8000; - // Snitch PMA Configuration - defines cacheable regions for instruction fetches - localparam snitch_pma_pkg::snitch_pma_t SPATZ_SNITCH_PMA_CFG = '{ - NrCachedRegionRules: 1, - CachedRegion: '{ - 0: '{base: INSTRRAM_ADDR_START, mask: INSTRRAM_PMA_MASK}, - default: '0 - }, - default: 0 - }; - - //SPATZ PARAMETERS from Makefile defines - //SPATZ_RVD (Double-width vector extension support) - `ifdef SPATZ_RVD - localparam bit SPATZ_RVD_PARAM = `SPATZ_RVD; - `else - localparam bit SPATZ_RVD_PARAM = 1'b0; - `endif - - //SPATZ_N_IPU and SPATZ_N_FPU - `ifdef SPATZ_N_IPU - localparam int unsigned SPATZ_NUM_IPU = `SPATZ_N_IPU; - `else - localparam int unsigned SPATZ_NUM_IPU = 1; - `endif - - `ifdef SPATZ_N_FPU - localparam int unsigned SPATZ_NUM_FPU = `SPATZ_N_FPU; - `else - localparam int unsigned SPATZ_NUM_FPU = 4; - `endif - - //SPATZ_XDIVSQRT (FP division/sqrt enable) - `ifdef SPATZ_XDIVSQRT - localparam bit SPATZ_XDIVSQRT_PARAM = `SPATZ_XDIVSQRT; - `else - localparam bit SPATZ_XDIVSQRT_PARAM = 1'b0; - `endif - - //SPATZ_XDMA (DMA inside Spatz_cc) - `ifdef SPATZ_XDMA - localparam bit SPATZ_XDMA_PARAM = `SPATZ_XDMA; - `else - localparam bit SPATZ_XDMA_PARAM = 1'b0; - `endif - - //SPATZ_RVF (Single-precision FP support) - `ifdef SPATZ_RVF - localparam bit SPATZ_RVF_PARAM = `SPATZ_RVF; - `else - localparam bit SPATZ_RVF_PARAM = 1'b1; - `endif + // Snitch PMA with one cacheable instruction region + function automatic snitch_pma_pkg::snitch_pma_t gen_spatz_pma_cfg(logic [magia_pkg::ADDR_W-1:0] base, + logic [magia_pkg::ADDR_W-1:0] mask); + snitch_pma_pkg::snitch_pma_t cfg; + cfg = '0; + cfg.NrCachedRegionRules = 1; + cfg.CachedRegion[0] = '{base: 48'(base), mask: 48'(mask)}; // Snitch PMA rules are 48 bit + return cfg; + endfunction + + localparam snitch_pma_pkg::snitch_pma_t SPATZ_SNITCH_PMA_CFG = gen_spatz_pma_cfg(INSTRRAM_ADDR_START, INSTRRAM_PMA_MASK); + + // Spatz parameters + + localparam bit SPATZ_RVD_PARAM = magia_pkg::MagiaSpatzRVD; + localparam int unsigned SPATZ_NUM_IPU = magia_pkg::MagiaSpatzNumIPU; + localparam int unsigned SPATZ_NUM_FPU = magia_pkg::MagiaSpatzNumFPU; + localparam bit SPATZ_XDIVSQRT_PARAM = magia_pkg::MagiaSpatzXDivSqrt; + localparam bit SPATZ_XDMA_PARAM = magia_pkg::MagiaSpatzXDMA; + localparam bit SPATZ_RVF_PARAM = magia_pkg::MagiaSpatzRVF; + localparam bit SPATZ_RVV_PARAM = magia_pkg::MagiaSpatzRVV; - //SPATZ_RVV (Vector extension support) - `ifdef SPATZ_RVV - localparam bit SPATZ_RVV_PARAM = `SPATZ_RVV; - `else - localparam bit SPATZ_RVV_PARAM = 1'b1; - `endif - - // Spatz CC parameters (must be defined before HCI parameters) - localparam int unsigned SPATZ_NUM_FU = (SPATZ_NUM_FPU > SPATZ_NUM_IPU) ? SPATZ_NUM_FPU : SPATZ_NUM_IPU; // Max of FPU and IPU - localparam int unsigned SPATZ_TCDM_PORTS = SPATZ_NUM_FU + 1; // N_FU + 1 TCDM ports (N_FU vector + 1 snitch) - localparam int unsigned SPATZ_HCI_PORTS = SPATZ_RVD_PARAM ? (SPATZ_TCDM_PORTS * 2) : SPATZ_TCDM_PORTS; // RVD=1: 2xTCDM HCI32, RVD=0: 1xTCDM HCI32 + function automatic int unsigned gen_spatz_num_fu(magia_pkg::spatz_cfg_t cfg); + return (cfg.NumFPU > cfg.NumIPU) ? cfg.NumFPU : cfg.NumIPU; + endfunction + + function automatic int unsigned gen_spatz_tcdm_ports(magia_pkg::spatz_cfg_t cfg); + return cfg.RVV ? (gen_spatz_num_fu(cfg) + 1) : 1; + endfunction + + function automatic int unsigned gen_spatz_hci_ports(magia_pkg::spatz_cfg_t cfg); + return cfg.RVD ? (gen_spatz_tcdm_ports(cfg) * 2) : gen_spatz_tcdm_ports(cfg); + endfunction + + function automatic int unsigned gen_tile_spatz_hci_ports(magia_tile_cfg_t cfg); + return cfg.EnSpatzCC ? gen_spatz_hci_ports(cfg.Spatz) : 0; + endfunction + + function automatic int unsigned gen_tile_num_hci_core(magia_tile_cfg_t cfg); + // ctrl core + Spatz TCDM ports + one dedicated L1/TCDM port per cluster core + return 1 + gen_tile_spatz_hci_ports(cfg) + (cfg.EnCluster ? cfg.Cluster.NumCores : 0); + endfunction + localparam int unsigned SPATZ_HCI_PORTS = gen_spatz_hci_ports(magia_pkg::MagiaSpatzDefaultCfg); // Spatz CC outstanding transactions and timing parameters parameter int unsigned SPATZ_NUM_INT_OUTSTANDING_LOADS = 1; // Snitch core outstanding loads @@ -212,8 +216,12 @@ package magia_tile_pkg; }; // Spatz bootrom parameters +`ifdef MAGIA_SPATZ_BOOT_ADDR + parameter logic [31:0] SPATZ_BOOT_ADDR = `MAGIA_SPATZ_BOOT_ADDR; // Spatz bootrom base address +`else parameter logic [31:0] SPATZ_BOOT_ADDR = 32'h1000_0000; // Spatz bootrom base address - parameter logic [31:0] SPATZ_BOOTROM_SIZE = 32'h0000_00FF; +`endif + parameter logic [31:0] SPATZ_BOOTROM_SIZE = 32'h0000_0100; // Spatz TCDM parameters parameter int unsigned SPATZ_TCDM_ADDR_WIDTH = $clog2(magia_pkg::N_MEM_BANKS * magia_pkg::N_WORDS_BANK * magia_pkg::DATA_W / 8); @@ -222,8 +230,9 @@ package magia_tile_pkg; // Parameters used by the HCI + parameter int unsigned N_CLUSTER_CORES = magia_pkg::MagiaClusterDefaultCfg.NumCores; // Upper bound for TileCfg.Cluster.NumCores parameter int unsigned N_HWPE = 1; // Number of HWPEs attached to the port - parameter int unsigned N_CORE = 1 + SPATZ_HCI_PORTS; // Number of core-side HCI ports (CV32 + Spatz TCDM ports) + parameter int unsigned N_CORE = 1 + SPATZ_HCI_PORTS + N_CLUSTER_CORES; // MAX core-side HCI ports (ctrl + Spatz + cluster); actual count from gen_tile_num_hci_core(), only sizes IW parameter int unsigned N_DMA = 4; // Number of DMA ports (1 out read channel, 1 out write channel, 1 in read channel and 1 in write channel) typedef enum logic[1:0]{ HCI_DMA_OUT_CH_READ_IDX = 2'b00, @@ -235,23 +244,16 @@ package magia_tile_pkg; parameter int unsigned AWC = magia_pkg::ADDR_W; // Address width core (slave ports) parameter int unsigned DW_LIC = magia_pkg::DATA_W; // Data Width for Log Interconnect parameter int unsigned BW_LIC = magia_pkg::BYTE_W; // Byte Width for Log Interconnect - localparam int unsigned AWM = - $clog2(magia_pkg::N_WORDS_BANK*DW_LIC/BW_LIC); // Address width memory (master ports) parameter int unsigned UW_LIC = magia_pkg::USR_W; // User Width for Log Interconnect localparam int unsigned SW_LIC = DW_LIC/BW_LIC; // Strobe Width for Log Interconnect - localparam int unsigned WD_LIC = DW_LIC/DW_LIC; // Number of words per data for Log Interconnect - parameter int unsigned TS_BIT = 21; // TEST_SET_BIT (for Log Interconnect) parameter int unsigned IW = N_HWPE+N_CORE+N_DMA+N_EXT; // ID Width HCI parameter int unsigned EXPFIFO = 0; // FIFO Depth for HWPE Interconnect - parameter int unsigned DWH = 288; // Data Width for HWPE Interconnect: RedMulE Hx(P+1)xBits + Bank width for misaligned + parameter int unsigned DWH = magia_pkg::MagiaRedMuleDefaultCfg.Height * + (magia_pkg::MagiaRedMuleDefaultCfg.NumPipeRegs + 1) * 16 + 32; parameter int unsigned AWH = magia_pkg::ADDR_W; // Address Width for HWPE Interconnect parameter int unsigned BWH = magia_pkg::BYTE_W; // Byte Width for HWPE Interconnect - parameter int unsigned WWH = DWH; // Word Width for HWPE Interconnect - parameter int unsigned OWH = AWH; // Offset Width for HWPE Interconnect parameter int unsigned UWH = magia_pkg::USR_W; // User Width for HWPE Interconnect - parameter int unsigned SEL_LIC = 1; // Log interconnect type selector localparam int unsigned SWH = DWH/BWH; // Strobe Width for HWPE Interconnect - localparam int unsigned WDH = DWH/WWH; // Number of words per data for HWPE Interconnect // Parameters used by the cv32e40x core parameter bit X_EXT_EN = 1; // Enable eXtension Interface (X) support, see eXtension Interface @@ -266,9 +268,7 @@ package magia_tile_pkg; parameter bit CLIC_EN = 1'b0; // Specifies whether Smclic, Smclicshv and Smclicconfig are supported // Parameters used by cv32e40p core - parameter bit PULP_CLUSTER = 1'b1; // PULP cluster mode parameter bit FPU = 1'b1; // Enable FPU (main feature) - parameter bit FP_DIVSQRT = 1'b1; // FP division and square root parameter logic[31:0] DM_HALT_ADDR = 32'h1A110800; // Debug module halt address `ifdef ZFINX_CTRL @@ -293,16 +293,7 @@ package magia_tile_pkg; `endif parameter int unsigned CLIC_ID_W_CLUSTER = 5; // cv32e40p irq_id_o/irq_id_i width (fixed, independent of the ctrl core's CLIC_ID_W) - // Parameters used by Event Unit - parameter int unsigned EVENT_UNIT_IRQ_WIDTH = 5; // Width of Event Unit IRQ ID signals (supports up to 32 different event types) - - // Parameters used by RedMulE - parameter int unsigned REDMULE_HEIGHT = 8; // RedMulE systolic array height - parameter int unsigned REDMULE_WIDTH = 8; // RedMulE systolic array width - parameter int unsigned REDMULE_NUM_PIPE_REGS = 1; // RedMulE pipeline registers - parameter int unsigned REDMULE_DW = DWH-32; // RedMulE Data Width - parameter int unsigned REDMULE_ID_W = magia_pkg::ID_W + - magia_pkg::ID_W_OFFSET; // RedMulE ID Width + parameter int unsigned REDMULE_DW = DWH-32; // RedMulE Data Width (default; per-tile in magia_tile.sv) parameter int unsigned REDMULE_UW = UWH; // RedMulE User Width // Parameters used by OBI @@ -314,23 +305,140 @@ package magia_tile_pkg; parameter int unsigned AID_WIDTH = 1; // Width of the aid signal (address channel identifier, see OBI documentation) parameter int unsigned RID_WIDTH = 1; // Width of the rid signal (response channel identifier, see OBI documentation) parameter int unsigned MID_WIDTH = 1; // Width of the mid signal (manager identifier, see OBI documentation) - parameter int unsigned OBI_ID_WIDTH = 1; - parameter int unsigned N_CLUSTER_CORES = 8; // Width of the id - configuration - parameter int unsigned N_SBR = 7; // Number of OBI slaves (HCI, AXI XBAR, RedMulE_Ctrl, iDMA_Ctrl, FSync_Ctrl, Event_Unit, Spatz_Ctrl) - parameter int unsigned N_MGR = 3 + N_CLUSTER_CORES; // Number of masters (Core, AXI XBAR, Spatz CC) + parameter int unsigned OBI_ID_WIDTH = 1; parameter int unsigned N_MAX_TRAN = 1; // Number of maximum outstanding transactions - parameter int unsigned N_ADDR_RULE = 9; // Number of OBI address rules (L2, L1, Stack, Reserved, RedMulE_Ctrl, iDMA_Ctrl, FSync_Ctrl, Event_Unit, Spatz_Ctrl) - localparam int unsigned N_BIT_SBR = $clog2(N_SBR); // Number of bits required to identify each slave - localparam int unsigned N_BIT_MGR = $clog2(N_MGR); // Number of bits required to identify each master - localparam int unsigned N_BIT_CLUSTER_CORES = $clog2(N_CLUSTER_CORES); // Number of bits required to identify each slave + + function automatic int unsigned gen_idx_width(int unsigned num); + return (num > 1) ? $clog2(num) : 1; + endfunction + + typedef struct packed { + int unsigned num_mgr; // Number of managers attached to the crossbar + int unsigned core; // Ctrl core data port + int unsigned ext; // External (AXI-to-OBI) port + int unsigned spatz; // Spatz CC data port (valid iff EnSpatzCC) + int unsigned cluster_base; // First cluster core port (valid iff EnCluster) + } obi_mgr_map_t; + + function automatic obi_mgr_map_t gen_obi_mgr_map(magia_tile_cfg_t cfg); + obi_mgr_map_t ret; + int unsigned idx; + ret = '0; + idx = 0; + ret.core = idx; + idx = idx + 1; + ret.ext = idx; + idx = idx + 1; + if (cfg.EnSpatzCC) begin + ret.spatz = idx; + idx = idx + 1; + end + if (cfg.EnCluster) begin + ret.cluster_base = idx; + idx += cfg.Cluster.NumCores; // per-tile cluster core count (<= N_CLUSTER_CORES max) + end + ret.num_mgr = idx; + return ret; + endfunction + + // Control units share one crossbar port through ctrl_demux; the EU keeps its own, its responses wait + localparam int unsigned CTRL_MAX_UNITS = 6; + + typedef struct packed { + int unsigned num_units; // Number of units behind the control port (one address rule each) + int unsigned redmule; // RedMulE control (valid iff EnRedMule) + int unsigned idma; // iDMA control + int unsigned fsync; // FractalSync control (valid iff MAGIA_FSYNC) + int unsigned spatz; // Spatz CC control (valid iff EnSpatzCC) + int unsigned cluster; // PULP cluster control (valid iff EnCluster) + int unsigned coll; // Collective control (valid iff EnCollective) + } ctrl_map_t; + + function automatic ctrl_map_t gen_ctrl_map(magia_tile_cfg_t cfg); + ctrl_map_t ret; + int unsigned idx; + ret = '0; + idx = 0; + if (cfg.EnRedMule) begin + ret.redmule = idx; + idx = idx + 1; + end + ret.idma = idx; + idx = idx + 1; + if (magia_pkg::MagiaEnFractalSync) begin + ret.fsync = idx; + idx = idx + 1; + end + if (cfg.EnSpatzCC) begin + ret.spatz = idx; + idx = idx + 1; + end + if (cfg.EnCluster) begin + ret.cluster = idx; + idx = idx + 1; + end + if (cfg.EnCollective) begin + ret.coll = idx; + idx = idx + 1; + end + ret.num_units = idx; + return ret; + endfunction + + typedef struct packed { + int unsigned num_sbr; // Number of subordinates attached to the crossbar + int unsigned num_rules; // Number of address decode rules + int unsigned l2; // AXI crossbar (L2) port - must stay 0: it is the crossbar default port + int unsigned l1; // L1 SPM (HCI) port + int unsigned eu; // Event Unit port + int unsigned ctrl; // Control port (every control-register unit, see ctrl_map_t) + } obi_sbr_map_t; + + function automatic obi_sbr_map_t gen_obi_sbr_map(magia_tile_cfg_t cfg); + obi_sbr_map_t ret; + ret = '0; + ret.l2 = 0; + ret.l1 = 1; + ret.eu = 2; + ret.ctrl = 3; + ret.num_sbr = 4; + // L2, L1, reserved, stack, EU and the control window around it + ret.num_rules = 7; + return ret; + endfunction + + /*******************************************************************/ + /* Event Unit event map */ + /*******************************************************************/ + localparam int unsigned EU_ACC_SPATZ_DONE = 0; + localparam int unsigned EU_ACC_REDMULE_EVT_0 = 2; + localparam int unsigned EU_ACC_REDMULE_EVT_1 = 3; + + localparam int unsigned EU_DMA_A2O_DONE = 0; + localparam int unsigned EU_DMA_O2A_DONE = 1; + + localparam int unsigned EU_OTHER_CLUSTER_DONE = 12; + localparam int unsigned EU_OTHER_SPATZ_START = 23; + localparam int unsigned EU_OTHER_FSYNC_DONE = 24; + localparam int unsigned EU_OTHER_A2O_START = 28; + localparam int unsigned EU_OTHER_O2A_START = 29; + + typedef struct packed { + logic [1:0] evt; // evt[0]: engine event (RedMulE evt_o); evt[1]: reserved, always 0 + } redmule_events_t; + + // The assembled event bus handed to magia_event_unit (control core only). + typedef struct packed { + logic [3:0] acc; + logic [1:0] dma; + logic [1:0] timer; + logic [31:0] other; + } eu_events_t; // Parameters used by AXI parameter int unsigned AXI_DATA_ID_W = 3; // Width of the AXI Data ID (3 bits for 5 slave ports on crossbar: 2^3=8) - parameter int unsigned AXI_INSTR_ID_W = 3; // Width of the AXI Instruction ID (3 bits for 5 slave ports on crossbar) parameter int unsigned AXI_ID_W = 3; // Width of the AXI Unified Communication Channel ID (3 bits for 5 slave ports) - localparam int unsigned AXI_MST_ID_W = 6; // Width of master port ID (slave 3b + prepend 3b for 5 ports) parameter int unsigned AXI_DATA_U_W = magia_pkg::USR_W; // Width of the AXI Data User - parameter int unsigned AXI_INSTR_U_W = magia_pkg::USR_W; // Width of the AXI Instruction User parameter int unsigned AXI_U_W = magia_pkg::USR_W; // Width of the AXI Unified Communication Channel User // Parameters used by the iDMA @@ -371,21 +479,14 @@ package magia_tile_pkg; parameter int unsigned FSYNC_NBR_AGGR_W = 1; // Fractal Sync Aggr. width for neighbor nodes parameter int unsigned FSYNC_NBR_LVL_W = 1; // Fractal Sync Level width for neighbor nodes parameter int unsigned FSYNC_NBR_ID_W = 2; // Fractal Sync Id width for neighbor nodes - parameter bit FSYNC_STALL = 1; // Fractal Sync Stall during synchronization // Parameters of the AXI XBAR parameter int unsigned AxiXbarNoSlvPorts = 5; // Number of Slave Ports (ext, Core Data, CV32 I$, Spatz I$, Cluster I$) - parameter int unsigned AxiXbarNoMstPorts = 3; // Number of Master Ports (to ext, to internal L1, to Spatz bootrom) localparam int unsigned AxiXbarSlvAxiIDWidth = AXI_DATA_ID_W; // Number of bits to indentify each Slave Port parameter int unsigned AxiXbarMaxWTrans = 16; // Maximum number of outstanding transactions per write parameter int unsigned AxiXbarMaxMstTrans = AxiXbarMaxWTrans; // Maximum number of outstanding transactions per master parameter int unsigned AxiXbarMaxSlvTrans = AxiXbarMaxWTrans; // Maximum number of outstanding transactions per slave parameter bit AxiXbarFallThrough = 1'b0; // Enabled -> MUX is purely combinational - parameter bit AxiXbarSpillAw = 1'b0; // Enabled -> Spill register on write master ports, +1 cycle of latency on read channels - parameter bit AxiXbarSpillW = 1'b0; // Enabled -> Spill register on write master ports, +1 cycle of latency on read channels - parameter bit AxiXbarSpillB = 1'b0; // Enabled -> Spill register on write master ports, +1 cycle of latency on read channels - parameter bit AxiXbarSpillAr = 1'b0; // Enabled -> Spill register on read master ports, +1 cycle of latency on write channels - parameter bit AxiXbarSpillR = 1'b0; // Enabled -> Spill register on read master ports, +1 cycle of latency on write channels // Parameters used by the i$ parameter int unsigned NR_FETCH_PORTS = 1; // i$ Number of request (fetch) ports @@ -394,26 +495,13 @@ package magia_tile_pkg; parameter int unsigned LINE_COUNT = 32; // i$ The number of cache lines per set. Power of two; >= 2. parameter int unsigned WAY_COUNT = 32; // i$ The set associativity of the cache. Power of two; >= 1. parameter int unsigned L0_PARITY_W = 0; // i$ Parity of the L0 cache - parameter int unsigned L1_PARITY_W = L0_PARITY_W; // i$ Parity of the L1 cache parameter int unsigned FETCH_AW = magia_pkg::ADDR_W; // i$ Fetch interface address width. Same as FETCH_AW; >= 1. parameter int unsigned FETCH_DW = magia_pkg::DATA_W; // i$ Fetch interface data width. Power of two; >= 8. parameter int unsigned FILL_AW = magia_pkg::ADDR_W; // i$ Fill interface address width. Same as FILL_AW; >= 1. parameter int unsigned FILL_DW = magia_pkg::DATA_W; // i$ Fill interface data width. Power of two; >= 8. - // Spatz ICache parameters (dedicated icache for Spatz CC) - parameter int unsigned SPATZ_ICACHE_LINE_WIDTH = 256; // Spatz i$ cache line width (should be investigated which is the best value) - parameter int unsigned SPATZ_ICACHE_LINE_COUNT = 32; // Spatz i$ number of cache lines - parameter int unsigned SPATZ_ICACHE_WAYS = 2; // Spatz i$ number of ways (2-way set associative) - localparam int unsigned SPATZ_L0_EARLY_TAG_W = snitch_pkg::PAGE_SHIFT - $clog2(SPATZ_ICACHE_LINE_WIDTH/8); // L0 early tag width - //Cluster ICache parameters (dedicated icache for cluster cores) - parameter int unsigned CLUSTER_NR_FETCH_PORTS = N_CLUSTER_CORES; // i$ Number of request (fetch) ports - parameter int unsigned CLUSTER_L0_LINE_COUNT = 32*N_CLUSTER_CORES; // i$ L0 Cache Line Count - parameter int unsigned CLUSTER_LINE_WIDTH = 128; // i$ Cache Line Width; >= 64 - parameter int unsigned CLUSTER_LINE_COUNT = 32*N_CLUSTER_CORES; // i$ The number of cache lines per set. Power of two; >= 2. - parameter int unsigned CLUSTER_WAY_COUNT = 32; // i$ The set associativity of the cache. Power of two; >= 1. parameter int unsigned CLUSTER_L0_PARITY_W = 0; // i$ Parity of the L0 cache - parameter int unsigned CLUSTER_L1_PARITY_W = CLUSTER_L0_PARITY_W; // i$ Parity of the L1 cache parameter int unsigned CLUSTER_FETCH_AW = magia_pkg::ADDR_W; // i$ Fetch interface address width. Same as FETCH_AW; >= 1. parameter int unsigned CLUSTER_FETCH_DW = magia_pkg::DATA_W; // i$ Fetch interface data width. Power of two; >= 8. parameter int unsigned CLUSTER_FILL_AW = magia_pkg::ADDR_W; // i$ Fill interface address width. Same as FILL_AW; >= 1. @@ -449,11 +537,35 @@ package magia_tile_pkg; logic[magia_pkg::ADDR_W-1:0] end_addr; } obi_xbar_rule_t; - typedef enum logic[1:0]{ - OBI_SPATZ_IDX = 2, - OBI_EXT_IDX = 1, - OBI_CORE_IDX = 0 - } obi_xbar_idx_e; + // TCDM ranges taken by the dedicated HCI ports: the shared L1, reserved and stack go through OBI + localparam int unsigned NUM_TCDM_RULES = 1; + + typedef obi_xbar_rule_t [CTRL_MAX_UNITS-1:0] ctrl_rules_t; + + // One rule per ctrl_demux port as in gen_ctrl_map(); a disabled unit's range falls to L2 and is flagged + function automatic ctrl_rules_t gen_ctrl_rules(magia_tile_cfg_t cfg); + ctrl_rules_t ret; + ctrl_map_t map; + ret = '0; + map = gen_ctrl_map(cfg); + if (cfg.EnRedMule) begin + ret[map.redmule] = '{idx: map.redmule, start_addr: REDMULE_CTRL_ADDR_START, end_addr: REDMULE_CTRL_ADDR_END}; + end + ret[map.idma] = '{idx: map.idma, start_addr: IDMA_CTRL_ADDR_START, end_addr: IDMA_CTRL_ADDR_END}; + if (magia_pkg::MagiaEnFractalSync) begin + ret[map.fsync] = '{idx: map.fsync, start_addr: FSYNC_CTRL_ADDR_START, end_addr: FSYNC_CTRL_ADDR_END}; + end + if (cfg.EnSpatzCC) begin + ret[map.spatz] = '{idx: map.spatz, start_addr: SPATZ_CTRL_ADDR_START, end_addr: SPATZ_CTRL_ADDR_END}; + end + if (cfg.EnCluster) begin + ret[map.cluster] = '{idx: map.cluster, start_addr: CLUSTER_CTRL_ADDR_START, end_addr: CLUSTER_CTRL_ADDR_END}; + end + if (cfg.EnCollective) begin + ret[map.coll] = '{idx: map.coll, start_addr: COLL_CTRL_ADDR_START, end_addr: COLL_CTRL_ADDR_END}; + end + return ret; + endfunction typedef struct packed { @@ -542,18 +654,6 @@ package magia_tile_pkg; logic[NR_FETCH_PORTS-1:0] rerror; } core_cache_instr_rsp_t; - typedef enum logic[3:0]{ - OBI_XBAR_STACK_IDX = 8, - OBI_XBAR_RESERVED_IDX = 7, - OBI_XBAR_TILE_CSR_IDX = 6, - OBI_XBAR_EVENT_UNIT_IDX = 5, - OBI_XBAR_FSYNC_CTRL_IDX = 4, - OBI_XBAR_IDMA_IDX = 3, - OBI_XBAR_REDMULE_CTRL_IDX = 2, - OBI_XBAR_L1SPM_IDX = 1, - OBI_XBAR_L2_IDX = 0 - } obi_mem_array_idx_e; - typedef enum logic[2:0]{ AXI_XBAR_STACK_IDX = 4, AXI_XBAR_RESERVED_IDX = 3, @@ -580,8 +680,8 @@ package magia_tile_pkg; typedef logic[iDMA_AddrWidth-1:0] idma_addr_t; - `HWPE_CTRL_TYPEDEF_REQ_T(redmule_ctrl_req_t, logic[AWC-1:0], logic[DWH-1:0], logic[SWH-1:0], logic[IW-1:0]) - `HWPE_CTRL_TYPEDEF_RSP_T(redmule_ctrl_rsp_t, logic[DWH-1:0], logic[IW-1:0]) + `HWPE_CTRL_TYPEDEF_REQ_T(redmule_ctrl_req_t, logic[AWC-1:0], logic[magia_pkg::DATA_W-1:0], logic[magia_pkg::STRB_W-1:0], logic[hci_package::DEFAULT_IW-1:0]) + `HWPE_CTRL_TYPEDEF_RSP_T(redmule_ctrl_rsp_t, logic[magia_pkg::DATA_W-1:0], logic[hci_package::DEFAULT_IW-1:0]) `HCI_TYPEDEF_REQ_T(redmule_data_req_t, logic[AWC-1:0], logic[DWH-1:0], logic[SWH-1:0], logic[UWH-1:0], logic[IW-1:0], logic[0:0], logic[0:0]) `HCI_TYPEDEF_RSP_T(redmule_data_rsp_t, logic[DWH-1:0], logic[UWH-1:0], logic[IW-1:0], logic[0:0], logic[0:0]) @@ -593,9 +693,6 @@ package magia_tile_pkg; localparam obi_pkg::obi_cfg_t obi_amo_cfg = obi_pkg::obi_default_cfg(magia_pkg::ADDR_W, magia_pkg::DATA_W, OBI_ID_WIDTH, obi_amo_optional_cfg); localparam obi_pkg::obi_cfg_t obi_no_amo_cfg = obi_pkg::obi_default_cfg(magia_pkg::ADDR_W, magia_pkg::DATA_W, OBI_ID_WIDTH, obi_no_amo_optional_cfg); - // OBI full configurations - 64-bit - localparam obi_pkg::obi_cfg_t obi_amo_cfg_64 = obi_pkg::obi_default_cfg(magia_pkg::ADDR_W, SPATZ_TCDM_DATA_WIDTH, OBI_ID_WIDTH, obi_amo_optional_cfg); - localparam obi_pkg::obi_cfg_t obi_no_amo_cfg_64 = obi_pkg::obi_default_cfg(magia_pkg::ADDR_W, SPATZ_TCDM_DATA_WIDTH, OBI_ID_WIDTH, obi_no_amo_optional_cfg); localparam bit RegisterAmo = 1; `OBI_TYPEDEF_ALL_A_OPTIONAL(core_data_obi_a_optional_t, AUSER_WIDTH, WUSER_WIDTH, MID_WIDTH, ACHK_WIDTH) @@ -657,7 +754,7 @@ package magia_tile_pkg; localparam axi_pkg::xbar_cfg_t axi_xbar_cfg = '{ NoSlvPorts : AxiXbarNoSlvPorts, - NoMstPorts : AxiXbarNoMstPorts, + NoMstPorts : 0, // placeholder: gen_axi_xbar_cfg() fills it from gen_axi_xbar_mst_map() MaxMstTrans : AxiXbarMaxMstTrans, MaxSlvTrans : AxiXbarMaxSlvTrans, FallThrough : AxiXbarFallThrough, @@ -668,9 +765,48 @@ package magia_tile_pkg; UniqueIds : 1'b0, AxiAddrWidth : magia_pkg::ADDR_W, AxiDataWidth : magia_pkg::DATA_W, - NoAddrRules : 4 + NoAddrRules : 0, // placeholder: gen_axi_xbar_cfg() fills it from gen_axi_xbar_num_rules() + default : '0 // Fields of newer axi revisions }; + typedef struct packed { + int unsigned num_mst; // Number of AXI xbar master ports + int unsigned ext; // to NoC (always, index 0) + int unsigned obi; // to internal OBI (always, index 1) + int unsigned bootrom; // to Spatz bootrom (valid iff EnSpatzCC) + } axi_xbar_mst_map_t; + + function automatic axi_xbar_mst_map_t gen_axi_xbar_mst_map(magia_tile_cfg_t cfg); + axi_xbar_mst_map_t ret; + int unsigned idx; + ret = '0; + idx = 0; + ret.ext = idx; + idx = idx + 1; + ret.obi = idx; + idx = idx + 1; + if (cfg.EnSpatzCC) begin + ret.bootrom = idx; + idx = idx + 1; + end + ret.num_mst = idx; + return ret; + endfunction + + function automatic int unsigned gen_axi_xbar_num_rules(magia_tile_cfg_t cfg); + return 1 + 32'(cfg.EnSpatzCC); + endfunction + + function automatic axi_pkg::xbar_cfg_t gen_axi_xbar_cfg(magia_tile_cfg_t cfg); + axi_pkg::xbar_cfg_t ret; + axi_xbar_mst_map_t mst_map; + mst_map = gen_axi_xbar_mst_map(cfg); + ret = axi_xbar_cfg; + ret.NoMstPorts = mst_map.num_mst; + ret.NoAddrRules = gen_axi_xbar_num_rules(cfg); + return ret; + endfunction + `FSYNC_TYPEDEF_ALL(ht_tile_fsync, logic[FSYNC_AGGR_W-1:0], logic[FSYNC_LVL_W-1:0], logic[FSYNC_ID_W-1:0]) `FSYNC_TYPEDEF_ALL(vt_tile_fsync, logic[FSYNC_AGGR_W-1:0], logic[FSYNC_LVL_W-1:0], logic[FSYNC_ID_W-1:0]) `FSYNC_TYPEDEF_ALL(hn_tile_fsync, logic[FSYNC_NBR_AGGR_W-1:0], logic[FSYNC_NBR_LVL_W-1:0], logic[FSYNC_NBR_ID_W-1:0]) @@ -680,10 +816,7 @@ package magia_tile_pkg; // Packed observation boundary required by hierarchical Verilation. typedef struct packed { logic [magia_pkg::ADDR_W-1:0] axi_aw_addr; - // axi_aw_id is driven from axi_xbar_mst_req_t.aw.id (magia_pkg's NoC AXI - // alias), whose ID width is magia_pkg::AXI_NOC_ID_W. This tile package's - // own AXI_ID_W (3 bits) sizes a *different* xbar (the tile-internal one - // with 5 slave ports) and must not be reused here. + // NoC AXI ID width: AXI_ID_W of this package sizes the tile-internal xbar, not this one logic [magia_pkg::AXI_NOC_ID_W-1:0] axi_aw_id; logic axi_aw_valid; logic [magia_pkg::DATA_W-1:0] axi_w_data; @@ -742,11 +875,14 @@ package magia_tile_pkg; `OBI_TYPEDEF_RSP_T(spatz_obi32_rsp_t, spatz_obi32_r_chan_t) + // Router reduction types for magia_tile, dropped by MAGIA_NO_NOC_TYPES +`ifndef MAGIA_NO_NOC_TYPES typedef logic [255:0] wide_data_t; `FLOO_RED_TYPEDEF_REQ_RSP_LINK(wide, wide_data_t, wide_req, wide_rsp) typedef logic [31:0] narrow_data_t; `FLOO_RED_TYPEDEF_REQ_RSP_LINK(narrow, narrow_data_t, narrow_req, narrow_rsp) +`endif diff --git a/hw/tile/obi_demux_addr.sv b/hw/tile/obi_demux_addr.sv index 259bb091..bb7dfcea 100644 --- a/hw/tile/obi_demux_addr.sv +++ b/hw/tile/obi_demux_addr.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -22,39 +22,34 @@ module obi_demux_addr #( parameter obi_pkg::obi_cfg_t SbrPortObiCfg = obi_pkg::ObiDefaultConfig, // The OBI configuration for the subordinate ports (input ports) parameter obi_pkg::obi_cfg_t MgrPortObiCfg = SbrPortObiCfg, // The OBI configuration for the manager ports (ouput ports) - - parameter type sbr_port_obi_req_t = logic, // The request struct for the subordinate ports (input ports) - parameter type sbr_port_obi_rsp_t = logic, // The response struct for the subordinate ports (input ports) - parameter type mgr_port_obi_req_t = sbr_port_obi_req_t, // The request struct for the manager ports (output ports) - parameter type mgr_port_obi_rsp_t = sbr_port_obi_rsp_t, // The response struct for the manager ports (output ports) - + parameter int unsigned NumMgrPorts = 32'd0, // The number of manager ports (output ports) parameter int unsigned NumMaxTrans = 32'd0, // The maximum number of outstanding transactions parameter int unsigned NumAddrRules = 32'd0, // The number of address rules - parameter type addr_map_rule_t = logic // The address map rule type + localparam int unsigned SelW = magia_tile_pkg::gen_idx_width(NumMgrPorts) // Selector width, 1 bit with a single port )( input logic clk_i, input logic rst_ni, - input sbr_port_obi_req_t sbr_ports_req_i, - output sbr_port_obi_rsp_t sbr_ports_rsp_o, + input magia_tile_pkg::core_obi_data_req_t sbr_ports_req_i, + output magia_tile_pkg::core_obi_data_rsp_t sbr_ports_rsp_o, - output mgr_port_obi_req_t[NumMgrPorts-1:0] mgr_ports_req_o, - input mgr_port_obi_rsp_t[NumMgrPorts-1:0] mgr_ports_rsp_i, + output magia_tile_pkg::core_obi_data_req_t[NumMgrPorts-1:0] mgr_ports_req_o, + input magia_tile_pkg::core_obi_data_rsp_t[NumMgrPorts-1:0] mgr_ports_rsp_i, - input addr_map_rule_t[NumAddrRules-1:0] addr_map_i, - input logic en_default_idx_i, - input logic[$clog2(NumMgrPorts)-1:0] default_idx_i + input magia_tile_pkg::obi_xbar_rule_t[NumAddrRules-1:0] addr_map_i, + input logic en_default_idx_i, + input logic[SelW-1:0] default_idx_i ); - logic[$clog2(NumMgrPorts)-1:0] sbr_port_select; + logic[SelW-1:0] sbr_port_select; addr_decode #( .NoIndices ( NumMgrPorts ), .NoRules ( NumAddrRules ), .addr_t ( logic[MgrPortObiCfg.AddrWidth-1:0] ), - .rule_t ( addr_map_rule_t ) + .rule_t ( magia_tile_pkg::obi_xbar_rule_t ) ) i_addr_decode ( .addr_i ( sbr_ports_req_i.a.addr ), .addr_map_i ( addr_map_i ), @@ -67,8 +62,8 @@ module obi_demux_addr #( obi_demux #( .ObiCfg ( SbrPortObiCfg ), - .obi_req_t ( sbr_port_obi_req_t ), - .obi_rsp_t ( sbr_port_obi_rsp_t ), + .obi_req_t ( magia_tile_pkg::core_obi_data_req_t ), + .obi_rsp_t ( magia_tile_pkg::core_obi_data_rsp_t ), .NumMgrPorts ( NumMgrPorts ), .NumMaxTrans ( NumMaxTrans ) ) i_demux ( diff --git a/hw/tile/obi_slave_ctrl_cluster.sv b/hw/tile/obi_slave_ctrl_cluster.sv index d5c929eb..58831e78 100644 --- a/hw/tile/obi_slave_ctrl_cluster.sv +++ b/hw/tile/obi_slave_ctrl_cluster.sv @@ -1,18 +1,18 @@ /* * Copyright (C) 2026 ETH Zurich, University of Bologna and Fondazione Chips-IT * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Solderpad Hardware License, Version 0.51 + * (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * SPDX-License-Identifier: Apache-2.0 + * SPDX-License-Identifier: SHL-0.51 * * Authors: Niccolò Giuliani, Fondazione Chips-IT */ @@ -21,7 +21,9 @@ module obi_slave_ctrl_cluster import magia_tile_pkg::*; #( - parameter logic [31:0] BaseAddr = 32'h00001700 // Base address for PULP cluster control registers + parameter magia_tile_pkg::magia_tile_cfg_t TileCfg = magia_tile_pkg::MagiaTileDefaultCfg, + parameter logic [31:0] BaseAddr = magia_tile_pkg::CLUSTER_CTRL_ADDR_START, // Base address for PULP cluster control registers + localparam int unsigned NumCores = TileCfg.Cluster.NumCores ) ( input logic clk_i, input logic rst_ni, @@ -31,15 +33,15 @@ module obi_slave_ctrl_cluster output core_obi_data_rsp_t obi_rsp_o, // Control outputs to PULP cluster cores - output logic [magia_tile_pkg::N_CLUSTER_CORES-1:0] clk_en_o, // broadcast (replicated) - output logic [31:0] boot_addr_o [magia_tile_pkg::N_CLUSTER_CORES-1:0], - output logic [magia_tile_pkg::N_CLUSTER_CORES-1:0] fetch_en_o, // broadcast (replicated) - output logic done_o, // DONE IRQ pulse when all selected cores complete - output logic [magia_tile_pkg::N_CLUSTER_CORES-1:0] start_irq_o // per-core 1-cycle dispatch IRQ pulse + output logic [NumCores-1:0] clk_en_o, // broadcast (replicated) + output logic [31:0] boot_addr_o [NumCores-1:0], + output logic [NumCores-1:0] fetch_en_o, // broadcast (replicated) + output logic done_o, // DONE IRQ pulse when all selected cores complete + output logic [NumCores-1:0] start_irq_o // per-core 1-cycle dispatch IRQ pulse ); //----------------------------------------------------------------------------- -// Register map (offsets from BaseAddr, instantiated by tile_csr at BaseAddr+0x40 = 0x1740) +// Register map (offsets from BaseAddr; instantiated inside gen_pulp_cluster at CLUSTER_CTRL_ADDR_START = 0x1740) // 0x00 CLK_EN : RW broadcast (1=enable all cores, 0=disable all) // writing CLK_EN also resets the READY counter // 0x04 BINARY : RW PULP binary entry point (boot address) @@ -51,7 +53,7 @@ module obi_slave_ctrl_cluster // 0x18 START : RW CV32 writes one-hot core_mask -> 1-cycle IRQ pulse // PULP cores write 0 to ACK (before task); // register clears when all NB_CORES_TO_WAIT ACKs received -// 0x1C READY : R reads as 1 once N_CLUSTER_CORES cores have written; +// 0x1C READY : R reads as 1 once NumCores cores have written; // W each PULP core writes 1 after boot (counter increment) //----------------------------------------------------------------------------- localparam logic [31:0] CLUSTER_CLK_EN = 32'h00; @@ -63,36 +65,39 @@ localparam logic [31:0] CLUSTER_DATA = 32'h14; localparam logic [31:0] CLUSTER_START = 32'h18; localparam logic [31:0] CLUSTER_READY = 32'h1C; +localparam int unsigned NumCoresW = magia_tile_pkg::gen_idx_width(NumCores); +localparam logic [NumCoresW:0] NumCoresCnt = (NumCoresW+1)'(NumCores); // NumCores at the counter width + // Address decode (offset from base) logic [31:0] addr_offset; logic addr_valid; assign addr_offset = obi_req_i.a.addr - BaseAddr; -assign addr_valid = (obi_req_i.a.addr >= BaseAddr) && +assign addr_valid = (obi_req_i.a.addr >= BaseAddr) & (obi_req_i.a.addr < (BaseAddr + 32)); // 8 registers * 4 bytes // Registers -logic clk_en_q, clk_en_d; -logic [31:0] entry_point_q, entry_point_d; -logic [magia_tile_pkg::N_BIT_CLUSTER_CORES:0] nb_cores_to_wait_q, nb_cores_to_wait_d; -logic done_q, done_d; -logic [31:0] taskbin_q, taskbin_d; -logic [31:0] data_q, data_d; -logic [magia_tile_pkg::N_CLUSTER_CORES-1:0] start_q, start_d; +logic clk_en_q, clk_en_d; +logic [31:0] entry_point_q, entry_point_d; +logic [NumCoresW:0] nb_cores_to_wait_q, nb_cores_to_wait_d; +logic done_q, done_d; +logic [31:0] taskbin_q, taskbin_d; +logic [31:0] data_q, data_d; +logic [NumCores-1:0] start_q, start_d; // Counters -logic [magia_tile_pkg::N_BIT_CLUSTER_CORES:0] nb_recv_done_reqs_q, nb_recv_done_reqs_d; -logic [magia_tile_pkg::N_BIT_CLUSTER_CORES:0] nb_recv_ack_reqs_q, nb_recv_ack_reqs_d; -logic [magia_tile_pkg::N_BIT_CLUSTER_CORES:0] nb_recv_ready_reqs_q, nb_recv_ready_reqs_d; +logic [NumCoresW:0] nb_recv_done_reqs_q, nb_recv_done_reqs_d; +logic [NumCoresW:0] nb_recv_ack_reqs_q, nb_recv_ack_reqs_d; +logic [NumCoresW:0] nb_recv_ready_reqs_q, nb_recv_ready_reqs_d; // One-cycle start IRQ pulse register -logic [magia_tile_pkg::N_CLUSTER_CORES-1:0] start_irq_q, start_irq_d; +logic [NumCores-1:0] start_irq_q, start_irq_d; // Response pipeline logic rvalid_q, rvalid_d; logic [31:0] rdata_q, rdata_d; -assign obi_rsp_o.gnt = obi_req_i.req && addr_valid; +assign obi_rsp_o.gnt = obi_req_i.req & addr_valid; assign obi_rsp_o.rvalid = rvalid_q; assign obi_rsp_o.r.rdata = rdata_q; assign obi_rsp_o.r.rid = '0; @@ -117,7 +122,7 @@ always_comb begin start_irq_d = '0; // default: no IRQ pulse this cycle if (obi_req_i.req && addr_valid && obi_req_i.a.we) begin - case (addr_offset) + unique case (addr_offset) CLUSTER_CLK_EN: begin // Broadcast: any non-zero enables all cores; 0 disables all. clk_en_d = |obi_req_i.a.wdata; @@ -128,7 +133,7 @@ always_comb begin entry_point_d = obi_req_i.a.wdata; end CLUSTER_NB_CORES_TO_WAIT: begin - nb_cores_to_wait_d = obi_req_i.a.wdata[magia_tile_pkg::N_BIT_CLUSTER_CORES:0]; + nb_cores_to_wait_d = obi_req_i.a.wdata[NumCoresW:0]; end CLUSTER_DONE: begin // Each PULP core writes 1 here on completion (write data ignored) @@ -143,10 +148,10 @@ always_comb begin CLUSTER_START: begin if (obi_req_i.a.wdata != 32'h0) begin // CV32 dispatch: latch core_mask, reset counters, fire 1-cycle IRQ pulses - start_d = obi_req_i.a.wdata[magia_tile_pkg::N_CLUSTER_CORES-1:0]; + start_d = obi_req_i.a.wdata[NumCores-1:0]; nb_recv_ack_reqs_d = '0; nb_recv_done_reqs_d = '0; - start_irq_d = obi_req_i.a.wdata[magia_tile_pkg::N_CLUSTER_CORES-1:0]; + start_irq_d = obi_req_i.a.wdata[NumCores-1:0]; end else begin // PULP core ACK (write 0): count; when all done, clear register nb_recv_ack_reqs_d = nb_recv_ack_reqs_q + 1; @@ -154,7 +159,7 @@ always_comb begin end CLUSTER_READY: begin // PULP core boot complete: count; saturate at N_CLUSTER_CORES - if (nb_recv_ready_reqs_q < magia_tile_pkg::N_CLUSTER_CORES) begin + if (nb_recv_ready_reqs_q < NumCoresCnt) begin nb_recv_ready_reqs_d = nb_recv_ready_reqs_q + 1; end end @@ -182,7 +187,7 @@ always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin clk_en_q <= 1'b0; entry_point_q <= 32'hCC000080; - nb_cores_to_wait_q <= magia_tile_pkg::N_CLUSTER_CORES; + nb_cores_to_wait_q <= NumCoresCnt; done_q <= 1'b0; taskbin_q <= 32'h0; data_q <= 32'h0; @@ -214,21 +219,21 @@ end // OBI read response logic (combinational) // ============================================ logic ready_reg_val; -assign ready_reg_val = (nb_recv_ready_reqs_q == magia_tile_pkg::N_CLUSTER_CORES); +assign ready_reg_val = (nb_recv_ready_reqs_q == NumCoresCnt); always_comb begin rdata_d = 32'h0; - rvalid_d = obi_req_i.req && addr_valid; + rvalid_d = obi_req_i.req & addr_valid; if (obi_req_i.req && addr_valid && !obi_req_i.a.we) begin - case (addr_offset) + unique case (addr_offset) CLUSTER_CLK_EN: rdata_d = {31'h0, clk_en_q}; CLUSTER_BINARY: rdata_d = entry_point_q; - CLUSTER_NB_CORES_TO_WAIT: rdata_d = {{(32-magia_tile_pkg::N_BIT_CLUSTER_CORES-1){1'b0}}, nb_cores_to_wait_q}; + CLUSTER_NB_CORES_TO_WAIT: rdata_d = {{(32-NumCoresW-1){1'b0}}, nb_cores_to_wait_q}; CLUSTER_DONE: rdata_d = {31'h0, done_q}; CLUSTER_TASKBIN: rdata_d = taskbin_q; CLUSTER_DATA: rdata_d = data_q; - CLUSTER_START: rdata_d = {{(32-magia_tile_pkg::N_CLUSTER_CORES){1'b0}}, start_q}; + CLUSTER_START: rdata_d = {{(32-NumCores){1'b0}}, start_q}; CLUSTER_READY: rdata_d = {31'h0, ready_reg_val}; default: rdata_d = 32'hDEADBEEF; endcase @@ -236,14 +241,14 @@ always_comb begin end // Outputs: broadcast clk_en and fetch_en to all cores (replicated bit) -assign clk_en_o = {magia_tile_pkg::N_CLUSTER_CORES{clk_en_q}}; -assign fetch_en_o = {magia_tile_pkg::N_CLUSTER_CORES{clk_en_q}}; +assign clk_en_o = {NumCores{clk_en_q}}; +assign fetch_en_o = {NumCores{clk_en_q}}; assign done_o = done_q; assign start_irq_o = start_irq_q; // All cores share the same boot address (PULP binary entry point) always_comb begin - for (int i = 0; i < magia_tile_pkg::N_CLUSTER_CORES; i++) begin + for (int i = 0; i < NumCores; i++) begin boot_addr_o[i] = entry_point_q; end end diff --git a/hw/tile/obi_slave_ctrl_coll.sv b/hw/tile/obi_slave_ctrl_coll.sv index 914012c2..fe863ae5 100644 --- a/hw/tile/obi_slave_ctrl_coll.sv +++ b/hw/tile/obi_slave_ctrl_coll.sv @@ -5,16 +5,16 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * SPDX-License-Identifier: SHL-0.51 * - * Authors: Carlotta Chiarini + * Authors: Carlotta Chiarini, Fondazione Chips-IT * based on obi_slave_ctrl_spatz by Luca Balboni * * OBI Slave Control Registers for the Collective Generator module @@ -24,7 +24,7 @@ module obi_slave_ctrl_coll import magia_tile_pkg::*; #( - parameter logic [31:0] BaseAddr = 32'h00001800 // Base address for control registers + parameter logic [31:0] BaseAddr = magia_tile_pkg::COLL_CTRL_ADDR_START // Base address for control registers ) ( input logic clk_i, input logic rst_ni, @@ -39,8 +39,8 @@ module obi_slave_ctrl_coll ); // Register offsets - localparam logic [3:0] COLLECTIVE_MASK_OFFSET = 4'h0; // +0x00 - localparam logic [3:0] COLLECTIVE_OP_OFFSET = 4'h4; // +0x04 + localparam logic [4:0] COLLECTIVE_MASK_OFFSET = 5'h00; // +0x00 + localparam logic [4:0] COLLECTIVE_OP_OFFSET = 5'h04; // +0x04 // Registers logic [31:0] collective_mask_q; @@ -57,11 +57,11 @@ module obi_slave_ctrl_coll assign addr_offset = obi_req_i.a.addr[4:0]; // Check if address is in valid range - assign addr_valid = (obi_req_i.a.addr >= BaseAddr) && + assign addr_valid = (obi_req_i.a.addr >= BaseAddr) & (obi_req_i.a.addr < (BaseAddr + 8)); // 2 registers * 4 bytes // Grant only if address is valid - assign obi_rsp_o.gnt = obi_req_i.req && addr_valid; + assign obi_rsp_o.gnt = obi_req_i.req & addr_valid; assign obi_rsp_o.r.err = 1'b0; // ============================================ @@ -77,9 +77,10 @@ module obi_slave_ctrl_coll // Update registers on write only if address is valid if (obi_req_i.req && obi_req_i.a.we && addr_valid) begin - case (addr_offset) + unique case (addr_offset) COLLECTIVE_MASK_OFFSET: collective_mask_d = obi_req_i.a.wdata; COLLECTIVE_OP_OFFSET: collective_op_d = obi_req_i.a.wdata[3:0]; + default: ; endcase end end @@ -102,10 +103,10 @@ module obi_slave_ctrl_coll // ============================================ always_comb begin rdata_d = 32'h0; - rvalid_d = obi_req_i.req && addr_valid; + rvalid_d = obi_req_i.req & addr_valid; if (obi_req_i.req && !obi_req_i.a.we && addr_valid) begin - case (addr_offset) + unique case (addr_offset) COLLECTIVE_MASK_OFFSET: rdata_d = collective_mask_q; COLLECTIVE_OP_OFFSET: rdata_d = {28'h0, collective_op_q}; default: rdata_d = 32'hDEADBEEF; diff --git a/hw/tile/obi_slave_ctrl_spatz.sv b/hw/tile/obi_slave_ctrl_spatz.sv index f75d8b2d..ffdfcfbb 100644 --- a/hw/tile/obi_slave_ctrl_spatz.sv +++ b/hw/tile/obi_slave_ctrl_spatz.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -23,7 +23,7 @@ module obi_slave_ctrl_spatz import magia_tile_pkg::*; #( - parameter logic [31:0] BaseAddr = 32'h00001700 // Base address for control registers + parameter logic [31:0] BaseAddr = magia_tile_pkg::SPATZ_CTRL_ADDR_START // Base address for control registers ) ( input logic clk_i, input logic rst_ni, @@ -39,10 +39,10 @@ module obi_slave_ctrl_spatz ); // Register offsets - localparam logic [3:0] CLK_EN_OFFSET = 4'h0; // +0x00 - localparam logic [3:0] READY_OFFSET = 4'h4; // +0x04 - localparam logic [3:0] START_OFFSET = 4'h8; // +0x08 - localparam logic [3:0] TASKBIN_OFFSET = 4'hC; // +0x0C + localparam logic [4:0] CLK_EN_OFFSET = 5'h00; // +0x00 + localparam logic [4:0] READY_OFFSET = 5'h04; // +0x04 + localparam logic [4:0] START_OFFSET = 5'h08; // +0x08 + localparam logic [4:0] TASKBIN_OFFSET = 5'h0C; // +0x0C localparam logic [4:0] DATA_OFFSET = 5'h10; // +0x10 localparam logic [4:0] RETURN_OFFSET = 5'h14; // +0x14 localparam logic [4:0] DONE_OFFSET = 5'h18; // +0x18 @@ -67,11 +67,11 @@ module obi_slave_ctrl_spatz assign addr_offset = obi_req_i.a.addr[4:0]; // Check if address is in valid range - assign addr_valid = (obi_req_i.a.addr >= BaseAddr) && + assign addr_valid = (obi_req_i.a.addr >= BaseAddr) & (obi_req_i.a.addr < (BaseAddr + 28)); // 7 registers * 4 bytes // Grant only if address is valid - assign obi_rsp_o.gnt = obi_req_i.req && addr_valid; + assign obi_rsp_o.gnt = obi_req_i.req & addr_valid; assign obi_rsp_o.r.err = 1'b0; // ============================================ @@ -97,7 +97,7 @@ module obi_slave_ctrl_spatz // Update registers on write only if address is valid if (obi_req_i.req && obi_req_i.a.we && addr_valid) begin - case (addr_offset) + unique case (addr_offset) CLK_EN_OFFSET: clk_en_d = obi_req_i.a.wdata[0]; READY_OFFSET: ready_d = obi_req_i.a.wdata[0]; // Spatz sets to 1 when ready for interrupts START_OFFSET: start_d = obi_req_i.a.wdata[0]; // CV32 sets to 1, Spatz clears to 0 @@ -105,6 +105,7 @@ module obi_slave_ctrl_spatz DATA_OFFSET: data_d = obi_req_i.a.wdata; // Preserved register RETURN_OFFSET: return_d = obi_req_i.a.wdata; // Preserved register DONE_OFFSET: done_d = obi_req_i.a.wdata[0]; // Spatz writes 1, creates pulse + default: ; endcase end end @@ -137,10 +138,10 @@ module obi_slave_ctrl_spatz // ============================================ always_comb begin rdata_d = 32'h0; - rvalid_d = obi_req_i.req && addr_valid; + rvalid_d = obi_req_i.req & addr_valid; if (obi_req_i.req && !obi_req_i.a.we && addr_valid) begin - case (addr_offset) + unique case (addr_offset) CLK_EN_OFFSET: rdata_d = {31'h0, clk_en_q}; READY_OFFSET: rdata_d = {31'h0, ready_q}; START_OFFSET: rdata_d = {31'h0, start_q}; diff --git a/hw/tile/obi_slave_fsync.sv b/hw/tile/obi_slave_fsync.sv index e1a0b9fc..6458a784 100644 --- a/hw/tile/obi_slave_fsync.sv +++ b/hw/tile/obi_slave_fsync.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -29,16 +29,14 @@ module obi_slave_fsync parameter int unsigned AGGR_W = magia_tile_pkg::FSYNC_AGGR_W, parameter int unsigned ID_W = magia_tile_pkg::FSYNC_ID_W, parameter int unsigned NBR_AGGR_W = magia_tile_pkg::FSYNC_NBR_AGGR_W, - parameter int unsigned NBR_ID_W = magia_tile_pkg::FSYNC_NBR_ID_W, - parameter type obi_req_t = magia_tile_pkg::core_obi_data_req_t, - parameter type obi_rsp_t = magia_tile_pkg::core_obi_data_rsp_t + parameter int unsigned NBR_ID_W = magia_tile_pkg::FSYNC_NBR_ID_W )( input logic clk_i, input logic rst_ni, input logic clear_i, - input obi_req_t obi_req_i, - output obi_rsp_t obi_rsp_o, + input core_obi_data_req_t obi_req_i, + output core_obi_data_rsp_t obi_rsp_o, fractal_sync_if.mst_port ht_fsync_if_o, fractal_sync_if.mst_port hn_fsync_if_o, @@ -60,7 +58,12 @@ module obi_slave_fsync logic done; logic addr_match; + core_obi_data_rsp_t obi_rsp_d; // Response computed in the address phase + logic rvalid_q; + core_obi_data_rsp_t obi_rsp_q; + logic[DATA_W-1:0] aggr_reg, id_reg, status_reg, control_reg; + logic[DATA_W-1:0] aggr_reg_d, id_reg_d; typedef enum logic[1:0] { IDLE, @@ -76,10 +79,10 @@ module obi_slave_fsync // BASE_ADDR + 0x04: ID_REG (write-only) // BASE_ADDR + 0x08: CONTROL_REG (write-only, writing triggers sync) // BASE_ADDR + 0x0C: STATUS_REG (read-only) - localparam logic [ADDR_W-1:0] AGGR_REG_OFFSET = 4'h0; - localparam logic [ADDR_W-1:0] ID_REG_OFFSET = 4'h4; - localparam logic [ADDR_W-1:0] CONTROL_REG_OFFSET = 4'h8; - localparam logic [ADDR_W-1:0] STATUS_REG_OFFSET = 4'hC; + localparam logic [ADDR_W-1:0] AGGR_REG_OFFSET = ADDR_W'('h0); + localparam logic [ADDR_W-1:0] ID_REG_OFFSET = ADDR_W'('h4); + localparam logic [ADDR_W-1:0] CONTROL_REG_OFFSET = ADDR_W'('h8); + localparam logic [ADDR_W-1:0] STATUS_REG_OFFSET = ADDR_W'('hC); /*******************************************************/ /** Internal Signal Definitions End **/ @@ -87,7 +90,7 @@ module obi_slave_fsync /** Hardwired Signals Beginning **/ /*******************************************************/ - assign addr_match = (obi_req_i.a.addr >= BASE_ADDR) && + assign addr_match = (obi_req_i.a.addr >= BASE_ADDR) & (obi_req_i.a.addr < BASE_ADDR + 32'h100); assign done_o = done; @@ -96,7 +99,7 @@ module obi_slave_fsync // Status register: bit 0 = done, bit 1 = error, bit 2 = busy // For polling: when busy=0, operation is complete - assign status_reg = {29'b0, (c_sync_state == SYNC || c_sync_state == WAIT), error_o, done}; + assign status_reg = {29'b0, (c_sync_state == SYNC | c_sync_state == WAIT), error_o, done}; /*******************************************************/ /** Hardwired Signals End **/ @@ -125,23 +128,22 @@ module obi_slave_fsync /*******************************************************/ always_comb begin: obi_interface - obi_rsp_o = '0; + obi_rsp_d = '0; sync_trigger = 1'b0; clk_reg_en = 1'b0; if (obi_req_i.req && addr_match) begin - obi_rsp_o.gnt = 1'b1; - obi_rsp_o.rvalid = 1'b1; + obi_rsp_d.gnt = 1'b1; clk_reg_en = 1'b1; // Enable clock for OBI register access // OBI protocol: assign response ID and optional fields - obi_rsp_o.r.rid = obi_req_i.a.aid; - obi_rsp_o.r.r_optional = '0; - obi_rsp_o.r.err = 1'b0; + obi_rsp_d.r.rid = obi_req_i.a.aid; + obi_rsp_d.r.r_optional = '0; + obi_rsp_d.r.err = 1'b0; if (obi_req_i.a.we) begin // Write operation - case (obi_req_i.a.addr - BASE_ADDR) + unique case (obi_req_i.a.addr - BASE_ADDR) CONTROL_REG_OFFSET: begin sync_trigger = 1'b1; // Writing to control register triggers sync end @@ -151,42 +153,72 @@ module obi_slave_fsync endcase end else begin // Read operation - case (obi_req_i.a.addr - BASE_ADDR) + unique case (obi_req_i.a.addr - BASE_ADDR) STATUS_REG_OFFSET: begin - obi_rsp_o.r.rdata = status_reg; + obi_rsp_d.r.rdata = status_reg; end default: begin - obi_rsp_o.r.rdata = 32'h0; // Return 0 for write-only registers + obi_rsp_d.r.rdata = 32'h0; // Return 0 for write-only registers end endcase end end end + always_ff @(posedge clk_i or negedge rst_ni) begin: obi_rvalid + if (!rst_ni) begin + rvalid_q <= 1'b0; + end else begin + rvalid_q <= obi_rsp_d.gnt; + end + end + + always_ff @(posedge clk_i or negedge rst_ni) begin: obi_response + if (!rst_ni) begin + obi_rsp_q <= '0; + end else if (obi_rsp_d.gnt) begin + obi_rsp_q <= obi_rsp_d; + end + end + + always_comb begin: obi_response_out + obi_rsp_o = obi_rsp_q; + obi_rsp_o.gnt = obi_rsp_d.gnt; + obi_rsp_o.rvalid = rvalid_q; + end + /*******************************************************/ /** OBI Interface Logic End **/ /*******************************************************/ /** Register Logic Beginning **/ /*******************************************************/ - always_ff @(posedge clk_reg_g, negedge rst_ni) begin: configuration_registers - if (~rst_ni) begin + always_comb begin: configuration_registers_next + aggr_reg_d = aggr_reg; + id_reg_d = id_reg; + if (clear_i) begin + aggr_reg_d = '0; + id_reg_d = '0; + end else if (obi_req_i.req & addr_match & obi_req_i.a.we) begin + unique case (obi_req_i.a.addr - BASE_ADDR) + AGGR_REG_OFFSET: begin + aggr_reg_d = obi_req_i.a.wdata; + end + ID_REG_OFFSET: begin + id_reg_d = obi_req_i.a.wdata; + end + default: ; + endcase + end + end + + always_ff @(posedge clk_reg_g or negedge rst_ni) begin: configuration_registers + if (!rst_ni) begin aggr_reg <= '0; id_reg <= '0; end else begin - if (clear_i) begin - aggr_reg <= '0; - id_reg <= '0; - end else if (obi_req_i.req && addr_match && obi_req_i.a.we) begin - case (obi_req_i.a.addr - BASE_ADDR) - AGGR_REG_OFFSET: begin - aggr_reg <= obi_req_i.a.wdata; - end - ID_REG_OFFSET: begin - id_reg <= obi_req_i.a.wdata; - end - endcase - end + aggr_reg <= aggr_reg_d; + id_reg <= id_reg_d; end end @@ -213,7 +245,7 @@ module obi_slave_fsync vn_fsync_if_o.aggr = '0; vn_fsync_if_o.id_req = '0; - case (c_sync_state) + unique case (c_sync_state) IDLE: begin if (sync_trigger) begin n_sync_state = SYNC; @@ -225,7 +257,7 @@ module obi_slave_fsync SYNC: begin n_sync_state = WAIT; if (aggr_reg != 1) begin // Tree (level > 1) request - case (id_reg[0]) + unique case (id_reg[0]) 1'b0: begin // Horizontal tree node request ht_fsync_if_o.sync = 1'b1; ht_fsync_if_o.aggr = aggr_reg[AGGR_W-1:0]; @@ -236,9 +268,10 @@ module obi_slave_fsync vt_fsync_if_o.aggr = aggr_reg[AGGR_W-1:0]; vt_fsync_if_o.id_req = id_reg[ID_W-1:0]; end + default: ; endcase end else begin // Neighbor (level = 1) request - case (id_reg[1:0]) + unique case (id_reg[1:0]) 2'b00: begin // Horizontal tree node request ht_fsync_if_o.sync = 1'b1; ht_fsync_if_o.aggr = aggr_reg[AGGR_W-1:0]; @@ -259,6 +292,7 @@ module obi_slave_fsync vn_fsync_if_o.aggr = aggr_reg[NBR_AGGR_W-1:0]; vn_fsync_if_o.id_req = id_reg[NBR_ID_W-1:0]; end + default: ; endcase end end @@ -275,14 +309,20 @@ module obi_slave_fsync n_sync_state = IDLE; done = 1'b1; end + + default: begin + n_sync_state = IDLE; + end endcase end - always_ff @(posedge clk_sync_g, negedge rst_ni) begin: sync_state - if (~rst_ni) c_sync_state <= IDLE; - else begin - if (clear_i) c_sync_state <= IDLE; - else c_sync_state <= n_sync_state; + always_ff @(posedge clk_sync_g or negedge rst_ni) begin: sync_state + if (!rst_ni) begin + c_sync_state <= IDLE; + end else if (clear_i) begin + c_sync_state <= IDLE; + end else begin + c_sync_state <= n_sync_state; end end diff --git a/hw/tile/spatz_bootrom.sv b/hw/tile/spatz_bootrom.sv index 4d6e7a18..6572b3d0 100644 --- a/hw/tile/spatz_bootrom.sv +++ b/hw/tile/spatz_bootrom.sv @@ -1,5 +1,5 @@ // Copyright (C) 2026 ETH Zurich, University of Bologna and Fondazione Chips-IT. -// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// Solderpad Hardware License, Version 0.51, see LICENSE.SHL for details. // SPDX-License-Identifier: SHL-0.51 // // Auto-generated bootrom for Spatz core complex @@ -35,5 +35,5 @@ module spatz_bootrom #( end // Return data based on registered address - assign rdata_o = (addr_q < RomSize) ? mem[addr_q] : '0; + assign rdata_o = (32'(addr_q) < RomSize) ? mem[addr_q] : '0; endmodule diff --git a/hw/tile/spatz_cc_wrapper.sv b/hw/tile/spatz_cc_wrapper.sv index 5d5306b9..dde7b215 100644 --- a/hw/tile/spatz_cc_wrapper.sv +++ b/hw/tile/spatz_cc_wrapper.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -29,6 +29,8 @@ module spatz_cc_wrapper import obi_pkg::*; import fpnew_pkg::*; #( + // Cacheable instruction regions + parameter snitch_pma_pkg::snitch_pma_t SnitchPMACfg = magia_tile_pkg::SPATZ_SNITCH_PMA_CFG, // Spatz Core Complex Parameters parameter int unsigned AddrWidth = magia_pkg::ADDR_W, parameter int unsigned DataWidth = magia_tile_pkg::SPATZ_TCDM_DATA_WIDTH, @@ -49,7 +51,9 @@ module spatz_cc_wrapper parameter logic [31:0] BootAddr = magia_tile_pkg::SPATZ_BOOT_ADDR, parameter fpnew_pkg::fpu_implementation_t FPUImplementation = magia_tile_pkg::SPATZ_FPUImplementation, - + parameter type hci_req_t = magia_tile_pkg::core_hci_data_req_t, + parameter type hci_rsp_t = magia_tile_pkg::core_hci_data_rsp_t, + // Derived parameters - calcolo dinamico basato su N_IPU e N_FPU configurabili localparam int unsigned NumSpatzFUs = (NumSpatzFPUs > NumSpatzIPUs) ? NumSpatzFPUs : NumSpatzIPUs, localparam int unsigned NumMemPortsPerSpatz = NumSpatzFUs, @@ -68,8 +72,8 @@ module spatz_cc_wrapper input snitch_pkg::interrupts_t irq_i, // HCI Master Interface(s) - Connect to MAGIA HCI Interconnect for L1 SPM access - output magia_tile_pkg::core_hci_data_req_t [HCIMasterPorts-1:0] hci_master_req_o, - input magia_tile_pkg::core_hci_data_rsp_t [HCIMasterPorts-1:0] hci_master_rsp_i, + output hci_req_t [HCIMasterPorts-1:0] hci_master_req_o, + input hci_rsp_t [HCIMasterPorts-1:0] hci_master_rsp_i, // OBI Master Interface - Single port for Snitch core output magia_tile_pkg::core_obi_data_req_t obi_master_req_o, @@ -168,161 +172,157 @@ module spatz_cc_wrapper hive_rsp_t hive_rsp; // Conditional signal declarations based on RVD parameter - generate - if (RVD) begin : gen_signals - // RVD=1: 64-bit signal types - magia_tile_pkg::spatz_reqrsp64_req_t data_req; - magia_tile_pkg::spatz_reqrsp64_rsp_t data_rsp; - magia_tile_pkg::spatz_tcdm64_req_t [TCDMPorts-1:0] tcdm_req; - magia_tile_pkg::spatz_tcdm64_rsp_t [TCDMPorts-1:0] tcdm_rsp; - end else begin : gen_signals - // RVD=0: 32-bit signal types - magia_tile_pkg::spatz_reqrsp_req_t data_req; - magia_tile_pkg::spatz_reqrsp_rsp_t data_rsp; - magia_tile_pkg::spatz_tcdm_req_t [TCDMPorts-1:0] tcdm_req; - magia_tile_pkg::spatz_tcdm_rsp_t [TCDMPorts-1:0] tcdm_rsp; - end - endgenerate + if (RVD) begin : gen_signals + // RVD=1: 64-bit signal types + magia_tile_pkg::spatz_reqrsp64_req_t data_req; + magia_tile_pkg::spatz_reqrsp64_rsp_t data_rsp; + magia_tile_pkg::spatz_tcdm64_req_t [TCDMPorts-1:0] tcdm_req; + magia_tile_pkg::spatz_tcdm64_rsp_t [TCDMPorts-1:0] tcdm_rsp; + end else begin : gen_signals + // RVD=0: 32-bit signal types + magia_tile_pkg::spatz_reqrsp_req_t data_req; + magia_tile_pkg::spatz_reqrsp_rsp_t data_rsp; + magia_tile_pkg::spatz_tcdm_req_t [TCDMPorts-1:0] tcdm_req; + magia_tile_pkg::spatz_tcdm_rsp_t [TCDMPorts-1:0] tcdm_rsp; + end /*******************************************************************/ /* Spatz Core Complex Instance */ /*******************************************************************/ - generate - if (RVD) begin : gen_spatz_cc_rvd - // RVD=1: 64-bit configuration - spatz_cc #( - .AddrWidth ( AddrWidth ), - .DataWidth ( DataWidth ), // 64-bit - .TCDMAddrWidth ( TCDMAddrWidth ), - .dreq_t ( magia_tile_pkg::spatz_reqrsp64_req_t ), - .drsp_t ( magia_tile_pkg::spatz_reqrsp64_rsp_t ), - .tcdm_req_t ( magia_tile_pkg::spatz_tcdm64_req_t ), - .tcdm_req_chan_t ( magia_tile_pkg::spatz_tcdm64_payload_t ), - .tcdm_rsp_t ( magia_tile_pkg::spatz_tcdm64_rsp_t ), - .tcdm_rsp_chan_t ( magia_tile_pkg::spatz_tcdm64_rsp_chan_t ), - .axi_req_t ( magia_tile_pkg::idma_axi_req_t ), - .axi_ar_chan_t ( magia_tile_pkg::idma_axi_ar_chan_t ), - .axi_aw_chan_t ( magia_tile_pkg::idma_axi_aw_chan_t ), - .axi_rsp_t ( magia_tile_pkg::idma_axi_rsp_t ), - .hive_req_t ( hive_req_t ), - .hive_rsp_t ( hive_rsp_t ), - .acc_issue_req_t ( acc_issue_req_t ), - .acc_issue_rsp_t ( acc_issue_rsp_t ), - .acc_rsp_t ( acc_rsp_t ), - .dma_events_t ( dma_events_t ), - .dma_perf_t ( logic ), - .SnitchPMACfg ( magia_tile_pkg::SPATZ_SNITCH_PMA_CFG ), - .FPUImplementation ( FPUImplementation ), - .BootAddr ( BootAddr ), - .RVE ( 1'b0 ), - .RVF ( RVF ), - .RVD ( 1'b1 ), - .XDivSqrt ( XDivSqrt ), - .XF8 ( 1'b1 ), - .XF16 ( 1'b1 ), - .XF16ALT ( 1'b1 ), - .XF8ALT ( 1'b1 ), - .Xdma ( Xdma ), - .NumIntOutstandingLoads ( NumIntOutstandingLoads ), - .NumIntOutstandingMem ( NumIntOutstandingMem ), - .NumSpatzOutstandingLoads ( NumSpatzOutstandingLoads ), - .RVV ( RVV ), - .NumSpatzFPUs ( NumSpatzFPUs ), - .NumSpatzIPUs ( NumSpatzIPUs ), - .IsoCrossing ( 1'b0 ), - .RegisterOffloadRsp ( RegisterOffloadRsp ), - .RegisterCoreReq ( RegisterCoreReq ), - .RegisterCoreRsp ( RegisterCoreRsp ) - ) i_spatz_cc ( - .clk_i ( clk_i ), - .clk_d2_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( test_mode_i ), - .hart_id_i ( hart_id_i ), - .irq_i ( irq_i ), - .tcdm_addr_base_i ( tcdm_addr_base_i ), - .hive_req_o ( hive_req ), - .hive_rsp_i ( hive_rsp ), - .data_req_o ( gen_signals.data_req ), - .data_rsp_i ( gen_signals.data_rsp ), - .tcdm_req_o ( gen_signals.tcdm_req ), - .tcdm_rsp_i ( gen_signals.tcdm_rsp ), - .axi_dma_req_o ( /* DMA disabled */ ), - .axi_dma_res_i ( '0 ), - .axi_dma_busy_o ( /* DMA disabled */ ), - .axi_dma_perf_o ( /* DMA disabled */ ), - .axi_dma_events_o ( /* DMA disabled */ ), - .core_events_o ( core_events_o ) - ); - end else begin : gen_spatz_cc_no_rvd - // RVD=0: 32-bit configuration - spatz_cc #( - .AddrWidth ( AddrWidth ), - .DataWidth ( DataWidth ), // 32-bit - .TCDMAddrWidth ( TCDMAddrWidth ), - .dreq_t ( magia_tile_pkg::spatz_reqrsp_req_t ), - .drsp_t ( magia_tile_pkg::spatz_reqrsp_rsp_t ), - .tcdm_req_t ( magia_tile_pkg::spatz_tcdm_req_t ), - .tcdm_req_chan_t ( magia_tile_pkg::spatz_tcdm_req_chan_t ), - .tcdm_rsp_t ( magia_tile_pkg::spatz_tcdm_rsp_t ), - .tcdm_rsp_chan_t ( magia_tile_pkg::spatz_tcdm_rsp_chan_t ), - .axi_req_t ( magia_tile_pkg::idma_axi_req_t ), - .axi_ar_chan_t ( magia_tile_pkg::idma_axi_ar_chan_t ), - .axi_aw_chan_t ( magia_tile_pkg::idma_axi_aw_chan_t ), - .axi_rsp_t ( magia_tile_pkg::idma_axi_rsp_t ), - .hive_req_t ( hive_req_t ), - .hive_rsp_t ( hive_rsp_t ), - .acc_issue_req_t ( acc_issue_req_t ), - .acc_issue_rsp_t ( acc_issue_rsp_t ), - .acc_rsp_t ( acc_rsp_t ), - .dma_events_t ( dma_events_t ), - .dma_perf_t ( logic ), - .SnitchPMACfg ( magia_tile_pkg::SPATZ_SNITCH_PMA_CFG ), - .FPUImplementation ( FPUImplementation ), - .BootAddr ( BootAddr ), - .RVE ( 1'b0 ), - .RVF ( RVF ), - .RVD ( 1'b0 ), - .XDivSqrt ( XDivSqrt ), - .XF8 ( 1'b1 ), - .XF16 ( 1'b1 ), - .XF16ALT ( 1'b1 ), - .XF8ALT ( 1'b1 ), - .Xdma ( Xdma ), - .NumIntOutstandingLoads ( NumIntOutstandingLoads ), - .NumIntOutstandingMem ( NumIntOutstandingMem ), - .NumSpatzOutstandingLoads ( NumSpatzOutstandingLoads ), - .RVV ( RVV ), - .NumSpatzFPUs ( NumSpatzFPUs ), - .NumSpatzIPUs ( NumSpatzIPUs ), - .IsoCrossing ( 1'b0 ), - .RegisterOffloadRsp ( RegisterOffloadRsp ), - .RegisterCoreReq ( RegisterCoreReq ), - .RegisterCoreRsp ( RegisterCoreRsp ) - ) i_spatz_cc ( - .clk_i ( clk_i ), - .clk_d2_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( test_mode_i ), - .hart_id_i ( hart_id_i ), - .irq_i ( irq_i ), - .tcdm_addr_base_i ( tcdm_addr_base_i ), - .hive_req_o ( hive_req ), - .hive_rsp_i ( hive_rsp ), - .data_req_o ( gen_signals.data_req ), - .data_rsp_i ( gen_signals.data_rsp ), - .tcdm_req_o ( gen_signals.tcdm_req ), - .tcdm_rsp_i ( gen_signals.tcdm_rsp ), - .axi_dma_req_o ( /* DMA disabled */ ), - .axi_dma_res_i ( '0 ), - .axi_dma_busy_o ( /* DMA disabled */ ), - .axi_dma_perf_o ( /* DMA disabled */ ), - .axi_dma_events_o ( /* DMA disabled */ ), - .core_events_o ( core_events_o ) - ); - end - endgenerate + if (RVD) begin : gen_spatz_cc_rvd + // RVD=1: 64-bit configuration + spatz_cc #( + .AddrWidth ( AddrWidth ), + .DataWidth ( DataWidth ), // 64-bit + .TCDMAddrWidth ( TCDMAddrWidth ), + .dreq_t ( magia_tile_pkg::spatz_reqrsp64_req_t ), + .drsp_t ( magia_tile_pkg::spatz_reqrsp64_rsp_t ), + .tcdm_req_t ( magia_tile_pkg::spatz_tcdm64_req_t ), + .tcdm_req_chan_t ( magia_tile_pkg::spatz_tcdm64_payload_t ), + .tcdm_rsp_t ( magia_tile_pkg::spatz_tcdm64_rsp_t ), + .tcdm_rsp_chan_t ( magia_tile_pkg::spatz_tcdm64_rsp_chan_t ), + .axi_req_t ( magia_tile_pkg::idma_axi_req_t ), + .axi_ar_chan_t ( magia_tile_pkg::idma_axi_ar_chan_t ), + .axi_aw_chan_t ( magia_tile_pkg::idma_axi_aw_chan_t ), + .axi_rsp_t ( magia_tile_pkg::idma_axi_rsp_t ), + .hive_req_t ( hive_req_t ), + .hive_rsp_t ( hive_rsp_t ), + .acc_issue_req_t ( acc_issue_req_t ), + .acc_issue_rsp_t ( acc_issue_rsp_t ), + .acc_rsp_t ( acc_rsp_t ), + .dma_events_t ( dma_events_t ), + .dma_perf_t ( logic ), + .SnitchPMACfg ( SnitchPMACfg ), + .FPUImplementation ( FPUImplementation ), + .BootAddr ( BootAddr ), + .RVE ( 1'b0 ), + .RVF ( RVF ), + .RVD ( 1'b1 ), + .XDivSqrt ( XDivSqrt ), + .XF8 ( 1'b1 ), + .XF16 ( 1'b1 ), + .XF16ALT ( 1'b1 ), + .XF8ALT ( 1'b1 ), + .Xdma ( Xdma ), + .NumIntOutstandingLoads ( NumIntOutstandingLoads ), + .NumIntOutstandingMem ( NumIntOutstandingMem ), + .NumSpatzOutstandingLoads ( NumSpatzOutstandingLoads ), + .RVV ( RVV ), + .NumSpatzFPUs ( NumSpatzFPUs ), + .NumSpatzIPUs ( NumSpatzIPUs ), + .IsoCrossing ( 1'b0 ), + .RegisterOffloadRsp ( RegisterOffloadRsp ), + .RegisterCoreReq ( RegisterCoreReq ), + .RegisterCoreRsp ( RegisterCoreRsp ) + ) i_spatz_cc ( + .clk_i ( clk_i ), + .clk_d2_i ( clk_i ), + .rst_ni ( rst_ni ), + .testmode_i ( test_mode_i ), + .hart_id_i ( hart_id_i ), + .irq_i ( irq_i ), + .tcdm_addr_base_i ( tcdm_addr_base_i ), + .hive_req_o ( hive_req ), + .hive_rsp_i ( hive_rsp ), + .data_req_o ( gen_signals.data_req ), + .data_rsp_i ( gen_signals.data_rsp ), + .tcdm_req_o ( gen_signals.tcdm_req ), + .tcdm_rsp_i ( gen_signals.tcdm_rsp ), + .axi_dma_req_o ( /* DMA disabled */ ), + .axi_dma_res_i ( '0 ), + .axi_dma_busy_o ( /* DMA disabled */ ), + .axi_dma_perf_o ( /* DMA disabled */ ), + .axi_dma_events_o ( /* DMA disabled */ ), + .core_events_o ( core_events_o ) + ); + end else begin : gen_spatz_cc_no_rvd + // RVD=0: 32-bit configuration + spatz_cc #( + .AddrWidth ( AddrWidth ), + .DataWidth ( DataWidth ), // 32-bit + .TCDMAddrWidth ( TCDMAddrWidth ), + .dreq_t ( magia_tile_pkg::spatz_reqrsp_req_t ), + .drsp_t ( magia_tile_pkg::spatz_reqrsp_rsp_t ), + .tcdm_req_t ( magia_tile_pkg::spatz_tcdm_req_t ), + .tcdm_req_chan_t ( magia_tile_pkg::spatz_tcdm_req_chan_t ), + .tcdm_rsp_t ( magia_tile_pkg::spatz_tcdm_rsp_t ), + .tcdm_rsp_chan_t ( magia_tile_pkg::spatz_tcdm_rsp_chan_t ), + .axi_req_t ( magia_tile_pkg::idma_axi_req_t ), + .axi_ar_chan_t ( magia_tile_pkg::idma_axi_ar_chan_t ), + .axi_aw_chan_t ( magia_tile_pkg::idma_axi_aw_chan_t ), + .axi_rsp_t ( magia_tile_pkg::idma_axi_rsp_t ), + .hive_req_t ( hive_req_t ), + .hive_rsp_t ( hive_rsp_t ), + .acc_issue_req_t ( acc_issue_req_t ), + .acc_issue_rsp_t ( acc_issue_rsp_t ), + .acc_rsp_t ( acc_rsp_t ), + .dma_events_t ( dma_events_t ), + .dma_perf_t ( logic ), + .SnitchPMACfg ( SnitchPMACfg ), + .FPUImplementation ( FPUImplementation ), + .BootAddr ( BootAddr ), + .RVE ( 1'b0 ), + .RVF ( RVF ), + .RVD ( 1'b0 ), + .XDivSqrt ( XDivSqrt ), + .XF8 ( 1'b1 ), + .XF16 ( 1'b1 ), + .XF16ALT ( 1'b1 ), + .XF8ALT ( 1'b1 ), + .Xdma ( Xdma ), + .NumIntOutstandingLoads ( NumIntOutstandingLoads ), + .NumIntOutstandingMem ( NumIntOutstandingMem ), + .NumSpatzOutstandingLoads ( NumSpatzOutstandingLoads ), + .RVV ( RVV ), + .NumSpatzFPUs ( NumSpatzFPUs ), + .NumSpatzIPUs ( NumSpatzIPUs ), + .IsoCrossing ( 1'b0 ), + .RegisterOffloadRsp ( RegisterOffloadRsp ), + .RegisterCoreReq ( RegisterCoreReq ), + .RegisterCoreRsp ( RegisterCoreRsp ) + ) i_spatz_cc ( + .clk_i ( clk_i ), + .clk_d2_i ( clk_i ), + .rst_ni ( rst_ni ), + .testmode_i ( test_mode_i ), + .hart_id_i ( hart_id_i ), + .irq_i ( irq_i ), + .tcdm_addr_base_i ( tcdm_addr_base_i ), + .hive_req_o ( hive_req ), + .hive_rsp_i ( hive_rsp ), + .data_req_o ( gen_signals.data_req ), + .data_rsp_i ( gen_signals.data_rsp ), + .tcdm_req_o ( gen_signals.tcdm_req ), + .tcdm_rsp_i ( gen_signals.tcdm_rsp ), + .axi_dma_req_o ( /* DMA disabled */ ), + .axi_dma_res_i ( '0 ), + .axi_dma_busy_o ( /* DMA disabled */ ), + .axi_dma_perf_o ( /* DMA disabled */ ), + .axi_dma_events_o ( /* DMA disabled */ ), + .core_events_o ( core_events_o ) + ); + end /*******************************************************************/ /* Instruction Cache Interface (Hive) Connection */ @@ -347,143 +347,123 @@ module spatz_cc_wrapper /* Protocol Conversion: reqrsp (Snitch) → OBI32 */ /*******************************************************************/ - generate - if (RVD) begin : gen_reqrsp64_to_obi32 - // RVD=1: Snitch data port 64-bit reqrsp → 32-bit OBI (for L2/peripherals) - reqrsp64_to_obi32 #( - .ObiCfg ( magia_tile_pkg::obi_amo_cfg ), - .reqrsp_req_t ( magia_tile_pkg::spatz_reqrsp64_req_t ), - .reqrsp_rsp_t ( magia_tile_pkg::spatz_reqrsp64_rsp_t ), - .obi_req_t ( magia_tile_pkg::core_obi_data_req_t ), - .obi_rsp_t ( magia_tile_pkg::core_obi_data_rsp_t ) - ) i_snitch_reqrsp_to_obi32 ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .reqrsp_req_i ( gen_signals.data_req ), - .reqrsp_rsp_o ( gen_signals.data_rsp ), - .obi_req_o ( obi_master_req_o ), - .obi_rsp_i ( obi_master_rsp_i ) - ); - end else begin : gen_reqrsp32_to_obi32 - // RVD=0: Snitch data port 32-bit reqrsp → 32-bit OBI (for L2/peripherals) - reqrsp2obi #( - .ObiCfg ( magia_tile_pkg::obi_amo_cfg ), - .reqrsp_req_t ( magia_tile_pkg::spatz_reqrsp_req_t ), - .reqrsp_rsp_t ( magia_tile_pkg::spatz_reqrsp_rsp_t ), - .obi_req_t ( magia_tile_pkg::core_obi_data_req_t ), - .obi_rsp_t ( magia_tile_pkg::core_obi_data_rsp_t ) - ) i_snitch_reqrsp_to_obi32 ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .reqrsp_req_i ( gen_signals.data_req ), - .reqrsp_rsp_o ( gen_signals.data_rsp ), - .obi_req_o ( obi_master_req_o ), - .obi_rsp_i ( obi_master_rsp_i ) - ); - end - endgenerate + if (RVD) begin : gen_reqrsp64_to_obi32 + // RVD=1: Snitch data port 64-bit reqrsp → 32-bit OBI (for L2/peripherals) + reqrsp64_to_obi32 #( + .reqrsp_req_t ( magia_tile_pkg::spatz_reqrsp64_req_t ), + .reqrsp_rsp_t ( magia_tile_pkg::spatz_reqrsp64_rsp_t ), + .ObiCfg ( magia_tile_pkg::obi_amo_cfg ) + ) i_snitch_reqrsp_to_obi32 ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .reqrsp_req_i ( gen_signals.data_req ), + .reqrsp_rsp_o ( gen_signals.data_rsp ), + .obi_req_o ( obi_master_req_o ), + .obi_rsp_i ( obi_master_rsp_i ) + ); + end else begin : gen_reqrsp32_to_obi32 + // RVD=0: Snitch data port 32-bit reqrsp → 32-bit OBI (for L2/peripherals) + reqrsp2obi #( + .ObiCfg ( magia_tile_pkg::obi_amo_cfg ) + ) i_snitch_reqrsp_to_obi32 ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .reqrsp_req_i ( gen_signals.data_req ), + .reqrsp_rsp_o ( gen_signals.data_rsp ), + .obi_req_o ( obi_master_req_o ), + .obi_rsp_i ( obi_master_rsp_i ) + ); + end /*******************************************************************/ /* Protocol Conversion: TCDM (Spatz) → HCI32 */ /*******************************************************************/ - generate - if (RVD) begin : gen_tcdm64_to_hci - // RVD=1: Each 64-bit TCDM port splits into 2×32-bit HCI ports - - // Ports 0-3: Spatz vector memory ports (64-bit TCDM → 2×32-bit HCI) - for (genvar i = 0; i < NumMemPortsPerSpatz; i++) begin : gen_tcdm64_to_dual_hci32_spatz - tcdm64_to_dual_hci32 #( - .tcdm64_req_t ( magia_tile_pkg::spatz_tcdm64_req_t ), - .tcdm64_rsp_t ( magia_tile_pkg::spatz_tcdm64_rsp_t ), - .tcdm32_req_t ( magia_tile_pkg::spatz_tcdm32_req_t ), - .tcdm32_rsp_t ( magia_tile_pkg::spatz_tcdm32_rsp_t ), - .hci_req_t ( magia_tile_pkg::core_hci_data_req_t ), - .hci_rsp_t ( magia_tile_pkg::core_hci_data_rsp_t ) - ) i_tcdm64_to_dual_hci32_spatz ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .tcdm_req_i ( gen_signals.tcdm_req[i] ), - .tcdm_rsp_o ( gen_signals.tcdm_rsp[i] ), - .hci_req_lo_o ( hci_master_req_o[i*2] ), - .hci_rsp_lo_i ( hci_master_rsp_i[i*2] ), - .hci_req_hi_o ( hci_master_req_o[i*2+1] ), - .hci_rsp_hi_i ( hci_master_rsp_i[i*2+1] ) - ); - end - - // Port 4: Snitch RV64 TCDM (with AMO) → Dual HCI32 (ports 8-9) - tcdm64_to_dual_hci32_atomic #( - .tcdm64_req_t ( magia_tile_pkg::spatz_tcdm64_req_t ), - .tcdm64_rsp_t ( magia_tile_pkg::spatz_tcdm64_rsp_t ), - .tcdm32_req_t ( magia_tile_pkg::spatz_tcdm32_req_t ), - .tcdm32_rsp_t ( magia_tile_pkg::spatz_tcdm32_rsp_t ), - .obi32_req_t ( magia_tile_pkg::spatz_obi32_req_t ), - .obi32_rsp_t ( magia_tile_pkg::spatz_obi32_rsp_t ), - .obi32_a_chan_t ( magia_tile_pkg::spatz_obi32_a_chan_t ), - .obi32_r_chan_t ( magia_tile_pkg::spatz_obi32_r_chan_t ), - .hci_req_t ( magia_tile_pkg::core_hci_data_req_t ), - .hci_rsp_t ( magia_tile_pkg::core_hci_data_rsp_t ), - .obi32_a_optional_t ( magia_tile_pkg::spatz_obi32_a_optional_t ), - .obi32_r_optional_t ( magia_tile_pkg::spatz_obi32_r_optional_t ), - .SbrPortObiCfg ( magia_tile_pkg::obi_amo_cfg ), - .MgrPortObiCfg ( magia_tile_pkg::obi_no_amo_cfg ), - .BypassCut ( 1'b0 ) - ) i_tcdm64_to_dual_hci32_atomic_snitch ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .tcdm_req_i ( gen_signals.tcdm_req[NumMemPortsPerSpatz] ), - .tcdm_rsp_o ( gen_signals.tcdm_rsp[NumMemPortsPerSpatz] ), - .hci_req_lo_o ( hci_master_req_o[NumMemPortsPerSpatz*2] ), - .hci_rsp_lo_i ( hci_master_rsp_i[NumMemPortsPerSpatz*2] ), - .hci_req_hi_o ( hci_master_req_o[NumMemPortsPerSpatz*2+1] ), - .hci_rsp_hi_i ( hci_master_rsp_i[NumMemPortsPerSpatz*2+1] ) + if (RVD) begin : gen_tcdm64_to_hci + // RVD=1: Each 64-bit TCDM port splits into 2×32-bit HCI ports + + // Ports 0-3: Spatz vector memory ports (64-bit TCDM → 2×32-bit HCI) + for (genvar i = 0; i < NumMemPortsPerSpatz; i++) begin : gen_tcdm64_to_dual_hci32_spatz + tcdm64_to_dual_hci32 #( + .tcdm64_req_t ( magia_tile_pkg::spatz_tcdm64_req_t ), + .tcdm64_rsp_t ( magia_tile_pkg::spatz_tcdm64_rsp_t ), + .hci_req_t ( hci_req_t ), + .hci_rsp_t ( hci_rsp_t ) + ) i_tcdm64_to_dual_hci32_spatz ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .tcdm_req_i ( gen_signals.tcdm_req[i] ), + .tcdm_rsp_o ( gen_signals.tcdm_rsp[i] ), + .hci_req_lo_o ( hci_master_req_o[i*2] ), + .hci_rsp_lo_i ( hci_master_rsp_i[i*2] ), + .hci_req_hi_o ( hci_master_req_o[i*2+1] ), + .hci_rsp_hi_i ( hci_master_rsp_i[i*2+1] ) ); - - end else begin : gen_tcdm32_to_hci - // RVD=0: Each 32-bit TCDM port maps directly to 1×32-bit HCI port - - // Ports 0-3: Spatz vector memory ports (32-bit TCDM → 32-bit HCI) - for (genvar i = 0; i < NumMemPortsPerSpatz; i++) begin : gen_tcdm32_to_hci32_spatz - tcdm2hci #( - .tcdm_req_t ( magia_tile_pkg::spatz_tcdm_req_t ), - .tcdm_rsp_t ( magia_tile_pkg::spatz_tcdm_rsp_t ), - .hci_req_t ( magia_tile_pkg::core_hci_data_req_t ), - .hci_rsp_t ( magia_tile_pkg::core_hci_data_rsp_t ) - ) i_tcdm32_to_hci32_spatz ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .tcdm_req_i ( gen_signals.tcdm_req[i] ), - .tcdm_rsp_o ( gen_signals.tcdm_rsp[i] ), - .hci_req_o ( hci_master_req_o[i] ), - .hci_rsp_i ( hci_master_rsp_i[i] ) - ); - end - - // Port 4: Snitch RV32 TCDM (with AMO) → HCI32 - tcdm2hci_atomic #( - .tcdm_req_t ( magia_tile_pkg::spatz_tcdm_req_t ), - .tcdm_rsp_t ( magia_tile_pkg::spatz_tcdm_rsp_t ), - .obi_req_t ( magia_tile_pkg::core_obi_data_req_t ), - .obi_rsp_t ( magia_tile_pkg::core_obi_data_rsp_t ), - .obi_a_chan_t ( magia_tile_pkg::core_data_obi_a_chan_t ), - .obi_r_chan_t ( magia_tile_pkg::core_data_obi_r_chan_t ), - .hci_req_t ( magia_tile_pkg::core_hci_data_req_t ), - .hci_rsp_t ( magia_tile_pkg::core_hci_data_rsp_t ), - .obi_a_optional_t ( magia_tile_pkg::core_data_obi_a_optional_t ), - .obi_r_optional_t ( magia_tile_pkg::core_data_obi_r_optional_t ), - .SbrPortObiCfg ( magia_tile_pkg::obi_amo_cfg ), - .MgrPortObiCfg ( magia_tile_pkg::obi_no_amo_cfg ), - .BypassCut ( 1'b0 ) - ) i_tcdm32_to_hci32_atomic_snitch ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .tcdm_req_i ( gen_signals.tcdm_req[NumMemPortsPerSpatz] ), - .tcdm_rsp_o ( gen_signals.tcdm_rsp[NumMemPortsPerSpatz] ), - .hci_req_o ( hci_master_req_o[NumMemPortsPerSpatz] ), - .hci_rsp_i ( hci_master_rsp_i[NumMemPortsPerSpatz] ) + end + + // Port 4: Snitch RV64 TCDM (with AMO) → Dual HCI32 (ports 8-9) + tcdm64_to_dual_hci32_atomic #( + .tcdm64_req_t ( magia_tile_pkg::spatz_tcdm64_req_t ), + .tcdm64_rsp_t ( magia_tile_pkg::spatz_tcdm64_rsp_t ), + .hci_req_t ( hci_req_t ), + .hci_rsp_t ( hci_rsp_t ), + .SbrPortObiCfg ( magia_tile_pkg::obi_amo_cfg ), + .MgrPortObiCfg ( magia_tile_pkg::obi_no_amo_cfg ), + .BypassCut ( 1'b0 ) + ) i_tcdm64_to_dual_hci32_atomic_snitch ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .tcdm_req_i ( gen_signals.tcdm_req[NumMemPortsPerSpatz] ), + .tcdm_rsp_o ( gen_signals.tcdm_rsp[NumMemPortsPerSpatz] ), + .hci_req_lo_o ( hci_master_req_o[NumMemPortsPerSpatz*2] ), + .hci_rsp_lo_i ( hci_master_rsp_i[NumMemPortsPerSpatz*2] ), + .hci_req_hi_o ( hci_master_req_o[NumMemPortsPerSpatz*2+1] ), + .hci_rsp_hi_i ( hci_master_rsp_i[NumMemPortsPerSpatz*2+1] ) + ); + + end else begin : gen_tcdm32_to_hci + // RVD=0: Each 32-bit TCDM port maps directly to 1×32-bit HCI port + + // Ports 0-3: Spatz vector memory ports (32-bit TCDM → 32-bit HCI) + for (genvar i = 0; i < NumMemPortsPerSpatz; i++) begin : gen_tcdm32_to_hci32_spatz + tcdm2hci #( + .tcdm_req_t ( magia_tile_pkg::spatz_tcdm_req_t ), + .tcdm_rsp_t ( magia_tile_pkg::spatz_tcdm_rsp_t ), + .hci_req_t ( hci_req_t ), + .hci_rsp_t ( hci_rsp_t ) + ) i_tcdm32_to_hci32_spatz ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .tcdm_req_i ( gen_signals.tcdm_req[i] ), + .tcdm_rsp_o ( gen_signals.tcdm_rsp[i] ), + .hci_req_o ( hci_master_req_o[i] ), + .hci_rsp_i ( hci_master_rsp_i[i] ) ); end - endgenerate + + // Port 4: Snitch RV32 TCDM (with AMO) → HCI32 + tcdm2hci_atomic #( + .tcdm_req_t ( magia_tile_pkg::spatz_tcdm_req_t ), + .tcdm_rsp_t ( magia_tile_pkg::spatz_tcdm_rsp_t ), + .obi_req_t ( magia_tile_pkg::core_obi_data_req_t ), + .obi_rsp_t ( magia_tile_pkg::core_obi_data_rsp_t ), + .obi_a_chan_t ( magia_tile_pkg::core_data_obi_a_chan_t ), + .obi_r_chan_t ( magia_tile_pkg::core_data_obi_r_chan_t ), + .hci_req_t ( hci_req_t ), + .hci_rsp_t ( hci_rsp_t ), + .obi_a_optional_t ( magia_tile_pkg::core_data_obi_a_optional_t ), + .obi_r_optional_t ( magia_tile_pkg::core_data_obi_r_optional_t ), + .SbrPortObiCfg ( magia_tile_pkg::obi_amo_cfg ), + .MgrPortObiCfg ( magia_tile_pkg::obi_no_amo_cfg ), + .BypassCut ( 1'b0 ) + ) i_tcdm32_to_hci32_atomic_snitch ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .tcdm_req_i ( gen_signals.tcdm_req[NumMemPortsPerSpatz] ), + .tcdm_rsp_o ( gen_signals.tcdm_rsp[NumMemPortsPerSpatz] ), + .hci_req_o ( hci_master_req_o[NumMemPortsPerSpatz] ), + .hci_rsp_i ( hci_master_rsp_i[NumMemPortsPerSpatz] ) + ); + end endmodule : spatz_cc_wrapper diff --git a/hw/tile/tile_csr.sv b/hw/tile/tile_csr.sv deleted file mode 100644 index 713b3232..00000000 --- a/hw/tile/tile_csr.sv +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2026 ETH Zurich, University of Bologna and Fondazione Chips-IT - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * SPDX-License-Identifier: Apache-2.0 - * - * Authors: Niccolò Giuliani, Fondazione Chips-IT - */ - - - -/* - * Register map (offsets from BaseAddr): - * 0x00–0x18 Spatz registers (handled by obi_slave_ctrl_spatz) - * 0x40–0x44 PULP/Cluster regs (handled by obi_slave_ctrl_cluster) - * 0x100–0x104 Collective registers (handled by obi_slave_ctrl_coll) - */ -module tile_csr - import magia_tile_pkg::*; -#( - parameter logic [31:0] BaseAddr = 32'h00001700, - parameter int unsigned BOOT_ADDR = 32'hCC000000 -) ( - input logic clk_i, - input logic rst_ni, - - // Single OBI slave interface - input core_obi_data_req_t obi_req_i, - output core_obi_data_rsp_t obi_rsp_o, - - // Spatz Control outputs - output logic spatz_clk_en_o, - output logic spatz_start_o, - output logic spatz_done_o, - - // Collective Control outputs - output logic[31:0] collective_mask_o, - output logic[3:0] collective_op_o, - - // Cluster Control outputs - output logic [magia_tile_pkg::N_CLUSTER_CORES-1:0] cluster_clk_en_o, - output logic [31:0] cluster_boot_addr_o [magia_tile_pkg::N_CLUSTER_CORES-1:0], - output logic [magia_tile_pkg::N_CLUSTER_CORES-1:0] cluster_fetch_en_o, - output logic cluster_done_o, - // Per-core 1-cycle dispatch IRQ pulse (drives MEI bit 11 of each PULP core) - output logic [magia_tile_pkg::N_CLUSTER_CORES-1:0] cluster_start_irq_o -); - - // ============================================ - // Internal OBI signals for sub-modules - // ============================================ - core_obi_data_rsp_t spatz_obi_rsp; - core_obi_data_rsp_t collective_obi_rsp; - core_obi_data_rsp_t cluster_obi_rsp; - - // All the sub-modules receive the same OBI request. - // Each checks addr_valid against its own BaseAddr/range, - // so only one will grant at a time. - - // ============================================ - // Spatz control registers (offset 0x00–0x18) - // ============================================ - obi_slave_ctrl_spatz #( - .BaseAddr ( BaseAddr ) - ) i_spatz_ctrl ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .obi_req_i ( obi_req_i ), - .obi_rsp_o ( spatz_obi_rsp ), - .clk_en_o ( spatz_clk_en_o ), - .start_o ( spatz_start_o ), - .done_o ( spatz_done_o ) - ); - - - // ============================================ - // Cluster control registers (offset 0x40–0x44) - // ============================================ - obi_slave_ctrl_cluster #( - .BaseAddr ( BaseAddr + 32'h40 ) - ) i_cluster_ctrl ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .obi_req_i ( obi_req_i ), - .obi_rsp_o ( cluster_obi_rsp ), - .clk_en_o ( cluster_clk_en_o ), - .boot_addr_o ( cluster_boot_addr_o), - .fetch_en_o ( cluster_fetch_en_o ), - .done_o ( cluster_done_o ), - .start_irq_o ( cluster_start_irq_o) - ); - - // ============================================ - // Collective control registers (offset 0x100–0x104) - // ============================================ - obi_slave_ctrl_coll #( - .BaseAddr ( BaseAddr + 32'h100) - ) i_collective_ctrl ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .obi_req_i ( obi_req_i ), - .obi_rsp_o ( collective_obi_rsp ), - .collective_mask_o ( collective_mask_o ), - .collective_op_o ( collective_op_o ) - ); - - - // ============================================ - // OBI response mux - // ============================================ - // Non-overlapping address ranges guarantee at most one - // sub-module grants/responds at a time. - assign obi_rsp_o.gnt = spatz_obi_rsp.gnt | collective_obi_rsp.gnt | cluster_obi_rsp.gnt; - assign obi_rsp_o.rvalid = spatz_obi_rsp.rvalid | collective_obi_rsp.rvalid | cluster_obi_rsp.rvalid; - assign obi_rsp_o.r.rdata = spatz_obi_rsp.rvalid ? spatz_obi_rsp.r.rdata : collective_obi_rsp.rvalid ? collective_obi_rsp.r.rdata : cluster_obi_rsp.r.rdata; - assign obi_rsp_o.r.rid = '0; - assign obi_rsp_o.r.err = spatz_obi_rsp.r.err | collective_obi_rsp.r.err | cluster_obi_rsp.r.err; - assign obi_rsp_o.r.r_optional = '0; - -endmodule \ No newline at end of file diff --git a/scripts/bin2header.py b/scripts/bin2header.py index e36deb41..8669b2cc 100644 --- a/scripts/bin2header.py +++ b/scripts/bin2header.py @@ -1,8 +1,8 @@ # Copyright (C) 2026 ETH Zurich, University of Bologna and Fondazione Chips-IT # -# Licensed under the Solderpad Hardware License, Version 0.51 -# (the "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -# SPDX-License-Identifier: SHL-0.51 +# SPDX-License-Identifier: Apache-2.0 # # Authors: Luca Balboni diff --git a/scripts/bwruntests.py b/scripts/bwruntests.py deleted file mode 100644 index b98681f5..00000000 --- a/scripts/bwruntests.py +++ /dev/null @@ -1,327 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright 2020-2026 ETH Zurich and University of Bologna -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -# Run shell commands listed in a file separated by newlines in a parallel -# fashion. If requested the results (tuples consisting of command, stdout, -# stderr and returncode) will be gathered in a junit.xml file. There a few -# knobs to tune the number of spawned processes and the junit.xml formatting. - -# Author: Robert Balas (balasr@iis.ee.ethz.ch) - -import argparse -from subprocess import (Popen, TimeoutExpired, - CalledProcessError, PIPE) -from threading import Lock -import shlex -import sys -import signal -import os -import multiprocessing -import errno -import pprint -import time - - -runtest = argparse.ArgumentParser( - prog='bwruntests', - formatter_class=argparse.RawDescriptionHelpFormatter, - description="""Run MAGIA tests in parallel""", - epilog=""" -Test_file needs to be either a .yaml file (set the --yaml switch) -which looks like this: - -mytests.yml -[...] -parallel_bare_tests: # name of the test set - parMatrixMul8: # name of the test - path: ./parallel_bare_tests/parMatrixMul8 # path to the test's folder - command: make clean all run # command to run in the test's folder -[...] - -or - -Test_file needs to be a list of commands to be executed. Each line corresponds -to a single command and a test - -commands.f -[...] -make -C ./ml_tests/mlGrad clean all run -make -C ./ml_tests/mlDct clean all run -[...] - -Example: -bwruntests.py --proc-verbose -v \\ - --report-junit -t 3600 --yaml \\ - -o simplified-runtime.xml runtime-tests.yaml - -This Runs a set of tests defined in runtime-tests.yaml and dumps the -resulting junit.xml into simplified-runtime.xml. The --proc-verbose -scripts makes sure to print the stdout of each process to the shell. To -prevent a broken process from running forever, a maximum timeout of 3600 -seconds was set. For debugging purposes we enabled -v (--verbose) which -shows the full set of commands being run.""") - -runtest.version = '0.2' - -runtest.add_argument('test_file', type=str, - help='file defining tests to be run') -runtest.add_argument('--version', action='version', - version='%(prog)s ' + runtest.version) -runtest.add_argument('-p', '--max-procs', type=int, - default=multiprocessing.cpu_count(), - help="""Number of parallel - processes used to run test. - Default is number of cpu cores.""") -runtest.add_argument('-t', '--timeout', type=float, - default=None, - help="""Timeout for all processes in seconds""") -runtest.add_argument('-v', '--verbose', action='store_true', - help="""Enable verbose output""") -runtest.add_argument('-s', '--proc-verbose', action='store_true', - help="""Write processes' stdout and stderr to shell stdout - after they terminate""") -runtest.add_argument('--report-junit', action='store_true', - help="""Generate a junit report""") -runtest.add_argument('--disable-junit-pp', action='store_true', - help="""Disable pretty print of junit report""") -runtest.add_argument('--disable-results-pp', action='store_true', - help="""Disable printing test results""") -runtest.add_argument('-y,', '--yaml', action='store_true', - help="""Read tests from yaml file instead of executing - from a list of commands""") -runtest.add_argument('-o,', '--output', type=str, - help="""Write junit.xml to file instead of stdout""") -stdout_lock = Lock() - - -class FinishedProcess(object): - """A process that has finished running. - """ - def __init__(self, name, cwd, args, returncode, - stdout=None, stderr=None, time=None): - self.name = name - self.cwd = cwd - self.args = args - self.returncode = returncode - self.stdout = stdout - self.stderr = stderr - self.time = time - - def __repr__(self): - args = ['name={!r}'.format(self.name)] - args += ['cwd={!r}'.format(self.cwd)] - args += ['args={!r}'.format(self.args), - 'returncode={!r}'.format(self.returncode)] - if self.stdout is not None: - args.append('stdout={!r}'.format(self.stdout)) - if self.stderr is not None: - args.append('stderr={!r}'.format(self.stderr)) - if self.time is not None: - args.append('time={!r}'.format(self.time)) - return "{}({})".format(type(self).__name__, ', '.join(args)) - - -def fork(name, cwd, *popenargs, check=False, shell=True, - **kwargs): - """Run subprocess and return process args, error code, stdout and stderr - """ - - def proc_out(cwd, stdout, stderr): - print('cwd={}'.format(cwd)) - print('stdout=') - print(stdout.decode('utf-8')) - print('stderr=') - print(stderr.decode('utf-8')) - - kwargs['stdout'] = PIPE - kwargs['stderr'] = PIPE - - with Popen(*popenargs, preexec_fn=os.setpgrp, cwd=cwd, - **kwargs) as process: - try: - # Child and parent are racing for setting/using the pgid so we have - # to set it in both processes. See glib manual. - try: - os.setpgid(process.pid, process.pid) - except OSError as e: - if e.errno != errno.EACCES: - raise - # measure runtime - start = time.time() - stdout, stderr = process.communicate(input, timeout=args.timeout) - except TimeoutExpired: - pgid = os.getpgid(process.pid) - os.killpg(pgid, signal.SIGKILL) - # process.kill() will only kill the immediate child but not its - # forks. This won't work since our commands will create a few forks - # (make -> vsim -> etc). We need to make a process group and kill - # that - stdout, stderr = process.communicate() - timeoutmsg = 'TIMEOUT after {:f}s'.format(args.timeout) - - if args.proc_verbose: - stdout_lock.acquire() - print(name) - print(timeoutmsg) - proc_out(cwd, stdout, stderr) - stdout_lock.release() - - return FinishedProcess(name, cwd, process.args, 1, - stdout.decode('utf-8'), - timeoutmsg + '\n' - + stderr.decode('utf-8'), - time.time() - start) - # Including KeyboardInterrupt, communicate handled that. - except: # noqa: E722 - pgid = os.getpgid(process.pid) - os.killpg(pgid, signal.SIGKILL) - # We don't call process.wait() as .__exit__ does that for us. - raise - retcode = process.poll() - if check and retcode: - raise CalledProcessError(retcode, process.args, - output=stdout, stderr=stderr) - if args.proc_verbose: - stdout_lock.acquire() - print(name) - proc_out(cwd, stdout, stderr) - stdout_lock.release() - - return FinishedProcess(name, cwd, process.args, retcode, - stdout.decode('utf-8'), - stderr.decode('utf-8'), - time.time() - start) - - -if __name__ == '__main__': - args = runtest.parse_args() - pp = pprint.PrettyPrinter(indent=4) - - # lazy importing so that we can work without junit_xml - if args.report_junit: - try: - from junit_xml import TestSuite, TestCase - except ImportError: - print("""Error: The --report-junit option requires -the junit_xml library which is not installed.""", - file=sys.stderr) - exit(1) - - # lazy import PrettyTable for displaying results - if not(args.disable_results_pp): - try: - from prettytable import PrettyTable - except ImportError: - print("""Warning: Displaying results requires the PrettyTable -library which is not installed""") - - tests = [] # list of tuple (testname, working dir, command) - - # load tests (yaml or command list) - if args.yaml: - try: - import yaml - except ImportError: - print("""Error: The --yaml option requires -the pyyaml library which is not installed.""", - file=sys.stderr) - exit(1) - with open(args.test_file) as f: - testyaml = yaml.load(f, Loader=yaml.Loader) - for testsetname, testv in testyaml.items(): - for testname, insn in testv.items(): - cmd = shlex.split(insn['command']) - cwd = insn['path'] - tests.append((testsetname + ':' + testname, cwd, cmd)) - if args.verbose: - pp.pprint(tests) - else: # (command list) - with open(args.test_file) as f: - testnames = list(map(str.rstrip, f)) - shellcmds = [shlex.split(e) for e in testnames] - cwds = ['./' for e in testnames] - tests = list(zip(testnames, cwds, shellcmds)) - if args.verbose: - print('Tests which we are running:') - pp.pprint(tests) - pp.pprint(shellcmds) - - # Spawning process pool - # Disable signals to prevent race. Child processes inherit SIGINT handler - original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN) - pool = multiprocessing.Pool(processes=args.max_procs) - # Restore SIGINT handler - signal.signal(signal.SIGINT, original_sigint_handler) - try: - procresults = pool.starmap(fork, tests) - except KeyboardInterrupt: - print("\nTerminating bwruntest.py") - pool.terminate() - pool.join() - exit(1) - - if args.verbose: - pp.pprint(procresults) - pool.close() - pool.join() - - # Generate junit.xml file. Junit.xml differentiates between failure and - # errors but we treat everything as errors. - if args.report_junit: - testcases = [] - for p in procresults: - # we can either expect p.name = testsetname:testname - # or p.name = testname - testcase = TestCase(p.name, - classname=((p.name).split(':'))[0], - stdout=p.stdout, - stderr=p.stderr, - elapsed_sec=p.time) - if p.returncode != 0: - testcase.add_failure_info(p.stderr) - testcases.append(testcase) - - testsuite = TestSuite('bwruntests', testcases) - if args.output: - with open(args.output, 'w') as f: - TestSuite.to_file(f, [testsuite], - prettyprint=not(args.disable_junit_pp)) - else: - print(TestSuite.to_xml_string([testsuite], - prettyprint=(args.disable_junit_pp))) - - # print summary of test results - if not(args.disable_results_pp): - testcount = sum(1 for x in tests) - testfailcount = sum(1 for p in procresults if p.returncode != 0) - testpassedcount = testcount - testfailcount - resulttable = PrettyTable(['test', 'time', 'passed/total']) - resulttable.align['test'] = "l" - resulttable.add_row(['bwruntest', '', '{0:d}/{1:d}'. - format(testpassedcount, testcount)]) - for p in procresults: - testpassed = 1 if p.returncode == 0 else 0 - testname = p.name - resulttable.add_row([testname, - '{0:.2f}s'.format(p.time), - '{0:d}/{1:d}'.format(testpassed, 1)]) - print(resulttable) \ No newline at end of file diff --git a/scripts/generate_spatz_bootrom.py b/scripts/generate_spatz_bootrom.py index f02985d2..b85eb8dc 100644 --- a/scripts/generate_spatz_bootrom.py +++ b/scripts/generate_spatz_bootrom.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # Copyright 2024 ETH Zurich and University of Bologna. -# Solderpad Hardware License, Version 0.51, see LICENSE for details. -# SPDX-License-Identifier: SHL-0.51 +# Licensed under the Apache License, Version 2.0, see LICENSE.APACHE for details. +# SPDX-License-Identifier: Apache-2.0 # # Generate SystemVerilog bootrom module from binary file @@ -31,7 +31,7 @@ def generate_bootrom_sv(bin_file, output_file): # Generate SystemVerilog module (like spatz_cluster) sv_content = f'''// Copyright (C) 2026 ETH Zurich, University of Bologna and Fondazione Chips-IT. -// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// Solderpad Hardware License, Version 0.51, see LICENSE.SHL for details. // SPDX-License-Identifier: SHL-0.51 // // Auto-generated bootrom for Spatz core complex diff --git a/scripts/run_regression.py b/scripts/run_regression.py new file mode 100755 index 00000000..fdf0eb4a --- /dev/null +++ b/scripts/run_regression.py @@ -0,0 +1,728 @@ +#!/usr/bin/env python3 +# Copyright (C) 2026 ETH Zurich, University of Bologna and Fondazione Chips-IT +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# SPDX-License-Identifier: Apache-2.0 +# +# Author: Luca Balboni, Fondazione Chips-IT +# +# Run the MAGIA tests of sw/tests/tests.yml over several build configurations, one after the other. +# +# Usage: scripts/run_regression.py --sim SIM --core CORE --fsync on|off --test TEST [options] +# --sim/--core/--fsync take a value, a comma list or `all`; --test takes `all`, `mesh`, `tile`, +# a folder of sw/tests/ (`general` is sw/tests/ itself) or folder/test. See --help for the rest. +# +# Each configuration builds in its own worktree under .regression/, and its HW is rebuilt only when +# its sources change (--rebuild forces it). Tests run only where their sims/cores/requires allow; +# --list prints the plan and the tests left out. Results, with one log per build and per test, go +# to .regression/results//. +# +# Environment: riscv64-unknown-elf-gcc and bender on PATH (or BENDER), SPATZ_LLVM_PATH for Spatz, +# and optionally MAGIA_QUESTA_SETUP / MAGIA_VERILATOR_SETUP to load the simulators. +# +# Examples: +# scripts/run_regression.py --sim questa --core CV32E40P --fsync on --test mm_tests/fsync_test_mm +# scripts/run_regression.py --sim verilator --core CV32E40P --fsync on --test collective_tests +# scripts/run_regression.py --sim all --core all --fsync all --test all + +import argparse +import collections +import concurrent.futures +import datetime +import hashlib +import os +import re +import shutil +import signal +import subprocess +import sys +import threading +import time + +import yaml + +# Tuning: software builds and simulations running at the same time in each build, and per-test timeouts +PARALLEL_SIMS = 4 +TIMEOUT_MESH_S = 3600 +TIMEOUT_TILE_S = 1800 +MONITOR_PERIOD_S = 60 # Dashboard period when stdout is not a terminal (a terminal refreshes every 2 s); 0 disables it + +# Simulator setup, run before every command of that simulator; empty means the tools are already on PATH +QUESTA_SETUP = os.environ.get('MAGIA_QUESTA_SETUP', '') +VERILATOR_SETUP = os.environ.get('MAGIA_VERILATOR_SETUP', '') +QUESTA_ENV = f"{QUESTA_SETUP} && " if QUESTA_SETUP else '' +VERILATOR_ENV = f"{VERILATOR_SETUP} && " if VERILATOR_SETUP else '' + +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +DEFAULT_YML = ['sw/tests/tests.yml'] +TESTBENCHES = ('mesh', 'tile') +SIMS = ('questa', 'verilator') +CORES = ('CV32E40P', 'CV32E40X') +FSYNC = ('on', 'off') + +print_lock = threading.Lock() +git_lock = threading.Lock() # git worktree add/remove cannot run concurrently + +TTY = sys.stdout.isatty() # A terminal gets the dashboard redrawn in place + + +class Console: + """Where log lines go: printed before the run, into the dashboard during a live run, always to a file.""" + + def __init__(self): + self.live = False # True while the terminal dashboard owns the screen + self.events = collections.deque(maxlen=6) + self.logfh = None + + +console = Console() + + +def log(msg): + line = f"[{time.strftime('%H:%M:%S')}] {msg}" + with print_lock: + console.events.append(line) + if console.logfh: + console.logfh.write(line + '\n') + console.logfh.flush() + if not console.live: + print(line, flush=True) + + +def hms(sec): + sec = int(sec) + return f"{sec // 3600:d}:{sec % 3600 // 60:02d}:{sec % 60:02d}" + + +# Error lines of a failed log, most telling first: tool errors, then test results, then make +ERROR_RES = [re.compile(r'%Error|\*\* (Error|Fatal)|\$fatal|Fatal error|\berror:|undefined reference|' + r'Segmentation fault|Traceback|[Cc]ommand not found|No such file or directory|cannot open'), + re.compile(r'TILE\[.*\] ERRORS|EXIT CODE: *0*[1-9a-fA-F]|Assertion'), + re.compile(r'make(\[\d+\])?: \*\*\*')] + + +def first_error(logfile): + """The most telling error line of a log, or its last non-empty line, cut to one readable line.""" + try: + with open(logfile, errors='replace') as fh: + lines = [ln.strip() for ln in fh if ln.strip() and not ln.startswith(('$ ', '===== '))] + except OSError: + return f"no log ({logfile})" + hit = next((ln for rx in ERROR_RES for ln in lines if rx.search(ln)), None) + line = hit or (lines[-1] if lines else 'empty log') + line = re.sub(r'\s+', ' ', line.replace(ROOT, '.')) + return line if len(line) <= 140 else line[:137] + '...' + + +class Progress: + """Live state of every build: phase, results and running tests.""" + + def __init__(self): + self.lock = threading.Lock() + self.jobs = {} # job -> state, in execution order + + def add(self, job, label, total): + with self.lock: + self.jobs[job] = {'label': label, 'phase': 'queued', 'since': None, 'start': None, 'end': None, + 'total': total, 'results': {}, 'logs': {}, 'reasons': {}, 'running': {}, + 'build_error': None} + + def phase(self, job, phase): + with self.lock: + j = self.jobs[job] + now = time.time() + j['phase'], j['since'] = phase, now + j['start'] = j['start'] or now + if phase == 'done': + j['end'] = now + + def start(self, job, test): + with self.lock: + self.jobs[job]['running'][test] = time.time() + + def done(self, job, test, status, logfile=None, reason=None): + with self.lock: + j = self.jobs[job] + j['running'].pop(test, None) + j['results'][test] = status + j['logs'][test] = logfile + j['reasons'][test] = reason + + def build_failed(self, job, logfile, reason, status='HW_BUILD_FAIL'): + """The build failed, so none of its tests ran: reported once for the whole build.""" + with self.lock: + self.jobs[job]['build_error'] = (logfile, reason, status) + + def report(self, t0, out_dir, final=False): + """The dashboard: one row per build, then failures, running tests and recent events.""" + now = time.time() + width = 92 + rule = '─' * width + title = 'MAGIA regression · finished' if final else 'MAGIA regression · running' + lines = [f"{title} {time.strftime('%H:%M:%S')} elapsed {hms(now - t0)}", + f"results: {out_dir}", rule, + f"{'#':>2} {'build':42s} {'phase':10s} {'pass':>5s} {'fail':>5s} {'run':>4s} " + f"{'todo':>5s} {'time':>8s}", rule] + fails, running = [], [] + tot = npass = nfail = nrun = 0 + with self.lock: + for n, (job, j) in enumerate(self.jobs.items(), 1): + p = sum(v == 'PASS' for v in j['results'].values()) + f = len(j['results']) - p + r = len(j['running']) + todo = j['total'] - len(j['results']) - r + tot, npass, nfail, nrun = tot + j['total'], npass + p, nfail + f, nrun + r + if j['start'] is None: + t = '-' + else: + t = hms((j['end'] or now) - j['start']) + lines.append(f"{n:2d} {j['label']:42s} {j['phase']:10s} {p:5d} {f:5d} {r:4d} {todo:5d} {t:>8s}") + if j['build_error']: + lf, why, st = j['build_error'] + fails.append((n, f"build ({j['total']} tests not run)", st, lf, why)) + else: + for test, st in j['results'].items(): + if st != 'PASS': + fails.append((n, test, st, j['logs'].get(test), j['reasons'].get(test))) + for test, st in j['running'].items(): + running.append((now - st, n, test)) + lines.append(rule) + lines.append(f"total {tot} pass {npass} fail {nfail} running {nrun} todo {tot - npass - nfail - nrun}") + if fails: + lines += ['', f"failures"] + for n, test, st, lf, why in fails: + lines.append(f" #{n:<2d} {test:38s} {st}") + if why: + lines.append(f" {why}") + if lf: + lines.append(f" log: {lf}") + if running and not final: + lines += ['', f"running (longest first)"] + for el, n, test in sorted(running, reverse=True)[:8]: + lines.append(f" #{n:<2d} {test:38s} {hms(el)}") + if len(running) > 8: + lines.append(f" ... and {len(running) - 8} more") + if console.events and not final: + lines += ['', f"recent"] + [f" {e}" for e in console.events] + return '\n'.join(lines) + + +progress = Progress() + + +class Screen: + """Redraws a block of text in place: moves up over the previous block and erases it, so the + terminal scrollback never fills with old copies.""" + + def __init__(self): + self.height = 0 # Lines drawn by the previous update + + def draw(self, text, fit=True): + """`fit` clips to the terminal so the next update can move back over every line.""" + size = shutil.get_terminal_size() + lines = text.split('\n') + if fit: + lines = [line[:size.columns - 1] for line in lines][:size.lines - 1] + up = f"\033[{self.height}F" if self.height else '' + sys.stdout.write(up + '\033[J' + '\n'.join(lines) + '\n') + sys.stdout.flush() + self.height = len(lines) + + +screen = Screen() + + +def monitor(period, t0, out_dir, stop): + """Redraws the dashboard in place on a terminal, prints it every `period` s otherwise.""" + step = 2 if TTY else period + while not stop.wait(step): + rep = progress.report(t0, out_dir) + with print_lock: + if TTY: + screen.draw(rep) + elif period > 0: + print(rep, flush=True) + with open(os.path.join(out_dir, 'status.txt'), 'w') as fh: + fh.write(rep + '\n') + + +def sh(cmd, cwd, logfile=None, timeout=None, env=None, title=None): + """Run a shell command; kill its whole process group on timeout. Returns rc, or None on timeout. + With a title the output is appended to the log under a header naming the step and the command.""" + out = open(logfile, 'a' if title else 'w') if logfile else subprocess.DEVNULL + if title: + out.write(f"\n===== {title} [{time.strftime('%H:%M:%S')}]\n$ {cmd}\n\n") + out.flush() + try: + p = subprocess.Popen(cmd, cwd=cwd, shell=True, stdout=out, stderr=subprocess.STDOUT, + start_new_session=True, env=env) + try: + return p.wait(timeout=timeout) + except subprocess.TimeoutExpired: + os.killpg(p.pid, signal.SIGKILL) + p.wait() + return None + finally: + if logfile: + out.close() + + +def unsupported(sim, core, fsync): + """Why a configuration cannot be built, or None if it can.""" + return None + + +class Config: + """A build configuration: simulator, control core and FractalSync on/off.""" + + def __init__(self, sim, core, fsync): + self.sim = sim + self.core = core + self.fsync = fsync == 'on' + self.defines = {core} | ({'MAGIA_FSYNC'} if self.fsync else set()) + self.name = f"{self.sim}_{core}_{'fsync' if self.fsync else 'nofsync'}" + + def make_args(self, mesh_dv, fast): + return f"core={self.core} fsync={int(self.fsync)} mesh_dv={mesh_dv} fast_sim={int(fast)}" + + def reject(self, test): + """Why the test does not run in this configuration, or None if it does.""" + if self.sim not in test['sims']: + return f"runs only on {'/'.join(test['sims'])}" + if self.core not in test['cores']: + return f"runs only on {'/'.join(test['cores'])}" + missing = set(test['requires']) - self.defines + if missing: + return f"requires {' '.join(sorted(missing))}" + return None + + +def parse_choice(opt, value, choices): + """Comma list or `all` of an option; returns (values, from_all).""" + if value == 'all': + return list(choices), True + values = value.split(',') + bad = [v for v in values if v not in choices] + if bad: + sys.exit(f"{opt}: unknown value(s) {' '.join(bad)} (use {', '.join(choices)} or all)") + return values, False + + +def load_tests(yml_files): + """Tests of the yml lists; each top-level key must be the sw/tests/ folder of its tests.""" + tests = [] + for f in yml_files: + with open(os.path.join(ROOT, f)) as fh: + for folder, entries in yaml.safe_load(fh).items(): + for name, t in entries.items(): + if t.get('testbench') not in TESTBENCHES: + sys.exit(f"{f}:{name}: testbench must be one of {', '.join(TESTBENCHES)}") + if test_folder(name) != folder: + sys.exit(f"{f}:{name}: listed under {folder} but lives in {test_folder(name)}") + sims = t.get('sims') or [] + if not sims or not set(sims) <= set(SIMS): + sys.exit(f"{f}:{name}: sims must list some of {', '.join(SIMS)}") + tests.append({'name': name, 'testbench': t['testbench'], 'sims': sims, + 'mesh_dv': int(t['testbench'] == 'mesh'), + 'cores': t.get('cores', list(CORES)), + 'requires': t.get('requires') or [], + 'fast_sim': t.get('fast_sim', True), + 'timeout': t.get('timeout'), + 'path': f"{folder}/{os.path.basename(name)}"}) + return tests + + +def test_folder(name): + """Folder of a test under sw/tests/, or 'general' for tests that live in sw/tests/ itself.""" + base = os.path.join(ROOT, 'sw', 'tests') + if '/' in name: + rel = os.path.dirname(name) + else: + rel = '' + for dirpath, dirnames, filenames in os.walk(base): + if name + '.c' in filenames or name in dirnames: + rel = os.path.relpath(dirpath, base) + break + rel = '' if rel == '.' else rel + return rel.split(os.sep)[0] if rel else 'general' + + +# Paths that never change the HW build: test software, docs and this script +NON_HW_RE = re.compile(r'^(sw/|spatz/sw/|doc/|\.github/|\.regression|scripts/run_regression\.py$|' + r'.*\.md$|\.gitlab-ci\.yml$)') + + +def hw_fingerprint(*extra): + """Hash of every file of the working tree that feeds the HW build, plus build arguments and setup.""" + files = subprocess.run(['git', 'ls-files', '-co', '--exclude-standard', '-z'], cwd=ROOT, check=True, + stdout=subprocess.PIPE).stdout.decode().split('\0') + h = hashlib.sha256('\0'.join(extra).encode()) + for f in sorted(filter(None, files)): + path = os.path.join(ROOT, f) + if NON_HW_RE.match(f) or not os.path.isfile(path): + continue + h.update(f.encode() + b'\0') + with open(path, 'rb') as fh: + h.update(fh.read()) + return h.hexdigest() + + +def copy_changes(wt): + """Applies the uncommitted changes and untracked files of the working tree to a worktree at HEAD.""" + diff = subprocess.run(['git', 'diff', 'HEAD', '--binary'], cwd=ROOT, check=True, + stdout=subprocess.PIPE).stdout + if diff: + # Files the diff adds survive the reset of a reused worktree as untracked and would block the apply + added = subprocess.run(['git', 'diff', 'HEAD', '--name-only', '--diff-filter=AR', '-z'], cwd=ROOT, + check=True, stdout=subprocess.PIPE).stdout.decode().split('\0') + for f in filter(None, added): + if os.path.isfile(os.path.join(wt, f)): + os.remove(os.path.join(wt, f)) + subprocess.run(['git', 'apply', '--whitespace=nowarn'], cwd=wt, input=diff, check=True) + untracked = subprocess.run(['git', 'ls-files', '--others', '--exclude-standard', '-z'], cwd=ROOT, + check=True, stdout=subprocess.PIPE).stdout.decode().split('\0') + for f in filter(None, untracked): + if f.startswith('.regression'): + continue + os.makedirs(os.path.dirname(os.path.join(wt, f)) or wt, exist_ok=True) + shutil.copy2(os.path.join(ROOT, f), os.path.join(wt, f)) + + +def make_worktree(wt): + """New worktree at HEAD with the working-tree changes.""" + with git_lock: + if os.path.exists(wt): + subprocess.run(['git', 'worktree', 'remove', '--force', wt], cwd=ROOT, check=False, + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + shutil.rmtree(wt, ignore_errors=True) + subprocess.run(['git', 'worktree', 'prune'], cwd=ROOT, check=True) + subprocess.run(['git', 'worktree', 'add', '--detach', wt, 'HEAD'], cwd=ROOT, check=True, + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + copy_changes(wt) + + +def sync_worktree(wt): + """Brings an existing worktree to HEAD plus the working-tree changes; build outputs are untracked + files, so the reset leaves them in place.""" + head = subprocess.run(['git', 'rev-parse', 'HEAD'], cwd=ROOT, check=True, + stdout=subprocess.PIPE).stdout.decode().strip() + with git_lock: + subprocess.run(['git', 'reset', '-q', '--hard', head], cwd=wt, check=True) + copy_changes(wt) + + +def share_bender(wt, work_dir): + """Points the worktree's .bender at one dependency checkout shared by every build, instead of a + full clone per worktree (builds run one at a time, so they never touch it concurrently).""" + shared = os.path.join(work_dir, 'bender_deps') + os.makedirs(shared, exist_ok=True) + link = os.path.join(wt, '.bender') + if os.path.islink(link): + return + if os.path.exists(link): + shutil.rmtree(link) + os.symlink(shared, link) + + +def job_name(cfg, mesh_dv, fast): + return f"{cfg.name}_{'mesh' if mesh_dv else 'tile'}{'' if fast else '_nofast'}" + + +def job_label(cfg, mesh_dv, fast): + return (f"{cfg.sim:9s} {cfg.core:8s} {'fsync' if cfg.fsync else 'nofsync':7s} " + f"{'mesh' if mesh_dv else 'tile'}{'' if fast else ' nofast'}") + + +def select_tests(tests, selectors): + """Tests matching any selector: `all`, a testbench (mesh, tile), a folder or folder/test.""" + if 'all' in selectors: + return tests + folders = sorted({t['path'].split('/')[0] for t in tests}) + sel = [] + for s in selectors: + hit = [t for t in tests if t['testbench'] == s or t['path'] == s or t['path'].startswith(s + '/')] + if not hit: + sys.exit(f"--test {s}: no such testbench, folder or test (testbenches: {' '.join(TESTBENCHES)}; " + f"folders: {' '.join(folders)}; --test all --list prints every test)") + sel += [t for t in hit if t not in sel] + return sel + + +def print_plan(jobs, skipped, verbose): + """Builds in execution order, then the tests left out of each configuration and why.""" + print(f"\nPlan: {len(jobs)} build(s), {sum(len(sel) for *_, sel in jobs)} test run(s), " + f"one build at a time") + print(f"{'#':>2} {'build':42s} {'tests':>5s}") + for n, (cfg, mesh_dv, fast, sel) in enumerate(jobs, 1): + print(f"{n:2d} {job_label(cfg, mesh_dv, fast):42s} {len(sel):5d}") + if verbose: + print(f" {' '.join(t['path'] for t in sel)}") + if skipped: + print(f"\nNot run") + for cfg, why, names in skipped: + cfg_label = f"{cfg.sim} {cfg.core} {'fsync' if cfg.fsync else 'nofsync'}" + print(f" {cfg_label:32s} {len(names):3d} test(s): {why}") + if verbose: + print(f" {' '.join(names)}") + if not verbose: + print(f"(--list shows the test paths)") + + +def run_job(cfg, mesh_dv, fast, tests, args, out_dir): + """Build one configuration and run its tests. Returns {test name: status}.""" + job = job_name(cfg, mesh_dv, fast) + wt = os.path.join(args.work_dir, job) + jlog = os.path.join(out_dir, job) + os.makedirs(jlog, exist_ok=True) + margs = f"{cfg.make_args(mesh_dv, fast)} BENDER={args.bender}" + env = VERILATOR_ENV if cfg.sim == 'verilator' else QUESTA_ENV + results = {} + + # The HW is rebuilt only when a file feeding it, the build arguments or the tool setup changed + stamp = os.path.join(args.work_dir, f"{job}.hw_stamp") + fingerprint = hw_fingerprint(margs, env, QUESTA_ENV) + if os.path.exists(os.path.join(wt, '.git')): + progress.phase(job, 'sync') + log(f"{job}: updating worktree") + sync_worktree(wt) + else: + progress.phase(job, 'worktree') + log(f"{job}: creating worktree") + make_worktree(wt) + built = open(stamp).read().strip() if os.path.exists(stamp) else None + + hlog = f"{jlog}/hw_build.log" + if built == fingerprint and not args.rebuild: + log(f"{job}: HW unchanged since the last build, reusing it") + with open(hlog, 'w') as fh: + fh.write(f"HW unchanged since the last successful build, reusing the one in {wt}\n") + else: + why = 'forced by --rebuild' if args.rebuild else 'first build' if built is None else 'HW sources changed' + progress.phase(job, 'hw build') + log(f"{job}: building HW ({why})") + if os.path.exists(stamp): + os.remove(stamp) + with open(hlog, 'w') as fh: + fh.write(f"HW build of {job} ({why}) in {wt}\n") + share_bender(wt, args.work_dir) + ok = sh(f"{args.bender} checkout", wt, hlog, title='bender checkout') == 0 + # vsim-scripts also generates the iDMA RTL, which the Verilator flow needs too + ok = ok and sh(f"{QUESTA_ENV}make vsim-scripts {margs}", wt, hlog, title='compile scripts') == 0 + if ok and cfg.sim == 'verilator': + ok = sh(f"{env}make verilate {margs}", wt, hlog, title='Verilator model') == 0 + elif ok: + ok = sh(f"{env}make build-hw {margs}", wt, hlog, title='Questa build') == 0 + if ok: + with open(stamp, 'w') as fh: + fh.write(fingerprint + '\n') + else: + why = first_error(hlog) + log(f"{job}: HW build FAILED: {why}") + progress.build_failed(job, hlog, why) + for t in tests: + progress.done(job, t['path'], 'HW_BUILD_FAIL', hlog, why) + progress.phase(job, 'done') + return {t['path']: 'HW_BUILD_FAIL' for t in tests} + + # One log per test, SW build then simulation; tests run in parallel, so they never share a file + tdir = os.path.join(jlog, 'tests') + os.makedirs(tdir, exist_ok=True) + + def test_log(t): + return os.path.join(tdir, t['path'].replace('/', '__') + '.log') + + # `make clean` only touches this test's artifacts, so software builds can run in parallel too + def build_one(t): + open(test_log(t), 'w').close() + return t, sh(f"make clean all {margs} test={t['name']}", wt, test_log(t), title='SW build') == 0 + + progress.phase(job, 'sw build') + runnable = [] + with concurrent.futures.ThreadPoolExecutor(max_workers=args.procs) as pool: + for t, ok in pool.map(build_one, tests): + if ok: + runnable.append(t) + else: + results[t['path']] = 'SW_BUILD_FAIL' + why = first_error(test_log(t)) + log(f"{job}: {t['path']} SW build FAILED: {why}") + progress.done(job, t['path'], 'SW_BUILD_FAIL', test_log(t), why) + progress.phase(job, 'running') + log(f"{job}: {len(runnable)}/{len(tests)} tests built, running {args.procs} at a time") + + timeout = args.timeout_mesh if mesh_dv else args.timeout_tile + + def run_one(t): + logfile = test_log(t) + start = time.time() + progress.start(job, t['path']) + target = 'verilate-run' if cfg.sim == 'verilator' else 'run' + rc = sh(f"{env}make {target} {margs} test={t['name']}", wt, logfile, timeout=t['timeout'] or timeout, + title='simulation') + with open(logfile, errors='replace') as fh: + m = re.findall(r'EXIT CODE:\s*([0-9a-fA-Fx]+)', fh.read()) + limit = t['timeout'] or timeout + why = None + if rc is None: + st = 'TIMEOUT' + why = f"no EXIT CODE within {limit} s, last line: {first_error(logfile)}" + elif m and int(m[-1], 16) == 0: + st = 'PASS' + else: + st = f"FAIL(exit={m[-1] if m else 'none'})" + why = first_error(logfile) + log(f"{job}: {t['path']} {st} ({time.time() - start:.0f}s)" + (f": {why}" if why else '')) + progress.done(job, t['path'], st, logfile, why) + return t['path'], st + + with concurrent.futures.ThreadPoolExecutor(max_workers=args.procs) as pool: + for name, st in pool.map(run_one, runnable): + results[name] = st + progress.phase(job, 'done') + return results + + +def check_tools(bender, sims): + """Stops before any build if a tool the selected simulators need is missing.""" + missing = [] + if not shutil.which('riscv64-unknown-elf-gcc'): + missing.append('riscv64-unknown-elf-gcc on PATH') + if not shutil.which(bender): + missing.append(f"bender ({bender}): put it on PATH, set BENDER or pass --bender") + if 'questa' in sims and sh(f"{QUESTA_ENV}command -v vsim", ROOT) != 0: + missing.append('vsim: put Questa on PATH or set MAGIA_QUESTA_SETUP') + if 'verilator' in sims and sh(f"{VERILATOR_ENV}command -v verilator", ROOT) != 0: + missing.append('verilator: put it on PATH or set MAGIA_VERILATOR_SETUP') + if missing: + sys.exit('missing tools:\n ' + '\n '.join(missing)) + + +def main(): + ap = argparse.ArgumentParser(description='Run the MAGIA regression over several build configurations.') + ap.add_argument('yml', nargs='*', default=DEFAULT_YML, help='test lists (default: sw/tests/tests.yml)') + ap.add_argument('--sim', required=True, help=f"{', '.join(SIMS)} or all (comma list)") + ap.add_argument('--core', required=True, help=f"{', '.join(CORES)} or all (comma list)") + ap.add_argument('--fsync', required=True, help=f"{', '.join(FSYNC)} or all (comma list)") + ap.add_argument('--test', action='append', required=True, + help="all, mesh, tile, a folder of sw/tests/ ('general' = sw/tests/ itself) or " + "folder/test; repeatable, comma separated") + ap.add_argument('-p', '--procs', type=int, default=PARALLEL_SIMS, help='simulations in parallel per build') + ap.add_argument('--timeout-mesh', type=int, default=TIMEOUT_MESH_S, help='seconds per mesh test') + ap.add_argument('--timeout-tile', type=int, default=TIMEOUT_TILE_S, help='seconds per tile test') + ap.add_argument('--work-dir', default=os.path.join(ROOT, '.regression'), help='worktrees and results') + ap.add_argument('--bender', default=os.environ.get('BENDER', 'bender'), help='bender binary (default: $BENDER or bender)') + ap.add_argument('--rebuild', action='store_true', help='rebuild the HW even if its sources did not change') + ap.add_argument('--list', action='store_true', help='print the selected tests and exit') + ap.add_argument('--monitor', type=int, default=MONITOR_PERIOD_S, + help='seconds between dashboards when not on a terminal, 0 disables') + args = ap.parse_args() + args.work_dir = os.path.abspath(args.work_dir) + + sims, all_sims = parse_choice('--sim', args.sim, SIMS) + cores, all_cores = parse_choice('--core', args.core, CORES) + fsyncs, _ = parse_choice('--fsync', args.fsync, FSYNC) + configs = [] + for sim in sims: + for core in cores: + for fsync in fsyncs: + why = unsupported(sim, core, fsync) + if why and not (all_sims or all_cores): + sys.exit(f"configuration {sim} {core} fsync={fsync} is not supported: {why}") + if why: + print(f"skipping {sim} {core} fsync={fsync}: {why}") + else: + configs.append(Config(sim, core, fsync)) + + tests = load_tests(args.yml) + tests = select_tests(tests, [v.strip('/') for arg in args.test for v in arg.split(',')]) + + # fast_sim only changes the Questa build, Verilator runs every test in one build + jobs = [] + skipped = [] # (config, reason, test names) + for cfg in configs: + by_reason = {} + for t in tests: + why = cfg.reject(t) + if why: + by_reason.setdefault(why, []).append(t['path']) + skipped += [(cfg, why, names) for why, names in by_reason.items()] # names are sw/tests/ paths + for mesh_dv in (1, 0): + for fast in (True, False): + sel = [t for t in tests if t['mesh_dv'] == mesh_dv and cfg.reject(t) is None and + (cfg.sim == 'verilator' or t['fast_sim'] == fast)] + if cfg.sim == 'verilator' and not fast: + sel = [] + if sel: + jobs.append((cfg, mesh_dv, fast, sel)) + print_plan(jobs, skipped, args.list) + if not jobs: + sys.exit("none of the selected tests runs in the selected configurations") + if args.list: + return + check_tools(args.bender, {cfg.sim for cfg, *_ in jobs}) + + stamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S') + out_dir = os.path.join(args.work_dir, 'results', stamp) + os.makedirs(out_dir, exist_ok=True) + console.logfh = open(os.path.join(out_dir, 'events.log'), 'w') + for cfg, mesh_dv, fast, sel in jobs: + progress.add(job_name(cfg, mesh_dv, fast), job_label(cfg, mesh_dv, fast), len(sel)) + print(f"\nresults in {out_dir}\n", flush=True) + + t0 = time.time() + stop = threading.Event() + console.live = TTY + if TTY or args.monitor > 0: + threading.Thread(target=monitor, args=(args.monitor, t0, out_dir, stop), daemon=True).start() + + # One build at a time: builds and simulations of different configurations never overlap + results = {} + for cfg, mesh_dv, fast, sel in jobs: + job = job_name(cfg, mesh_dv, fast) + try: + results[job] = run_job(cfg, mesh_dv, fast, sel, args, out_dir) + except Exception as e: # noqa: BLE001 + log(f"{job}: {e}") + results[job] = {t['path']: 'ERROR' for t in sel} + progress.build_failed(job, None, f"script error: {e}", 'ERROR') + for t in sel: + progress.done(job, t['path'], 'ERROR', None, str(e)) + progress.phase(job, 'done') + + stop.set() + console.live = False + final = progress.report(t0, out_dir, final=True) + with open(os.path.join(out_dir, 'status.txt'), 'w') as fh: + fh.write(final + '\n') + + lines = ['| build | test | result |', '|---|---|---|'] + npass = ntot = 0 + for job in results: + for name, st in sorted(results[job].items()): + lines.append(f"| {job} | {name} | {st} |") + ntot += 1 + npass += st == 'PASS' + lines.append(f"\n{npass}/{ntot} passed") + with open(os.path.join(out_dir, 'summary.md'), 'w') as fh: + fh.write('\n'.join(lines) + '\n') + with print_lock: + if TTY: + screen.draw(final, fit=False) + else: + print('\n' + final, flush=True) + print(f"\n{npass}/{ntot} passed (summary.md, status.txt and events.log in {out_dir})") + sys.exit(0 if npass == ntot else 1) + + +if __name__ == '__main__': + main() diff --git a/scripts/sim_ret_errors.sh b/scripts/sim_ret_errors.sh index 8b6d4979..08c87437 100755 --- a/scripts/sim_ret_errors.sh +++ b/scripts/sim_ret_errors.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash # Copyright 2025 ETH Zurich and University of Bologna. -# Solderpad Hardware License, Version 0.51, see LICENSE.SHL for details. -# SPDX-License-Identifier: SHL-0.51 +# Licensed under the Apache License, Version 2.0, see LICENSE.APACHE for details. +# SPDX-License-Identifier: Apache-2.0 # Author: Alessandro Nadalini diff --git a/scripts/sim_ret_errors_verilator.sh b/scripts/sim_ret_errors_verilator.sh index 2613688a..7626404a 100755 --- a/scripts/sim_ret_errors_verilator.sh +++ b/scripts/sim_ret_errors_verilator.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash # Copyright 2026 ETH Zurich and University of Bologna. -# Solderpad Hardware License, Version 0.51, see LICENSE.SHL for details. -# SPDX-License-Identifier: SHL-0.51 +# Licensed under the Apache License, Version 2.0, see LICENSE.APACHE for details. +# SPDX-License-Identifier: Apache-2.0 # Verilator counterpart of sim_ret_errors.sh. QuestaSim prints an "Errors: N" # summary; Verilator prints nothing of the sort, so the verdict comes from the diff --git a/spatz/README.md b/spatz/README.md index d90ba1f7..ebf960a3 100644 --- a/spatz/README.md +++ b/spatz/README.md @@ -337,15 +337,12 @@ make python_venv source setup_env.sh make python_deps make bender -make update-ips > update-ips.log -make floonoc-patch +make vsim-scripts mesh_dv=0 > vsim-scripts.log -# 2. Build hardware (QuestaSim) -module load questasim/2024.3 +# 2. Build hardware (QuestaSim on PATH) make build-hw mesh_dv=0 fast_sim=1 > build-hw.log -# 3. Build software (auto-detects Spatz tasks) -module load pulp-gcc7/1.0.16 +# 3. Build software (auto-detects Spatz tasks; RISC-V GCC on PATH, SPATZ_LLVM_PATH set to the Spatz LLVM) make clean all test='my_test' mesh_dv=0 # 4. Run simulation diff --git a/spatz/bootrom/Makefile b/spatz/bootrom/Makefile index 9ae31cab..62d53737 100644 --- a/spatz/bootrom/Makefile +++ b/spatz/bootrom/Makefile @@ -1,8 +1,8 @@ # Copyright (C) 2026 ETH Zurich, University of Bologna and Fondazione Chips-IT # -# Licensed under the Solderpad Hardware License, Version 0.51 -# (the "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -# SPDX-License-Identifier: SHL-0.51 +# SPDX-License-Identifier: Apache-2.0 # # Authors: Luca Balboni # Spatz Initialization ROM Makefile for MAGIA Tile diff --git a/spatz/bootrom/spatz_init.ld b/spatz/bootrom/spatz_init.ld index 1d791eb1..e45d581b 100644 --- a/spatz/bootrom/spatz_init.ld +++ b/spatz/bootrom/spatz_init.ld @@ -1,9 +1,9 @@ /* * Copyright (C) 2026 ETH Zurich, University of Bologna and Fondazione Chips-IT * - * Licensed under the Solderpad Hardware License, Version 0.51 - * (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -12,7 +12,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * SPDX-License-Identifier: SHL-0.51 + * SPDX-License-Identifier: Apache-2.0 /* * Authors: Luca Balboni * diff --git a/spatz/sw/Makefile b/spatz/sw/Makefile index 374777b9..36970b39 100644 --- a/spatz/sw/Makefile +++ b/spatz/sw/Makefile @@ -1,8 +1,8 @@ # Copyright (C) 2026 ETH Zurich, University of Bologna and Fondazione Chips-IT # -# Licensed under the Solderpad Hardware License, Version 0.51 -# (the "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -# SPDX-License-Identifier: SHL-0.51 +# SPDX-License-Identifier: Apache-2.0 # # Authors: Luca Balboni # Spatz Programs Makefile for MAGIA Tile @@ -106,7 +106,8 @@ TASK_SRCS = $(addprefix $(TESTS_DIR)/,$(addsuffix .c,$(task))) # Source and output files CRT0 = $(KERNEL_DIR)/spatz_crt0.S -CRT0_OBJ = $(BIN_DIR)/spatz_crt0.o +# Per test, so tests can build in parallel +CRT0_OBJ = $(BIN_DIR)/$(TEST_NAME)_spatz_crt0.o ELF = $(BIN_DIR)/$(BINARY_NAME).elf BIN = $(BIN_DIR)/$(BINARY_NAME).bin DUMP = $(BIN_DIR)/$(BINARY_NAME).dump @@ -115,7 +116,7 @@ HEADER = $(HEADER_DIR)/$(HEADER_NAME).h # Python script for bin2header conversion BIN2HEADER = ../../scripts/bin2header.py -.PHONY: all clean bin header dirs +.PHONY: all clean clean-test bin header dirs # Complete build: compile binary and generate header # Force header regeneration when TASKS changes (always delete and rebuild) @@ -152,10 +153,10 @@ $(ELF): $(CRT0_OBJ) $(TASK_SRCS) $(KERNEL_DIR)/spatz_program.ld $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(CRT0_OBJ) $(TASK_SRCS) \ -Wl,--defsym,__first_task=$${FIRST_TASK} -# Generate binary from ELF +# Generate binary from ELF; .bss goes in the blob, or crt0 zeroes the code linked right after it $(BIN): $(ELF) @echo "[SPATZ] Generating binary..." - $(OBJCOPY) -O binary $< $@ + $(OBJCOPY) -O binary --set-section-flags .bss=alloc,load,contents $< $@ # Generate disassembly $(DUMP): $(ELF) diff --git a/spatz/sw/kernel/spatz_program.ld b/spatz/sw/kernel/spatz_program.ld index e1671380..998ecbf0 100644 --- a/spatz/sw/kernel/spatz_program.ld +++ b/spatz/sw/kernel/spatz_program.ld @@ -20,8 +20,8 @@ * 0xCC000000: CV32 .text * 0xCC000000 + CV32_size: .spatz_binary (Spatz code inline) * - * Stack: Spatz uses remaining 16KB after CV32 (0x0001C000-0x00020000) - * - CV32 uses: 0x00010000-0x0001C000 (48KB) + * Stack: Spatz uses the 16KB above the CV32/PULP stack region (0x0001C000-0x00020000) + * - CV32 and PULP: below 0x0001C000 (2KB slots, see sw/kernel/link.ld) * - Spatz uses: 0x0001C000-0x00020000 (16KB) */ @@ -33,9 +33,7 @@ MEMORY prog (rwxa) : ORIGIN = 0x00000000, LENGTH = 0x10000 /* 64KB max - relative addressing */ } -/* Stack configuration - Spatz uses remaining 16KB after CV32 */ -/* CV32 uses: 0x00010000-0x0001C000 (48KB, from CV32 link.ld) */ -/* Spatz uses: 0x0001C000-0x00020000 (16KB) */ +/* Spatz stack: 0x0001C000-0x00020000 (16KB), above the CV32/PULP slots of sw/kernel/link.ld */ _stack_start = 0x0001FFF8; /* Top of Spatz stack (grows downward) */ SECTIONS diff --git a/sw/kernel/crt0.S b/sw/kernel/crt0.S index b903b454..b6658f60 100644 --- a/sw/kernel/crt0.S +++ b/sw/kernel/crt0.S @@ -83,9 +83,7 @@ _start: skip_bss_clear: - /* Stack initialization: top of the CV32 stack band (0x14000), grows down. - * Must use _stack_start (region top), NOT `stack` (region bottom + _min_stack), - * otherwise sp starts near the floor and underflows past 0x10000. */ + /* Stack: top of slot 0 at _stack_start (0x1C000), the PULP harts take the 2 KB slots below */ la x2, _stack_start .section .text diff --git a/sw/kernel/link.ld b/sw/kernel/link.ld index b3090e6e..c528c3dd 100644 --- a/sw/kernel/link.ld +++ b/sw/kernel/link.ld @@ -28,9 +28,9 @@ MEMORY /* Stack information variables. * Spatz owns [0x1C000, 0x20000) in the tile SPM (_stack_start = 0x1FFF8 in * spatz_program.ld); this region stops at 0x1C000 to avoid overlap. - * Each hart gets _stack_slice_size bytes; crt0 computes: - * sp = stack - local_id * _stack_slice_size - * Slot 0 = CV32 main core, slots 1..8 = PULP cluster cores. */ + * Each hart gets _stack_slice_size bytes; slot n starts at + * sp = stack - n * _stack_slice_size + * Slot 0 = CV32 main core (crt0.S), slots 1..8 = PULP harts 0..7 (pulp_crt0.S). */ _stack_slice_size = 0x800; /* 2 KB per hart */ _stack_hart_count = 9; /* 1 main + 8 PULP cores */ _min_stack = _stack_slice_size * _stack_hart_count; /* 18 KB total */ @@ -160,8 +160,7 @@ SECTIONS _bss_end = .; } > dataram :data - /* Stack placed at the TOP of the CV32/PULP region so crt0 can compute - * per-hart SP = stack - local_id * _stack_slice_size. */ + /* Stack placed at the TOP of the CV32/PULP region: stack = _stack_start = 0x1C000 */ .stack ORIGIN(stack) + LENGTH(stack) - _min_stack (NOLOAD): { . = ALIGN(4); _stack_bottom = .; diff --git a/sw/kernel_pulp/Makefile b/sw/kernel_pulp/Makefile index 7a0c0634..bb8005c2 100644 --- a/sw/kernel_pulp/Makefile +++ b/sw/kernel_pulp/Makefile @@ -1,8 +1,8 @@ # Copyright (C) 2026 ETH Zurich, University of Bologna and Fondazione Chips-IT # -# Licensed under the Solderpad Hardware License, Version 0.51 -# (the "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -# SPDX-License-Identifier: SHL-0.51 +# SPDX-License-Identifier: Apache-2.0 # # PULP cluster task Makefile for MAGIA. # @@ -107,7 +107,7 @@ HEADER = $(HEADER_DIR)/$(HEADER_NAME).h BIN2HEADER = ../../scripts/bin2header.py -.PHONY: all clean dirs bin header +.PHONY: all clean clean-test dirs bin header all: bin @rm -f $(HEADER) @@ -131,9 +131,10 @@ $(ELF): $(CRT0_OBJ) $(TASK_SRCS) $(KERNEL_DIR)/pulp_program.ld $(KERNEL_DIR)/Mak @echo "[PULP] Building ELF (tasks: $(task))" $(CC) $(CFLAGS) $(LDFLAGS) $(TASK_UNDEF_FLAGS) -o $@ $(CRT0_OBJ) $(TASK_SRCS) +# .bss goes in the blob, or crt0 zeroes whatever the CV32 links right after it $(BIN): $(ELF) @echo "[PULP] Generating flat binary..." - $(OBJCOPY) -O binary $< $@ + $(OBJCOPY) -O binary --set-section-flags .bss=alloc,load,contents $< $@ $(DUMP): $(ELF) @echo "[PULP] Generating disassembly..." @@ -167,4 +168,8 @@ $(HEADER): $(BIN) $(ELF) clean: rm -rf $(BIN_DIR) $(HEADER_DIR) +# Clean only the current test artifacts, so other tests can build in parallel +clean-test: + rm -f $(ELF) $(BIN) $(DUMP) $(CRT0_OBJ) $(HEADER) + .PRECIOUS: $(ELF) $(BIN) diff --git a/sw/kernel_pulp/pulp_crt0.S b/sw/kernel_pulp/pulp_crt0.S index 14dda5a8..b81078b8 100644 --- a/sw/kernel_pulp/pulp_crt0.S +++ b/sw/kernel_pulp/pulp_crt0.S @@ -50,7 +50,7 @@ * PULP STACK_TOP = 0x1B800 * PULP core 0: [0x1B000, 0x1B800) (2 KB) * ... - * PULP core 7: [0x14000, 0x14800) (2 KB) + * PULP core 7: [0x17800, 0x18000) (2 KB) * * NOTE: stack and PULP_* MMIO addresses are loaded with 'li' (not 'la') * because the binary is position-independent (ORIGIN=0x0) and 'la' would diff --git a/sw/kernel_pulp/pulp_program.ld b/sw/kernel_pulp/pulp_program.ld index 984a100b..f66c5b68 100644 --- a/sw/kernel_pulp/pulp_program.ld +++ b/sw/kernel_pulp/pulp_program.ld @@ -26,10 +26,10 @@ * Binary is position-independent (compiled with -fPIC -mcmodel=medany). * ORIGIN=0x0 means all section addresses are relative to load address. * - * Local stack allocation (tile address space, absolute, set by pulp_crt0.S): - * CV32 stack: 0x00010000 – 0x00014000 (16 KB) - * PULP stack: 0x00014000 – 0x0001C000 (32 KB, 8 harts × 2 KB each) - * Spatz stack: 0x0001C000 – 0x00020000 (16 KB) + * Local stack allocation (tile address space, absolute, set by each crt0): + * PULP stack: 0x00017800 – 0x0001B800 (16 KB, 8 harts × 2 KB each, pulp_crt0.S) + * CV32 stack: 0x0001B800 – 0x0001C000 (2 KB, slot 0 of sw/kernel/link.ld) + * Spatz stack: 0x0001C000 – 0x00020000 (16 KB, spatz_crt0.S) */ OUTPUT_ARCH(riscv) diff --git a/sw/tests/amo_test.c b/sw/tests/amo_test.c index de6f16f5..76b81b1a 100644 --- a/sw/tests/amo_test.c +++ b/sw/tests/amo_test.c @@ -24,7 +24,7 @@ #define VERBOSE (0) -#define NUM_ITER (1000) +#define NUM_ITER (10) #define INITIAL_VAL (0) #define AMO_TILES (NUM_HARTS) #define EXPECTED_VAL (INITIAL_VAL + NUM_ITER*AMO_TILES) diff --git a/sw/tests/collective_tests/narrow_sync_column.c b/sw/tests/collective_tests/narrow_sync_column.c index 1294b50d..29d04bd4 100644 --- a/sw/tests/collective_tests/narrow_sync_column.c +++ b/sw/tests/collective_tests/narrow_sync_column.c @@ -14,7 +14,7 @@ * limitations under the License. * SPDX-License-Identifier: Apache-2.0 * - * Authors: Carlotta Chiarini + * Authors: Carlotta Chiarini, Fondazione Chips-IT * * MAGIA Column synchronization test over the narrow channel * using the built-in FlooNoC collectives diff --git a/sw/tests/collective_tests/narrow_sync_mesh.c b/sw/tests/collective_tests/narrow_sync_mesh.c index edd3f63b..9649993b 100644 --- a/sw/tests/collective_tests/narrow_sync_mesh.c +++ b/sw/tests/collective_tests/narrow_sync_mesh.c @@ -14,7 +14,7 @@ * limitations under the License. * SPDX-License-Identifier: Apache-2.0 * - * Authors: Carlotta Chiarini + * Authors: Carlotta Chiarini, Fondazione Chips-IT * * MAGIA Reduction test over the narrow channel */ diff --git a/sw/tests/collective_tests/narrow_sync_row.c b/sw/tests/collective_tests/narrow_sync_row.c index 6fe657e7..8402a940 100644 --- a/sw/tests/collective_tests/narrow_sync_row.c +++ b/sw/tests/collective_tests/narrow_sync_row.c @@ -14,7 +14,7 @@ * limitations under the License. * SPDX-License-Identifier: Apache-2.0 * - * Authors: Carlotta Chiarini + * Authors: Carlotta Chiarini, Fondazione Chips-IT * * MAGIA Reduction test over the narrow channel */ diff --git a/sw/tests/eu_tests/mesh_test_event_unit.c b/sw/tests/eu_tests/mesh_test_event_unit.c index 514e0e99..bc390fc8 100644 --- a/sw/tests/eu_tests/mesh_test_event_unit.c +++ b/sw/tests/eu_tests/mesh_test_event_unit.c @@ -41,11 +41,10 @@ #define Y_BASE (L1_BASE + 0x0001A048) #define Z_BASE (L2_BASE + 0x00042000) // Note: for a large number of tiles (e.g. 64x64 mesh) we might exceed memory range of L2 #define V_BASE (L2_BASE + 0x00046000) // Note: for a large number of tiles (e.g. 64x64 mesh) we might exceed memory range of L2 -#define T_BASE (L2_BASE + 0x0004A000) // Note: for a large number of tiles (e.g. 64x64 mesh) we might exceed memory range of L2 #define MHARTID_OFFSET (0x00010000) -#define M_SIZE (96) +#define M_SIZE (32) // first 32 rows of the 96x64 golden data #define N_SIZE (64) #define K_SIZE (64) @@ -69,11 +68,8 @@ void idma_mv_in_pure_eu(unsigned int x_dim, unsigned int y_dim, uint16_t src_dat eu_initialized = 1; } - for (int i = 0; i < x_dim*y_dim; i++) - mmio16(T_BASE + get_hartid()*MHARTID_OFFSET + 2*i) = src_data[i]; - dst_addr = (uint32_t)dst_address; - src_addr = (uint32_t)(T_BASE + get_hartid()*MHARTID_OFFSET); + src_addr = (uint32_t)src_data; len = (uint32_t)(x_dim*y_dim*2); // 2 Bytes per element #if VERBOSE > 10 printf("dst_addr: 0x%0x\n", dst_addr); @@ -204,9 +200,6 @@ int main(void) { // Wait for HWPE completion eu_redmule_wait_completion(wait_mode); - printf("Moving results through iDMA...\n"); - idma_mv_out_pure_eu(M_SIZE, K_SIZE, Y_BASE + get_hartid()*L1_TILE_OFFSET, V_BASE + get_hartid()*MHARTID_OFFSET); - printf("Verifying results...\n"); unsigned int num_errors[NUM_HARTS]; @@ -214,14 +207,18 @@ int main(void) { volatile uint16_t computed[NUM_HARTS], expected[NUM_HARTS], diff[NUM_HARTS]; for(int i = 0; i < M_SIZE*K_SIZE; i++){ - computed[get_hartid()] = mmio16(V_BASE + get_hartid()*MHARTID_OFFSET + 2*i); + computed[get_hartid()] = mmio16(Y_BASE + get_hartid()*L1_TILE_OFFSET + 2*i); expected[get_hartid()] = z_oup[i]; diff[get_hartid()] = (computed[get_hartid()] > expected[get_hartid()]) ? (computed[get_hartid()] - expected[get_hartid()]) : (expected[get_hartid()] - computed[get_hartid()]); if(diff[get_hartid()] > DIFF_TH){ num_errors[get_hartid()]++; - printf("**ERROR**: V[0x%0x](=0x%0x) != Z[%0d](=0x%0x)\n", V_BASE + get_hartid()*MHARTID_OFFSET + 2*i, computed[get_hartid()], i, expected[get_hartid()]); + printf("**ERROR**: Y[0x%0x](=0x%0x) != Z[%0d](=0x%0x)\n", Y_BASE + get_hartid()*L1_TILE_OFFSET + 2*i, computed[get_hartid()], i, expected[get_hartid()]); } } + + printf("Moving results through iDMA...\n"); + idma_mv_out_pure_eu(M_SIZE, K_SIZE, Y_BASE + get_hartid()*L1_TILE_OFFSET, V_BASE + get_hartid()*MHARTID_OFFSET); + printf("Finished test with %0d error(s)\n", num_errors[get_hartid()]); return num_errors[get_hartid()]; diff --git a/sw/tests/fpu_test.c b/sw/tests/fpu_test.c index 1d0e3829..5f89ec7a 100644 --- a/sw/tests/fpu_test.c +++ b/sw/tests/fpu_test.c @@ -15,7 +15,7 @@ * SPDX-License-Identifier: Apache-2.0 * * Authors: Victor Isachi - * Luca Balboni + * Luca Balboni, Fondazione Chips-IT * * MAGIA Tile FPU Test * diff --git a/sw/tests/hetero_mesh_test/main.c b/sw/tests/hetero_mesh_test/main.c new file mode 100644 index 00000000..a51e9985 --- /dev/null +++ b/sw/tests/hetero_mesh_test/main.c @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2026 Fondazione Chips-IT + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + * + * Authors: Luca Balboni, Fondazione Chips-IT + * + * Test for the heterogeneous mesh + */ + + +#include +#include "magia_tile_utils.h" +#include "magia_utils.h" +#include "cluster_utils.h" +#include "redmule_mm_utils.h" +#include "idma_mm_utils.h" +#include "event_unit_utils.h" +#include "magia_spatz_utils.h" + +#include "hetero_mesh_test_pulp_task_bin.h" +#include "hetero_mesh_test_task_bin.h" + +#include "x_input.h" +#include "w_input.h" +#include "y_input.h" +#include "z_output.h" + +/* L1_BASE is tile 0's L1 in the global map, add our own slice */ +static inline uint32_t l1(uint32_t off) { + return L1_BASE + get_hartid() * L1_TILE_OFFSET + off; +} + +#define SP_VLEN 16 +#define SP_X l1(0x00000000) +#define SP_Y l1(0x00001000) +#define SP_Z l1(0x00002000) +#define SP_PARAMS l1(0x00003000) + +#define RM_X l1(0x00012048) +#define RM_W l1(0x00016048) +#define RM_Y l1(0x0001A048) /* Z overwrites Y */ +#define RM_M_SIZE (1) +#define RM_N_SIZE (64) +#define RM_K_SIZE (64) +#define RM_DIFF_TH (0x0011) + +/* one uint32 per core, one block per tile: see pulp_task/ */ +#define CL_RESULT_BASE (L2_BASE + 0x00080000) +#define CL_RESULT_STRIDE (0x00000100) +#define CL_CHUNK 8u +#define CL_GOLDEN(c) ((CL_CHUNK) * (c) + ((CL_CHUNK) * ((CL_CHUNK) - 1u)) / 2u) + +#define FP16_ONE (0x3C00u) +#define FP16_TWO (0x4000u) +#define FP16_THREE (0x4200u) + +typedef struct { + uint32_t x_addr; + uint32_t y_addr; + uint32_t z_addr; + uint32_t n_size; +} vecsum_params_t; + +static void idma_load(uint32_t l2_src, uint32_t l1_dst, uint32_t size) { + eu_clear_events(0xFFFFFFFF); + eu_enable_events(EU_IDMA_A2O_DONE_MASK); + (void)idma_L2ToL1(l2_src, l1_dst, (unsigned short)size); + do { + eu_idma_wait_a2o_completion(EU_WAIT_MODE_WFE); + } while (idma_mm_is_busy_dir(0, 0)); +} + +/* 1x64x64 FP16 GEMM on iDMA-loaded data */ +static unsigned int run_redmule(void) { + unsigned int errors = 0; + + idma_load((uint32_t)x_inp, RM_X, RM_M_SIZE * RM_N_SIZE * 2); + idma_load((uint32_t)w_inp, RM_W, RM_N_SIZE * RM_K_SIZE * 2); + idma_load((uint32_t)y_inp, RM_Y, RM_M_SIZE * RM_K_SIZE * 2); + + hwpe_cg_enable(); + hwpe_soft_clear(); + while (hwpe_acquire_job() < 0) + ; + + redmule_cfg(RM_X, RM_W, RM_Y, RM_M_SIZE, RM_N_SIZE, RM_K_SIZE, + (uint8_t)gemm_ops, (uint8_t)Float16, (uint8_t)Float16); + + eu_redmule_init(); + hwpe_trigger_job(); + eu_redmule_wait_completion(EU_WAIT_MODE_WFE); + hwpe_cg_disable(); + + for (int i = 0; i < RM_M_SIZE * RM_K_SIZE; i++) { + uint16_t got = mmio16(RM_Y + 2 * i); + uint16_t exp = z_oup[i]; + uint16_t diff = (got > exp) ? (got - exp) : (exp - got); + if (diff > RM_DIFF_TH) errors++; + } + return errors; +} + +/* Z = X + Y, 16 FP16 elements */ +static unsigned int run_spatz(void) { + volatile uint16_t *x = (volatile uint16_t *)SP_X; + volatile uint16_t *y = (volatile uint16_t *)SP_Y; + volatile uint16_t *z = (volatile uint16_t *)SP_Z; + unsigned int errors = 0; + + for (int i = 0; i < SP_VLEN; i++) { + x[i] = FP16_ONE; + y[i] = FP16_TWO; + z[i] = 0; + } + + volatile vecsum_params_t *params = (volatile vecsum_params_t *)SP_PARAMS; + params->x_addr = SP_X; + params->y_addr = SP_Y; + params->z_addr = SP_Z; + params->n_size = SP_VLEN; + + eu_init(); + eu_enable_events(EU_SPATZ_DONE_MASK); + spatz_init(SPATZ_BINARY_START); + spatz_run_task_with_params(VECSUM16_TASK, SP_PARAMS); + eu_wait_spatz_wfe(EU_SPATZ_DONE_MASK); + + if (spatz_get_exit_code() != 0) errors++; + for (int i = 0; i < SP_VLEN; i++) { + if (z[i] != FP16_THREE) { + errors++; + break; + } + } + + spatz_clk_dis(); + return errors; +} + +/* every PULP core sums its own slice into L2 */ +static unsigned int run_cluster(void) { + unsigned int errors = 0; + + eu_init(); + cluster_boot(PULP_BINARY_START); + eu_cluster_done_init(); + cluster_dispatch_task(HETERO_CLUSTER_TASK, (1u << PULP_CORE_COUNT) - 1u); + eu_cluster_done_wait(EU_WAIT_MODE_WFE); + + uint32_t base = CL_RESULT_BASE + get_hartid() * CL_RESULT_STRIDE; + for (uint32_t c = 0; c < PULP_CORE_COUNT; c++) { + if (mmio32(base + 4 * c) != CL_GOLDEN(c)) errors++; + } + return errors; +} + +int main(void) { + uint32_t tile = get_hartid(); + unsigned int errors = 0; + + switch (tile / 4) { + case 0: + errors += run_redmule(); + errors += run_spatz(); + errors += run_cluster(); + break; + case 1: + errors += run_redmule(); + break; + case 2: + errors += run_spatz(); + break; + default: + errors += run_cluster(); + break; + } + + printf("[Tile %u] %s (%u)\n", (unsigned)tile, errors ? "FAIL" : "OK", errors); + return (int)errors; +} diff --git a/sw/tests/hetero_mesh_test/pulp_task/hetero_cluster_task.c b/sw/tests/hetero_mesh_test/pulp_task/hetero_cluster_task.c new file mode 100644 index 00000000..8f9c2bec --- /dev/null +++ b/sw/tests/hetero_mesh_test/pulp_task/hetero_cluster_task.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2026 Fondazione Chips-IT + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + * + * Authors: Luca Balboni, Fondazione Chips-IT + * + * hetero_mesh_test - PULP cluster-core task. + */ + +#include +#include "magia_tile_utils.h" +#include "cluster_utils.h" + +#define CHUNK 8u +#define RESULT_BASE (L2_BASE + 0x00080000) +#define RESULT_STRIDE (0x00000100) + +void hetero_cluster_task(void *data) { + (void)data; + + uint32_t tile_id = cluster_tile_id(); + uint32_t local_id = cluster_core_id(); + + /* Expected = CHUNK*local_id + (0+1+...+CHUNK-1). */ + uint32_t acc = 0; + for (uint32_t i = 0; i < CHUNK; i++) + acc += local_id + i; + + mmio32(RESULT_BASE + tile_id * RESULT_STRIDE + 4 * local_id) = acc; +} diff --git a/sw/tests/mesh_tests.yml b/sw/tests/mesh_tests.yml deleted file mode 100644 index 272c3803..00000000 --- a/sw/tests/mesh_tests.yml +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright (C) 2026 ETH Zurich, University of Bologna and Fondazione Chips-IT -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Author: Alessandro Nadalini - -mesh-generic-tests: - inter_l1_test: - path: . - command: make clean all run mesh_dv=1 fast_sim=1 test=inter_l1_test -redmule-tests: - mm_tests/mesh_test_mm: - path: . - command: make clean all run mesh_dv=1 fast_sim=1 test=mm_tests/mesh_test_mm - eu_tests/mesh_test_event_unit: - path: . - command: make clean all run mesh_dv=1 fast_sim=1 test=eu_tests/mesh_test_event_unit - mm_tests/fsync_extended_test_mm: - path: . - command: make clean all run mesh_dv=1 fast_sim=1 test=mm_tests/fsync_extended_test_mm - eu_tests/fsync_extended_test_event_unit: - path: . - command: make clean all run mesh_dv=1 fast_sim=1 test=eu_tests/fsync_extended_test_event_unit -spatz-tests: - hello_mesh_spatz_test: - path: . - command: make clean all run mesh_dv=1 fast_sim=1 test=hello_mesh_spatz_test - atomic_mesh_spatz_test: - path: . - command: make clean all run mesh_dv=1 fast_sim=1 test=atomic_mesh_spatz_test - dotp_mesh_spatz_test: - path: . - command: make clean all run mesh_dv=1 fast_sim=1 test=dotp_mesh_spatz_test \ No newline at end of file diff --git a/sw/tests/mm_tests/fsync_test_mm.c b/sw/tests/mm_tests/fsync_test_mm.c index aae62a7b..a473f1e8 100644 --- a/sw/tests/mm_tests/fsync_test_mm.c +++ b/sw/tests/mm_tests/fsync_test_mm.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023-2024 ETH Zurich and Unive printf("Starting Fractal Sync test...\n");sity of Bologna + * Copyright (C) 2023-2024 ETH Zurich and University of Bologna * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sw/tests/mm_tests/mesh_test_mm.c b/sw/tests/mm_tests/mesh_test_mm.c index 484765de..47d896ea 100644 --- a/sw/tests/mm_tests/mesh_test_mm.c +++ b/sw/tests/mm_tests/mesh_test_mm.c @@ -35,11 +35,10 @@ #define Y_BASE (L1_BASE + 0x0001A048) #define Z_BASE (L2_BASE + 0x00042000) // Note: for a large number of tiles (e.g. 64x64 mesh) we might exceed memory range of L2 #define V_BASE (L2_BASE + 0x00046000) // Note: for a large number of tiles (e.g. 64x64 mesh) we might exceed memory range of L2 -#define T_BASE (L2_BASE + 0x0004A000) // Note: for a large number of tiles (e.g. 64x64 mesh) we might exceed memory range of L2 #define MHARTID_OFFSET (0x00010000) -#define M_SIZE (96) +#define M_SIZE (32) // first 32 rows of the 96x64 golden data #define N_SIZE (64) #define K_SIZE (64) @@ -56,11 +55,8 @@ void idma_mv_in(unsigned int x_dim, unsigned int y_dim, uint16_t src_data[], uin uint32_t src_addr; uint32_t len; - for (int i = 0; i < x_dim*y_dim; i++) - mmio16(T_BASE + get_hartid()*MHARTID_OFFSET + 2*i) = src_data[i]; - dst_addr = (uint32_t)dst_address; - src_addr = (uint32_t)(T_BASE + get_hartid()*MHARTID_OFFSET); + src_addr = (uint32_t)src_data; len = (uint32_t)(x_dim*y_dim*2); // 2 Bytes per element #if VERBOSE > 10 printf("dst_addr: 0x%0x\n", dst_addr); @@ -167,9 +163,6 @@ int main(void) { // Wait for HWPE completion hwpe_wait_for_completion(); - printf("Moving results through iDMA...\n"); - idma_mv_out(M_SIZE, K_SIZE, Y_BASE + get_hartid()*L1_TILE_OFFSET, V_BASE + get_hartid()*MHARTID_OFFSET); - printf("Verifying results...\n"); unsigned int num_errors[NUM_HARTS]; @@ -177,14 +170,18 @@ int main(void) { uint16_t computed[NUM_HARTS], expected[NUM_HARTS], diff[NUM_HARTS]; for(int i = 0; i < M_SIZE*K_SIZE; i++){ - computed[get_hartid()] = mmio16(V_BASE + get_hartid()*MHARTID_OFFSET + 2*i); + computed[get_hartid()] = mmio16(Y_BASE + get_hartid()*L1_TILE_OFFSET + 2*i); expected[get_hartid()] = z_oup[i]; diff[get_hartid()] = (computed[get_hartid()] > expected[get_hartid()]) ? (computed[get_hartid()] - expected[get_hartid()]) : (expected[get_hartid()] - computed[get_hartid()]); if(diff[get_hartid()] > DIFF_TH){ num_errors[get_hartid()]++; - printf("**ERROR**: V[0x%0x](=0x%0x) != Z[%0d](=0x%0x)\n", V_BASE + get_hartid()*MHARTID_OFFSET + 2*i, computed[get_hartid()], i, expected[get_hartid()]); + printf("**ERROR**: Y[0x%0x](=0x%0x) != Z[%0d](=0x%0x)\n", Y_BASE + get_hartid()*L1_TILE_OFFSET + 2*i, computed[get_hartid()], i, expected[get_hartid()]); } } + + printf("Moving results through iDMA...\n"); + idma_mv_out(M_SIZE, K_SIZE, Y_BASE + get_hartid()*L1_TILE_OFFSET, V_BASE + get_hartid()*MHARTID_OFFSET); + printf("Finished test with %0d error(s)\n", num_errors[get_hartid()]); return num_errors[get_hartid()]; diff --git a/sw/tests/tests.yml b/sw/tests/tests.yml new file mode 100644 index 00000000..64094a8c --- /dev/null +++ b/sw/tests/tests.yml @@ -0,0 +1,346 @@ +# Copyright (C) 2026 ETH Zurich, University of Bologna and Fondazione Chips-IT +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# SPDX-License-Identifier: Apache-2.0 +# +# Authors: Alessandro Nadalini +# Luca Balboni, Fondazione Chips-IT +# +# MAGIA test list, read by scripts/run_regression.py. +# +# Top-level keys are the folders of sw/tests/ (`general` is sw/tests/ itself); each test is named +# as `make test=` expects it. Fields: +# testbench mesh or tile +# cores control cores the test runs on +# sims simulators the test runs on: questa, verilator +# requires defines the build must have (MAGIA_FSYNC: FractalSync on) +# fast_sim false builds the HW without the fast optimization (default true) +# timeout seconds, overrides the default of the testbench + +# Tests in sw/tests/ itself +general: + inter_l1_test: + testbench: mesh + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + hello_mesh: + testbench: mesh + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + hetero_mesh_test: + testbench: mesh + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + # Atomics are enabled only by the CV32E40X toolchain + amo_test: + testbench: mesh + cores: [CV32E40X] + sims: [questa, verilator] + requires: [] + fast_sim: false + hello_world: + testbench: tile + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + fpu_test: + testbench: tile + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + boot_test: + testbench: tile + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + l1_test: + testbench: tile + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + +# RedMulE, iDMA and FractalSync through memory-mapped registers +mm_tests: + mm_tests/mesh_test_mm: + testbench: mesh + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + timeout: 10800 + mm_tests/fsync_test_mm: + testbench: mesh + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [MAGIA_FSYNC] + mm_tests/fsync_extended_test_mm: + testbench: mesh + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [MAGIA_FSYNC] + mm_tests/tile_test_mm: + testbench: tile + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + mm_tests/redmule_test_mm: + testbench: tile + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + mm_tests/idma_test_mm: + testbench: tile + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + +# The same units through the Event Unit +eu_tests: + eu_tests/mesh_test_event_unit: + testbench: mesh + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + timeout: 10800 + eu_tests/fsync_test_event_unit: + testbench: mesh + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [MAGIA_FSYNC] + eu_tests/fsync_extended_test_event_unit: + testbench: mesh + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [MAGIA_FSYNC] + eu_tests/tile_test_event_unit: + testbench: tile + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + eu_tests/redmule_test_event_unit: + testbench: tile + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + eu_tests/event_unit_test: + testbench: tile + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + eu_tests/idma_test_event_unit: + testbench: tile + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + +# NoC collectives: broadcast, multicast, reduce and sync +collective_tests: + narrow_broadcast: + testbench: mesh + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + narrow_multicast_row: + testbench: mesh + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + narrow_multicast_column: + testbench: mesh + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + narrow_sync_row: + testbench: mesh + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + narrow_sync_column: + testbench: mesh + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + narrow_sync_mesh: + testbench: mesh + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + wide_broadcast: + testbench: mesh + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + wide_multicast_row: + testbench: mesh + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + wide_multicast_column: + testbench: mesh + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + narrow_reduce_row: + testbench: mesh + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + fast_sim: false + narrow_reduce_column: + testbench: mesh + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + fast_sim: false + narrow_reduce_mesh: + testbench: mesh + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + fast_sim: false + +# Software barriers on atomics, only by the CV32E40X +nsync: + nsync/nsync_single_test: + testbench: mesh + cores: [CV32E40X] + sims: [questa, verilator] + requires: [] + nsync/nsync_naive_test: + testbench: mesh + cores: [CV32E40X] + sims: [questa, verilator] + requires: [] + nsync/nsync_hneighbor_test: + testbench: mesh + cores: [CV32E40X] + sims: [questa, verilator] + requires: [] + nsync/nsync_vneighbor_test: + testbench: mesh + cores: [CV32E40X] + sims: [questa, verilator] + requires: [] + nsync/nsync_hring_test: + testbench: mesh + cores: [CV32E40X] + sims: [questa, verilator] + requires: [] + nsync/nsync_vring_test: + testbench: mesh + cores: [CV32E40X] + sims: [questa, verilator] + requires: [] + nsync/nsync_row_test: + testbench: mesh + cores: [CV32E40X] + sims: [questa, verilator] + requires: [] + nsync/nsync_col_test: + testbench: mesh + cores: [CV32E40X] + sims: [questa, verilator] + requires: [] + nsync/nsync_xy_test: + testbench: mesh + cores: [CV32E40X] + sims: [questa, verilator] + requires: [] + nsync/nsync_hyper_test: + testbench: mesh + cores: [CV32E40X] + sims: [questa, verilator] + requires: [] + nsync/nsync_row_hyper_test: + testbench: mesh + cores: [CV32E40X] + sims: [questa, verilator] + requires: [] + nsync/nsync_col_hyper_test: + testbench: mesh + cores: [CV32E40X] + sims: [questa, verilator] + requires: [] + +# Spatz vector core +spatz_tests: + hello_mesh_spatz_test: + testbench: mesh + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + atomic_mesh_spatz_test: + testbench: mesh + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + dotp_mesh_spatz_test: + testbench: mesh + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + simple_spatz_test: + testbench: tile + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + dotp_spatz_test: + testbench: tile + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + gemm_spatz_test: + testbench: tile + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + gemv_spatz_test: + testbench: tile + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + matmul_compare_spatz_test: + testbench: tile + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + vecsum_spatz_test: + testbench: tile + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + +# PULP cluster +cluster_tests: + hello_pulp: + testbench: tile + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + fpu_cluster_test: + testbench: tile + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + hello_redmule_pulp: + testbench: tile + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] + hello_spatz_pulp: + testbench: tile + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] diff --git a/sw/tests/tile_tests.yml b/sw/tests/tile_tests.yml deleted file mode 100644 index 965983a8..00000000 --- a/sw/tests/tile_tests.yml +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright (C) 2026 ETH Zurich, University of Bologna and Fondazione Chips-IT -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Author: Alessandro Nadalini - -tile-generic-tests: - hello_world: - path: . - command: make clean all run mesh_dv=0 fast_sim=1 test=hello_world - fpu_test: - path: . - command: make clean all run mesh_dv=0 fast_sim=1 test=fpu_test -redmule-tests: - mm_tests/tile_test_mm: - path: . - command: make clean all run mesh_dv=0 fast_sim=1 test=mm_tests/tile_test_mm - eu_tests/tile_test_event_unit: - path: . - command: make clean all run mesh_dv=0 fast_sim=1 test=eu_tests/tile_test_event_unit -spatz-tests: - simple_spatz_test: - path: . - command: make clean all run mesh_dv=0 fast_sim=1 test=simple_spatz_test - dotp_spatz_test: - path: . - command: make clean all run mesh_dv=0 fast_sim=1 test=dotp_spatz_test - gemm_spatz_test: - path: . - command: make clean all run mesh_dv=0 fast_sim=1 test=gemm_spatz_test - matmul_compare_spatz_test: - path: . - command: make clean all run mesh_dv=0 fast_sim=1 test=matmul_compare_spatz_test - vecsum_spatz_test: - path: . - command: make clean all run mesh_dv=0 fast_sim=1 test=vecsum_spatz_test -pulp_cluster_tests: - hello_pulp: - path: . - command: make clean all run mesh_dv=0 fast_sim=1 test=hello_pulp - fpu_cluster_test: - path: . - command: make clean all run mesh_dv=0 fast_sim=1 test=fpu_cluster_test - - \ No newline at end of file diff --git a/sw/utils/cache_fill.h b/sw/utils/cache_fill.h index 3a777eeb..d954c304 100644 --- a/sw/utils/cache_fill.h +++ b/sw/utils/cache_fill.h @@ -5,6 +5,7 @@ // Authors: Victor Isachi // +// 4096 nops = 16 KiB, the control-core I$ (128-bit lines x 32 lines x 32 ways) void fill_icache(){ asm volatile("nop" ::); asm volatile("nop" ::); @@ -4102,4100 +4103,4 @@ void fill_icache(){ asm volatile("nop" ::); asm volatile("nop" ::); asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); - asm volatile("nop" ::); } \ No newline at end of file diff --git a/sw/utils/event_unit_utils.h b/sw/utils/event_unit_utils.h index 5e746ba3..f09e7b5e 100644 --- a/sw/utils/event_unit_utils.h +++ b/sw/utils/event_unit_utils.h @@ -76,14 +76,11 @@ #define EU_TIMER_EVT_1_BIT 5 #define EU_REDMULE_UNUSED_BIT 8 -#define EU_REDMULE_BUSY_BIT 9 #define EU_REDMULE_DONE_BIT 10 #define EU_REDMULE_EVT1_BIT 11 // RedMulE event masks #define EU_REDMULE_DONE_MASK (1 << EU_REDMULE_DONE_BIT) -#define EU_REDMULE_BUSY_MASK (1 << EU_REDMULE_BUSY_BIT) -#define EU_REDMULE_ALL_MASK 0x0F00 // iDMA events (DMA events [3:2] + extended [31:26]) #define EU_IDMA_A2O_DONE_BIT 2 @@ -91,25 +88,14 @@ #define EU_IDMA_A2O_DONE_MASK (1 << EU_IDMA_A2O_DONE_BIT) #define EU_IDMA_O2A_DONE_MASK (1 << EU_IDMA_O2A_DONE_BIT) #define EU_IDMA_ALL_DONE_MASK (EU_IDMA_A2O_DONE_MASK | EU_IDMA_O2A_DONE_MASK) -#define EU_IDMA_A2O_ERROR_BIT 26 -#define EU_IDMA_O2A_ERROR_BIT 27 #define EU_IDMA_A2O_START_BIT 28 #define EU_IDMA_O2A_START_BIT 29 -#define EU_IDMA_A2O_BUSY_BIT 30 -#define EU_IDMA_O2A_BUSY_BIT 31 -#define EU_IDMA_A2O_ERROR_MASK (1 << EU_IDMA_A2O_ERROR_BIT) -#define EU_IDMA_O2A_ERROR_MASK (1 << EU_IDMA_O2A_ERROR_BIT) #define EU_IDMA_A2O_START_MASK (1 << EU_IDMA_A2O_START_BIT) #define EU_IDMA_O2A_START_MASK (1 << EU_IDMA_O2A_START_BIT) -#define EU_IDMA_A2O_BUSY_MASK (1 << EU_IDMA_A2O_BUSY_BIT) -#define EU_IDMA_O2A_BUSY_MASK (1 << EU_IDMA_O2A_BUSY_BIT) // FSync events (cluster events [25:24]) #define EU_FSYNC_DONE_BIT 24 -#define EU_FSYNC_ERROR_BIT 25 #define EU_FSYNC_DONE_MASK (1 << EU_FSYNC_DONE_BIT) -#define EU_FSYNC_ERROR_MASK (1 << EU_FSYNC_ERROR_BIT) -#define EU_FSYNC_ALL_MASK (EU_FSYNC_DONE_MASK | EU_FSYNC_ERROR_MASK) // Spatz events (accelerator events [8] + cluster events [23]) #define EU_SPATZ_DONE_BIT 8 @@ -290,10 +276,6 @@ static inline uint32_t eu_redmule_wait_completion(eu_wait_mode_t mode) { return eu_wait_events(EU_REDMULE_DONE_MASK, mode, 1000000); } -static inline uint32_t eu_redmule_is_busy(void) { - return eu_check_events(EU_REDMULE_BUSY_MASK); -} - static inline uint32_t eu_redmule_is_done(void) { return eu_check_events(EU_REDMULE_DONE_MASK); } @@ -336,23 +318,13 @@ static inline uint32_t eu_idma_o2a_is_done(void) { return eu_check_events(EU_IDMA_O2A_DONE_MASK); } -static inline uint32_t eu_idma_is_busy(void) { - uint32_t events = eu_get_events(); - return events & (EU_IDMA_A2O_BUSY_MASK | EU_IDMA_O2A_BUSY_MASK); -} - -static inline uint32_t eu_idma_has_error(void) { - uint32_t events = eu_get_events(); - return events & (EU_IDMA_A2O_ERROR_MASK | EU_IDMA_O2A_ERROR_MASK); -} - //============================================================================= // FSYNC FUNCTIONS //============================================================================= static inline void eu_fsync_init(void) { eu_clear_events(0xFFFFFFFF); - eu_enable_events(EU_FSYNC_ALL_MASK); + eu_enable_events(EU_FSYNC_DONE_MASK); } static inline uint32_t eu_fsync_wait_completion(eu_wait_mode_t mode) { @@ -363,10 +335,6 @@ static inline uint32_t eu_fsync_is_done(void) { return eu_check_events(EU_FSYNC_DONE_MASK); } -static inline uint32_t eu_fsync_has_error(void) { - return eu_check_events(EU_FSYNC_ERROR_MASK); -} - //============================================================================= // SPATZ FUNCTIONS //============================================================================= @@ -405,7 +373,7 @@ static inline void eu_multi_init(uint32_t redmule_en, uint32_t idma_a2o_en, uint32_t event_mask = 0; if (redmule_en) { - event_mask |= EU_REDMULE_ALL_MASK; + event_mask |= EU_REDMULE_DONE_MASK; } if (idma_a2o_en) { event_mask |= EU_IDMA_A2O_DONE_MASK; @@ -414,7 +382,7 @@ static inline void eu_multi_init(uint32_t redmule_en, uint32_t idma_a2o_en, event_mask |= EU_IDMA_O2A_DONE_MASK; } if (fsync_en) { - event_mask |= EU_FSYNC_ALL_MASK; + event_mask |= EU_FSYNC_DONE_MASK; } if (event_mask) eu_enable_events(event_mask); diff --git a/sw/utils/magia_coll_utils.h b/sw/utils/magia_coll_utils.h index 14443df7..3a2769ec 100644 --- a/sw/utils/magia_coll_utils.h +++ b/sw/utils/magia_coll_utils.h @@ -14,7 +14,7 @@ * limitations under the License. * SPDX-License-Identifier: Apache-2.0 * - * Authors: Carlotta Chiarini + * Authors: Carlotta Chiarini, Fondazione Chips-IT * * Collective Utility Functions */ diff --git a/sw/utils/magia_tile_utils.h b/sw/utils/magia_tile_utils.h index 54b07c99..63040896 100644 --- a/sw/utils/magia_tile_utils.h +++ b/sw/utils/magia_tile_utils.h @@ -93,17 +93,11 @@ // Use Event Unit API (event_unit_utils.h) for event handling #define IRQ_REDMULE_EVT_0 (31) #define IRQ_REDMULE_EVT_1 (30) -#define IRQ_A2O_ERROR (29) -#define IRQ_O2A_ERROR (28) #define IRQ_A2O_DONE (27) #define IRQ_O2A_DONE (26) #define IRQ_A2O_START (25) #define IRQ_O2A_START (24) -#define IRQ_A2O_BUSY (23) -#define IRQ_O2A_BUSY (22) -#define IRQ_REDMULE_BUSY (21) #define IRQ_FSYNC_DONE (20) -#define IRQ_FSYNC_ERROR (19) #define mmio64(x) (*(volatile uint64_t *)(x)) #define mmio32(x) (*(volatile uint32_t *)(x)) diff --git a/sw/utils/magia_utils.h b/sw/utils/magia_utils.h index 50c9d3e4..9e0b2057 100644 --- a/sw/utils/magia_utils.h +++ b/sw/utils/magia_utils.h @@ -24,10 +24,12 @@ #include "magia_tile_utils.h" +// Print buffer in the tile-private reserved region #define STR_OFFSET (0x00000000) #define STR_BASE (RESERVED_START + STR_OFFSET) -#define SYNC_OFFSET (0x0000D800) -#define SYNC_BASE (RESERVED_START + SYNC_OFFSET) +// Sync words in the top 4 KiB of L1, which every tile can reach +#define SYNC_OFFSET (L1_SIZE - 0x00001000) +#define SYNC_BASE (L1_BASE + SYNC_OFFSET) #define SYNC_EN (SYNC_BASE + 0x4) #define MESH_Y_TILES (4) @@ -83,24 +85,15 @@ char* utoa(unsigned int value, unsigned int base, char* result) { } char* bs(uint32_t x) { - uint32_t hartid = get_hartid(); - char *address = (char *)(uintptr_t)(STR_BASE + L1_TILE_OFFSET * hartid); - - return utoa(x, 2, address); + return utoa(x, 2, (char *)(uintptr_t)(STR_BASE)); } char* ds(uint32_t x) { - uint32_t hartid = get_hartid(); - char *address = (char *)(uintptr_t)(STR_BASE + L1_TILE_OFFSET * hartid); - - return utoa(x, 10, address); + return utoa(x, 10, (char *)(uintptr_t)(STR_BASE)); } char* hs(uint32_t x) { - uint32_t hartid = get_hartid(); - char *address = (char *)(uintptr_t)(STR_BASE + L1_TILE_OFFSET * hartid); - - return utoa(x, 16, address); + return utoa(x, 16, (char *)(uintptr_t)(STR_BASE)); } void h_psprint(uint32_t hartid, const char* string){ diff --git a/target/sim/src/mesh/magia_fixture.sv b/target/sim/src/mesh/magia_fixture.sv index d87e3fec..165130a8 100644 --- a/target/sim/src/mesh/magia_fixture.sv +++ b/target/sim/src/mesh/magia_fixture.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -78,12 +78,7 @@ module magia_fixture; magia #( .N_TILES_Y ( magia_tb_pkg::N_TILES_Y ), .N_TILES_X ( magia_tb_pkg::N_TILES_X ), - .N_TILES ( magia_tb_pkg::N_TILES ), - .N_MEM_BANKS ( magia_tb_pkg::N_MEM_BANKS ), - .N_WORDS_BANK ( magia_tb_pkg::N_WORDS_BANK ), - .TILE_FSYNC_AGGR_W ( magia_tb_pkg::TILE_FSYNC_AGGR_W ), - .TILE_FSYNC_LVL_W ( magia_tb_pkg::TILE_FSYNC_LVL_W ), - .TILE_FSYNC_ID_W ( magia_tb_pkg::TILE_FSYNC_ID_W ) + .N_TILES ( magia_tb_pkg::N_TILES ) ) i_magia ( .clk_i ( clk ), .rst_ni ( rst_n ), diff --git a/target/sim/src/mesh/magia_l2_mem_wrapper.sv b/target/sim/src/mesh/magia_l2_mem_wrapper.sv index 04df08f4..6766a15b 100644 --- a/target/sim/src/mesh/magia_l2_mem_wrapper.sv +++ b/target/sim/src/mesh/magia_l2_mem_wrapper.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. diff --git a/target/sim/src/mesh/magia_tb.sv b/target/sim/src/mesh/magia_tb.sv index b2afc64e..adaf42b2 100644 --- a/target/sim/src/mesh/magia_tb.sv +++ b/target/sim/src/mesh/magia_tb.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. diff --git a/target/sim/src/mesh/magia_tb_pkg.sv b/target/sim/src/mesh/magia_tb_pkg.sv index 4de92e45..8ae866fc 100644 --- a/target/sim/src/mesh/magia_tb_pkg.sv +++ b/target/sim/src/mesh/magia_tb_pkg.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. diff --git a/target/sim/src/mesh/magia_vip.sv b/target/sim/src/mesh/magia_vip.sv index 2ccdb262..7ad5b4db 100644 --- a/target/sim/src/mesh/magia_vip.sv +++ b/target/sim/src/mesh/magia_vip.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -127,6 +127,18 @@ module magia_vip rst_n = 1'b1; end + // $assertcontrol arguments (IEEE 1800-2012 20.12): control On/Off, unique|unique0|priority checks + localparam int unsigned ASSERT_ON = 3; + localparam int unsigned ASSERT_OFF = 4; + localparam int unsigned ASSERT_UNIQUE_PRIO = 32 + 64 + 128; + + // Before the reset edge every FSM state is X, so unique/priority checks start once it is applied + initial begin: p_unique_check_gate + $assertcontrol(ASSERT_OFF, ASSERT_UNIQUE_PRIO); + #(RST_ASSERT_TIME + 1); + $assertcontrol(ASSERT_ON, ASSERT_UNIQUE_PRIO); + end + /*******************************************************/ /** Clock and Reset End **/ /*******************************************************/ @@ -232,21 +244,21 @@ module magia_vip string_char_t chars[$]; bit[magia_tb_pkg::L2_ID_W-1:0] write_id; always @(posedge clk) begin: print_monitor - if ((i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_axi_xbar.mst_ports_req_o[0].aw.addr == 32'hFFFF0000) && (i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_axi_xbar.mst_ports_req_o[0].aw_valid)) + if ((i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_magia_isle.i_axi_xbar.mst_ports_req_o[0].aw.addr == 32'hFFFF0000) && (i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_magia_isle.i_axi_xbar.mst_ports_req_o[0].aw_valid)) stderr_ready = 1'b1; // NOTE: all print peripherals are assumed to be aliased - if ((i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_axi_xbar.mst_ports_req_o[0].aw.addr == 32'hFFFF0004/*+((i*magia_tb_pkg::N_TILES_X+j)*4)*/) && (i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_axi_xbar.mst_ports_req_o[0].aw_valid)) begin + if ((i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_magia_isle.i_axi_xbar.mst_ports_req_o[0].aw.addr == 32'hFFFF0004/*+((i*magia_tb_pkg::N_TILES_X+j)*4)*/) && (i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_magia_isle.i_axi_xbar.mst_ports_req_o[0].aw_valid)) begin stdio_ready = 1'b1; - write_id = i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_axi_xbar.mst_ports_req_o[0].aw.id; + write_id = i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_magia_isle.i_axi_xbar.mst_ports_req_o[0].aw.id; end - if ((i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_axi_xbar.mst_ports_req_o[0].w_valid) && stderr_ready) begin - errors = i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_axi_xbar.mst_ports_req_o[0].w.data[7:0]; + if ((i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_magia_isle.i_axi_xbar.mst_ports_req_o[0].w_valid) && stderr_ready) begin + errors = i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_magia_isle.i_axi_xbar.mst_ports_req_o[0].w.data[7:0]; stderr_ready = 1'b0; end - if ((i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_axi_xbar.mst_ports_req_o[0].w_valid) && stdio_ready) begin - if (i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_axi_xbar.mst_ports_req_o[0].w.data[7:0] == 10) // ASCII code for new line (\n) is 10 + if ((i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_magia_isle.i_axi_xbar.mst_ports_req_o[0].w_valid) && stdio_ready) begin + if (i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_magia_isle.i_axi_xbar.mst_ports_req_o[0].w.data[7:0] == 10) // ASCII code for new line (\n) is 10 print_line[write_id] = 1'b1; - chars.push_back('{i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_axi_xbar.mst_ports_req_o[0].w.data[7:0], write_id}); + chars.push_back('{i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_magia_isle.i_axi_xbar.mst_ports_req_o[0].w.data[7:0], write_id}); stdio_ready = 1'b0; end for (int k = 0; k < 2**magia_tb_pkg::L2_ID_W; k++) begin @@ -297,9 +309,9 @@ module magia_vip for (genvar i = 0; i < magia_tb_pkg::N_TILES_Y; i++) begin: gen_tile_instr_monitor_y for (genvar j = 0; j < magia_tb_pkg::N_TILES_X; j++) begin: gen_tile_instr_monitor_x `ifdef CV32E40X - assign curr_instr_ex[i*magia_tb_pkg::N_TILES_X+j] = i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_cv32e40x_ctrl_core.core_i.id_stage_i.id_ex_pipe_o.instr.bus_resp.rdata; + assign curr_instr_ex[i*magia_tb_pkg::N_TILES_X+j] = i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_magia_isle.i_cv32e40x_ctrl_core.core_i.id_stage_i.id_ex_pipe_o.instr.bus_resp.rdata; `else - assign curr_instr_ex[i*magia_tb_pkg::N_TILES_X+j] = i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_cv32e40p_ctrl_core.ex_valid ? i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_cv32e40p_ctrl_core.id_stage_i.instr_rdata_i : '0; + assign curr_instr_ex[i*magia_tb_pkg::N_TILES_X+j] = i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_magia_isle.i_cv32e40p_ctrl_core.ex_valid ? i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_magia_isle.i_cv32e40p_ctrl_core.id_stage_i.instr_rdata_i : '0; `endif always @(curr_instr_ex[i*magia_tb_pkg::N_TILES_X+j]) begin: instr_ex_reporter if (curr_instr_ex[i*magia_tb_pkg::N_TILES_X+j] == 32'h50500013) @@ -317,9 +329,9 @@ module magia_vip end end `ifdef CV32E40X - assign curr_instr_id[i*magia_tb_pkg::N_TILES_X+j] = i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_cv32e40x_ctrl_core.core_i.id_stage_i.if_id_pipe_i.instr.bus_resp.rdata; + assign curr_instr_id[i*magia_tb_pkg::N_TILES_X+j] = i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_magia_isle.i_cv32e40x_ctrl_core.core_i.id_stage_i.if_id_pipe_i.instr.bus_resp.rdata; `else - assign curr_instr_id[i*magia_tb_pkg::N_TILES_X+j] = i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_cv32e40p_ctrl_core.id_stage_i.instr_rdata_i; + assign curr_instr_id[i*magia_tb_pkg::N_TILES_X+j] = i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_magia_isle.i_cv32e40p_ctrl_core.id_stage_i.instr_rdata_i; `endif always @(curr_instr_id[i*magia_tb_pkg::N_TILES_X+j]) begin: instr_id_reporter if (curr_instr_id[i*magia_tb_pkg::N_TILES_X+j] == 32'h40400013) @@ -367,11 +379,11 @@ module magia_vip for (genvar i = 0; i < magia_tb_pkg::N_TILES_Y; i++) begin: gen_tile_instr_monitor_y for (genvar j = 0; j < magia_tb_pkg::N_TILES_X; j++) begin: gen_tile_instr_monitor_x `ifdef CV32E40X - assign curr_instr_wb[i*magia_tb_pkg::N_TILES_X+j] = i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_cv32e40x_ctrl_core.core_i.wb_stage_i.ex_wb_pipe_i.instr_valid ? - i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_cv32e40x_ctrl_core.core_i.wb_stage_i.ex_wb_pipe_i.instr.bus_resp.rdata : '0; + assign curr_instr_wb[i*magia_tb_pkg::N_TILES_X+j] = i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_magia_isle.i_cv32e40x_ctrl_core.core_i.wb_stage_i.ex_wb_pipe_i.instr_valid ? + i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_magia_isle.i_cv32e40x_ctrl_core.core_i.wb_stage_i.ex_wb_pipe_i.instr.bus_resp.rdata : '0; `else - assign curr_instr_wb[i*magia_tb_pkg::N_TILES_X+j] = i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_cv32e40p_ctrl_core.wb_valid ? - i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_cv32e40p_ctrl_core.regfile_wdata : '0; + assign curr_instr_wb[i*magia_tb_pkg::N_TILES_X+j] = i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_magia_isle.i_cv32e40p_ctrl_core.wb_valid ? + i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_magia_isle.i_cv32e40p_ctrl_core.regfile_wdata : '0; `endif always @(curr_instr_wb[i*magia_tb_pkg::N_TILES_X+j]) begin: instr_wb_reporter if (curr_instr_wb[i*magia_tb_pkg::N_TILES_X+j] == 32'h5AA00013) begin @@ -527,11 +539,11 @@ module magia_vip for (genvar i = 0; i < magia_tb_pkg::N_TILES_Y; i++) begin: gen_tile_instr_monitor_y for (genvar j = 0; j < magia_tb_pkg::N_TILES_X; j++) begin: gen_tile_instr_monitor_x `ifdef CV32E40X - assign curr_instr_wb[i*magia_tb_pkg::N_TILES_X+j] = i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_cv32e40x_ctrl_core.core_i.wb_stage_i.ex_wb_pipe_i.instr_valid ? - i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_cv32e40x_ctrl_core.core_i.wb_stage_i.ex_wb_pipe_i.instr.bus_resp.rdata : '0; + assign curr_instr_wb[i*magia_tb_pkg::N_TILES_X+j] = i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_magia_isle.i_cv32e40x_ctrl_core.core_i.wb_stage_i.ex_wb_pipe_i.instr_valid ? + i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_magia_isle.i_cv32e40x_ctrl_core.core_i.wb_stage_i.ex_wb_pipe_i.instr.bus_resp.rdata : '0; `else - assign curr_instr_wb[i*magia_tb_pkg::N_TILES_X+j] = i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_cv32e40p_ctrl_core.wb_valid ? - i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_cv32e40p_ctrl_core.instr_rdata_id : '0; + assign curr_instr_wb[i*magia_tb_pkg::N_TILES_X+j] = i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_magia_isle.i_cv32e40p_ctrl_core.wb_valid ? + i_magia.gen_y_tile[i].gen_x_tile[j].i_magia_tile.i_magia_isle.i_cv32e40p_ctrl_core.instr_rdata_id : '0; `endif always @(curr_instr_wb[i*magia_tb_pkg::N_TILES_X+j]) begin: instr_wb_reporter if (curr_instr_wb[i*magia_tb_pkg::N_TILES_X+j] == 32'h5AA00013) begin diff --git a/target/sim/src/tile/floo_axi_nw_mesh_1x2_pkg.sv b/target/sim/src/tile/floo_axi_nw_mesh_1x2_pkg.sv index 87401281..f73e0ae9 100644 --- a/target/sim/src/tile/floo_axi_nw_mesh_1x2_pkg.sv +++ b/target/sim/src/tile/floo_axi_nw_mesh_1x2_pkg.sv @@ -67,7 +67,9 @@ localparam sam_rule_t[SamNumRules-1:0] Sam = '{ XYAddrOffsetY: 33, IdAddrOffset: 0, NumSamRules: 2, - NumRoutes: 0}; + NumRoutes: 0, + // No collectives in the standalone tile + CollectiveCfg: '0}; typedef logic[31:0] axi_narrow_data_mst_addr_t; diff --git a/target/sim/src/tile/magia_tile_fixture.sv b/target/sim/src/tile/magia_tile_fixture.sv index 2520ea30..ebd91bd1 100644 --- a/target/sim/src/tile/magia_tile_fixture.sv +++ b/target/sim/src/tile/magia_tile_fixture.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -63,10 +63,16 @@ module magia_tile_fixture; floo_rsp_t noc_west_rsp_i; floo_wide_t noc_west_wide_o; - fractal_sync_if ht_fsync_if_o[1](); - fractal_sync_if hn_fsync_if_o[1](); - fractal_sync_if vt_fsync_if_o[1](); - fractal_sync_if vn_fsync_if_o[1](); +`ifdef MAGIA_FSYNC + ht_tile_fsync_req_t ht_fsync_req_o; + ht_tile_fsync_rsp_t ht_fsync_rsp_i; + hn_tile_fsync_req_t hn_fsync_req_o; + hn_tile_fsync_rsp_t hn_fsync_rsp_i; + vt_tile_fsync_req_t vt_fsync_req_o; + vt_tile_fsync_rsp_t vt_fsync_rsp_i; + vn_tile_fsync_req_t vn_fsync_req_o; + vn_tile_fsync_rsp_t vn_fsync_rsp_i; +`endif logic scan_cg_en; @@ -82,7 +88,7 @@ module magia_tile_fixture; logic[magia_pkg::N_IRQ-1:0] irq; - logic[magia_tile_pkg::N_CLUSTER_CORES:0] debug_req; + logic debug_req; // control-core only for the moment logic debug_havereset; logic debug_running; logic debug_halted; @@ -91,7 +97,6 @@ module magia_tile_fixture; logic fetch_enable; logic core_sleep; - logic wu_wfe; /*******************************************************/ /** Internal Signal Definitions End **/ @@ -100,14 +105,7 @@ module magia_tile_fixture; /*******************************************************/ magia_tile #( - .N_MEM_BANKS ( magia_tile_tb_pkg::N_MEM_BANKS ), - .N_WORDS_BANK ( magia_tile_tb_pkg::N_WORDS_BANK ), - - .CORE_ISA ( ), - .CORE_A ( ), - .CORE_B ( ), - .CORE_M ( ), - .ERROR_CAP ( ) + .TileCfg ( magia_tile_pkg::MagiaTileDefaultCfg ) ) i_magia_tile ( .clk_i ( clk ), .rst_ni ( rst_n ), @@ -145,10 +143,16 @@ module magia_tile_fixture; .x_id_i ( 1 ), .y_id_i ( 0 ), - .ht_fsync_if_o ( ht_fsync_if_o[0] ), - .hn_fsync_if_o ( hn_fsync_if_o[0] ), - .vt_fsync_if_o ( vt_fsync_if_o[0] ), - .vn_fsync_if_o ( vn_fsync_if_o[0] ), +`ifdef MAGIA_FSYNC + .ht_fsync_req_o ( ht_fsync_req_o ), + .ht_fsync_rsp_i ( ht_fsync_rsp_i ), + .hn_fsync_req_o ( hn_fsync_req_o ), + .hn_fsync_rsp_i ( hn_fsync_rsp_i ), + .vt_fsync_req_o ( vt_fsync_req_o ), + .vt_fsync_rsp_i ( vt_fsync_rsp_i ), + .vn_fsync_req_o ( vn_fsync_req_o ), + .vn_fsync_rsp_i ( vn_fsync_rsp_i ), +`endif .scan_cg_en_i ( scan_cg_en ), @@ -164,7 +168,7 @@ module magia_tile_fixture; .irq_i ( irq ), - .debug_req_i ( debug_req ), + .debug_req_i ( {{magia_tile_pkg::N_CLUSTER_CORES{1'b0}}, debug_req} ), .debug_havereset_o ( debug_havereset ), .debug_running_o ( debug_running ), .debug_halted_o ( debug_halted ), @@ -175,13 +179,6 @@ module magia_tile_fixture; .core_sleep_o ( core_sleep ), .wu_wfe_i ( wu_wfe ) ); -`ifdef CORE_TRACES -`ifdef CV32E40X - localparam string core_trace_file_name = "log_file_0"; - defparam i_magia_tile.i_cv32e40x_ctrl_core.rvfi_i.tracer_i.LOGFILE_PATH_PLUSARG = core_trace_file_name; -`endif - // Note: cv32e40p tracer generates its own filename: trace_core_{cluster_id}_{core_id}.log -`endif /*******************************************************/ /** DUT End **/ diff --git a/target/sim/src/tile/magia_tile_tb.sv b/target/sim/src/tile/magia_tile_tb.sv index ee259aba..d7922da5 100644 --- a/target/sim/src/tile/magia_tile_tb.sv +++ b/target/sim/src/tile/magia_tile_tb.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. diff --git a/target/sim/src/tile/magia_tile_tb_pkg.sv b/target/sim/src/tile/magia_tile_tb_pkg.sv index ee36af62..865390b3 100644 --- a/target/sim/src/tile/magia_tile_tb_pkg.sv +++ b/target/sim/src/tile/magia_tile_tb_pkg.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. diff --git a/target/sim/src/tile/magia_tile_vip.sv b/target/sim/src/tile/magia_tile_vip.sv index 64944510..93f68cf6 100644 --- a/target/sim/src/tile/magia_tile_vip.sv +++ b/target/sim/src/tile/magia_tile_vip.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -64,10 +64,16 @@ module magia_tile_vip output floo_rsp_t noc_west_rsp_i, input floo_wide_t noc_west_wide_o, - fractal_sync_if.slv_port ht_fsync_if_o[1], - fractal_sync_if.slv_port hn_fsync_if_o[1], - fractal_sync_if.slv_port vt_fsync_if_o[1], - fractal_sync_if.slv_port vn_fsync_if_o[1], +`ifdef MAGIA_FSYNC + input ht_tile_fsync_req_t ht_fsync_req_o, + output ht_tile_fsync_rsp_t ht_fsync_rsp_i, + input hn_tile_fsync_req_t hn_fsync_req_o, + output hn_tile_fsync_rsp_t hn_fsync_rsp_i, + input vt_tile_fsync_req_t vt_fsync_req_o, + output vt_tile_fsync_rsp_t vt_fsync_rsp_i, + input vn_tile_fsync_req_t vn_fsync_req_o, + output vn_tile_fsync_rsp_t vn_fsync_rsp_i, +`endif output logic scan_cg_en, @@ -83,7 +89,7 @@ module magia_tile_vip output logic[magia_pkg::N_IRQ-1:0] irq, - output logic[magia_tile_pkg::N_CLUSTER_CORES:0] debug_req, + output logic debug_req, // control-core only input logic debug_havereset, input logic debug_running, input logic debug_halted, @@ -110,24 +116,13 @@ module magia_tile_vip assign dm_exception_addr = '0; assign mhartid = '0; assign mimpid_patch = '0; - assign debug_req = '0; - assign wu_wfe = 1'b0; - assign ht_fsync_if_o[0].wake = 1'b0; - assign ht_fsync_if_o[0].lvl = '0; - assign ht_fsync_if_o[0].id_rsp = '0; - assign ht_fsync_if_o[0].error = 1'b0; - assign hn_fsync_if_o[0].wake = 1'b0; - assign hn_fsync_if_o[0].lvl = '0; - assign hn_fsync_if_o[0].id_rsp = '0; - assign hn_fsync_if_o[0].error = 1'b0; - assign vt_fsync_if_o[0].wake = 1'b0; - assign vt_fsync_if_o[0].lvl = '0; - assign vt_fsync_if_o[0].id_rsp = '0; - assign vt_fsync_if_o[0].error = 1'b0; - assign vn_fsync_if_o[0].wake = 1'b0; - assign vn_fsync_if_o[0].lvl = '0; - assign vn_fsync_if_o[0].id_rsp = '0; - assign vn_fsync_if_o[0].error = 1'b0; + assign debug_req = 1'b0; +`ifdef MAGIA_FSYNC + assign ht_fsync_rsp_i = '0; + assign hn_fsync_rsp_i = '0; + assign vt_fsync_rsp_i = '0; + assign vn_fsync_rsp_i = '0; +`endif /*******************************************************/ /** Hardwired Signals End **/ @@ -135,13 +130,42 @@ module magia_tile_vip /** Clock and Reset Beginning **/ /*******************************************************/ - clk_rst_gen #( - .ClkPeriod ( CLK_PERIOD ), - .RstClkCycles ( RST_CYCLES ) - ) i_clk_rst_sys ( - .clk_o ( clk ), - .rst_no ( rst_n ) - ); + // A real 1 -> 0 reset edge with the clock stopped, so 2-state simulators reset every async flop + localparam time RST_ASSERT_TIME = CLK_PERIOD; + localparam time CLK_START_TIME = 2 * CLK_PERIOD; + + initial begin: p_clk_gen + clk = 1'b0; + #(CLK_START_TIME); + forever begin + clk = 1'b1; + #(CLK_PERIOD / 2); + clk = 1'b0; + #((CLK_PERIOD + 1) / 2); + end + end + + initial begin: p_rst_gen + rst_n = 1'b1; + #(RST_ASSERT_TIME); + rst_n = 1'b0; + repeat (RST_CYCLES) @(negedge clk); + rst_n = 1'b1; + end + +`ifndef VERILATOR + // $assertcontrol arguments (IEEE 1800-2012 20.12): control On/Off, unique|unique0|priority checks + localparam int unsigned ASSERT_ON = 3; + localparam int unsigned ASSERT_OFF = 4; + localparam int unsigned ASSERT_UNIQUE_PRIO = 32 + 64 + 128; + + // FSM states are X until the reset edge + initial begin: p_unique_check_gate + $assertcontrol(ASSERT_OFF, ASSERT_UNIQUE_PRIO); + #(RST_ASSERT_TIME + 1); + $assertcontrol(ASSERT_ON, ASSERT_UNIQUE_PRIO); + end +`endif /*******************************************************/ /** Clock and Reset End **/ @@ -159,7 +183,9 @@ module magia_tile_vip $readmemh(image, i_l2_mem.i_l2_mem.mem); endtask: data_preload + // rst_n is high at power-up, so wait for the falling edge first task wait_for_reset; + @(negedge rst_n); @(posedge rst_n); @(posedge clk); endtask: wait_for_reset @@ -218,21 +244,21 @@ int errors = -1; bit stdio_ready = 0; bit stderr_ready = 0; always @(posedge clk) begin: print_monitor - if ((i_magia_tile.i_axi_xbar.mst_ports_req_o[0].aw.addr == 32'hFFFF0000) && (i_magia_tile.i_axi_xbar.mst_ports_req_o[0].aw_valid)) stderr_ready = 1'b1; - if ((i_magia_tile.i_axi_xbar.mst_ports_req_o[0].aw.addr == 32'hFFFF0004) && (i_magia_tile.i_axi_xbar.mst_ports_req_o[0].aw_valid)) stdio_ready = 1'b1; - if ((i_magia_tile.i_axi_xbar.mst_ports_req_o[0].w_valid) && stderr_ready) begin + if ((i_magia_tile.i_magia_isle.i_axi_xbar.mst_ports_req_o[0].aw.addr == 32'hFFFF0000) && (i_magia_tile.i_magia_isle.i_axi_xbar.mst_ports_req_o[0].aw_valid)) stderr_ready = 1'b1; + if ((i_magia_tile.i_magia_isle.i_axi_xbar.mst_ports_req_o[0].aw.addr == 32'hFFFF0004) && (i_magia_tile.i_magia_isle.i_axi_xbar.mst_ports_req_o[0].aw_valid)) stdio_ready = 1'b1; + if ((i_magia_tile.i_magia_isle.i_axi_xbar.mst_ports_req_o[0].w_valid) && stderr_ready) begin // NOTE: This is stupid! But unless we keep track of the outstanding AXI writes (which would require some logic) this should work, // unless other modules (not related to the print function) transfer bytes (instead of words) to the L2 - if (i_magia_tile.i_axi_xbar.mst_ports_req_o[0].w.data < 256 && i_magia_tile.i_axi_xbar.mst_ports_req_o[0].w.data > 0) begin - errors = i_magia_tile.i_axi_xbar.mst_ports_req_o[0].w.data; + if (i_magia_tile.i_magia_isle.i_axi_xbar.mst_ports_req_o[0].w.data < 256 && i_magia_tile.i_magia_isle.i_axi_xbar.mst_ports_req_o[0].w.data > 0) begin + errors = i_magia_tile.i_magia_isle.i_axi_xbar.mst_ports_req_o[0].w.data; stderr_ready = 1'b0; end end - if ((i_magia_tile.i_axi_xbar.mst_ports_req_o[0].w_valid) && stdio_ready) begin + if ((i_magia_tile.i_magia_isle.i_axi_xbar.mst_ports_req_o[0].w_valid) && stdio_ready) begin // NOTE: This is stupid! But unless we keep track of the outstanding AXI writes (which would require some logic) this should work, // unless other modules (not related to the print function) transfer bytes (instead of words) to the L2 - if (i_magia_tile.i_axi_xbar.mst_ports_req_o[0].w.data < 256 && i_magia_tile.i_axi_xbar.mst_ports_req_o[0].w.data > 0) begin - $write("%c", i_magia_tile.i_axi_xbar.mst_ports_req_o[0].w.data); + if (i_magia_tile.i_magia_isle.i_axi_xbar.mst_ports_req_o[0].w.data < 256 && i_magia_tile.i_magia_isle.i_axi_xbar.mst_ports_req_o[0].w.data > 0) begin + $write("%c", i_magia_tile.i_magia_isle.i_axi_xbar.mst_ports_req_o[0].w.data); stdio_ready = 1'b0; end end @@ -259,9 +285,9 @@ end `ifdef PROFILE_DETAILED bit[31:0] curr_instr; `ifdef CV32E40X - assign curr_instr = i_magia_tile.i_cv32e40x_ctrl_core.core_i.if_stage_i.if_id_pipe_o.instr.bus_resp.rdata; + assign curr_instr = i_magia_tile.i_magia_isle.i_cv32e40x_ctrl_core.core_i.if_stage_i.if_id_pipe_o.instr.bus_resp.rdata; `else - assign curr_instr = i_magia_tile.i_cv32e40p_ctrl_core.id_stage_i.instr_rdata_i; + assign curr_instr = i_magia_tile.i_magia_isle.i_cv32e40p_ctrl_core.id_stage_i.instr_rdata_i; `endif always @(curr_instr) begin: instr_reporter if (curr_instr == 32'h50500013) $display("[TB] detected sentinel instruction at time %0dns", time_var); @@ -275,11 +301,11 @@ end time end_sentinel[$]; time sentinel_latency; `ifdef CV32E40X - assign curr_instr_wb = i_magia_tile.i_cv32e40x_ctrl_core.core_i.wb_stage_i.ex_wb_pipe_i.instr_valid ? - i_magia_tile.i_cv32e40x_ctrl_core.core_i.wb_stage_i.ex_wb_pipe_i.instr.bus_resp.rdata : '0; + assign curr_instr_wb = i_magia_tile.i_magia_isle.i_cv32e40x_ctrl_core.core_i.wb_stage_i.ex_wb_pipe_i.instr_valid ? + i_magia_tile.i_magia_isle.i_cv32e40x_ctrl_core.core_i.wb_stage_i.ex_wb_pipe_i.instr.bus_resp.rdata : '0; `else - assign curr_instr_wb = i_magia_tile.i_cv32e40p_ctrl_core.wb_valid ? - i_magia_tile.i_cv32e40p_ctrl_core.instr_rdata_id : '0; + assign curr_instr_wb = i_magia_tile.i_magia_isle.i_cv32e40p_ctrl_core.wb_valid ? + i_magia_tile.i_magia_isle.i_cv32e40p_ctrl_core.instr_rdata_id : '0; `endif always @(curr_instr_wb) begin: instr_wb_reporter if (curr_instr_wb == 32'h5AA00013) begin diff --git a/target/verilator/include/uvm_macros.svh b/target/verilator/include/uvm_macros.svh index 9342ad66..a6cac100 100644 --- a/target/verilator/include/uvm_macros.svh +++ b/target/verilator/include/uvm_macros.svh @@ -1,5 +1,5 @@ // Copyright 2026 ETH Zurich and University of Bologna -// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: SHL-0.51 // // Minimal stand-in for UVM's uvm_macros.svh, for the Verilator flow only. // diff --git a/target/verilator/src/cv32e40p_instr_trace.svh b/target/verilator/src/cv32e40p_instr_trace.svh new file mode 100644 index 00000000..45c577ed --- /dev/null +++ b/target/verilator/src/cv32e40p_instr_trace.svh @@ -0,0 +1,1264 @@ +// VENDORIZED COPY for the Verilator flow: cv32e40p bhv/cv32e40p_instr_trace.svh at rev 193270d plus the "MAGIA verilator:" members +// Copyright 2020 Silicon Labs, Inc. +// +// This file, and derivatives thereof are licensed under the +// Solderpad License, Version 2.0 (the "License"). +// +// Use of this file means you agree to the terms and conditions +// of the license and are in full compliance with the License. +// +// You may obtain a copy of the License at: +// +// https://solderpad.org/licenses/SHL-2.0/ +// +// Unless required by applicable law or agreed to in writing, software +// and hardware implementations thereof distributed under the License +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED. +// +// See the License for the specific language governing permissions and +// limitations under the License. + +//////////////////////////////////////////////////////////////////////////////// +// Engineer: Steve Richmond - steve.richmond@silabs.com // +// // +// Design Name: cv32e40p_tracer data structures // +// Project Name: CV32E40P // +// Language: SystemVerilog // +// // +// Description: Moves the class definition for instr_trace_t out of the // +// tracer module for readability and code partitioning // +// // +// Includes various enhancements to make the instr_trace_t // +// class more comprehensive // +// // +//////////////////////////////////////////////////////////////////////////////// + +typedef struct { + logic [5:0] addr; + logic [31:0] value; + bit filled; +} reg_t; + +typedef struct { + logic [31:0] addr; + logic we; + logic [3:0] be; + logic [31:0] wdata; + logic [31:0] rdata; +} mem_acc_t; + +class instr_trace_t; + time simtime; + time stoptime; + bit external_time; + int cycles; + int stopcycles; + logic [31:0] pc; + logic [31:0] instr; + string ctx; //Used to add context in the trace log file (Canceled, debug, interrput,....) + bit compressed; + bit wb_bypass; + bit misaligned; + bit retire; + bit ebreak; + string str; + reg_t regs_read[$]; + reg_t regs_write[$]; + mem_acc_t mem_access[$]; + logic is_apu; + logic is_load; + logic got_regs_write; + + // MAGIA verilator: Verilator shares this class across tracer instances, so each object keeps its own tracer state + integer f; + logic [5:0] rd, rs1, rs2, rs3, rs4; + logic [31:0] rs1_value, rs2_value, rs2_value_vec, rs3_value; + logic [31:0] imm_u_type, imm_uj_type, imm_i_type, imm_z_type, imm_s_type, imm_sb_type; + logic [31:0] imm_s2_type, imm_s3_type, imm_vs_type, imm_vu_type, imm_shuffle_type; + logic [11:0] imm_iz_type; + logic [ 4:0] imm_clip_type; + + function new(); + str = ""; + regs_read = {}; + regs_write = {}; + mem_access = {}; + external_time = 0; + stoptime = 0; + stopcycles = 0; + endfunction + + function void init(int unsigned cycles, bit [31:0] pc, bit compressed, bit [31:0] instr); + if(!this.external_time) begin + this.simtime = $time; + end + this.cycles = cycles; + this.pc = pc; + this.compressed = compressed; + this.instr = instr; + this.is_apu = 0; + this.is_load = 0; + this.got_regs_write = 0; + + // use casex instead of case inside due to ModelSim bug + casex (instr) + // Aliases + 32'h00_00_00_13: this.printMnemonic("nop"); + // Regular opcodes + INSTR_LUI: this.printUInstr("lui"); + INSTR_AUIPC: this.printUInstr("auipc"); + INSTR_JAL: this.printUJInstr("jal"); + INSTR_JALR: this.printIInstr("jalr"); + // BRANCH + INSTR_BEQ: this.printSBInstr("beq"); + INSTR_BNE: this.printSBInstr("bne"); + INSTR_BLT: this.printSBInstr("blt"); + INSTR_BGE: this.printSBInstr("bge"); + INSTR_BLTU: this.printSBInstr("bltu"); + INSTR_BGEU: this.printSBInstr("bgeu"); + INSTR_BEQIMM: this.printSBallInstr("cv.beqimm"); + INSTR_BNEIMM: this.printSBallInstr("cv.bneimm"); + // OPIMM + INSTR_ADDI: this.printIInstr("addi"); + INSTR_SLTI: this.printIInstr("slti"); + INSTR_SLTIU: this.printIInstr("sltiu"); + INSTR_XORI: this.printIInstr("xori"); + INSTR_ORI: this.printIInstr("ori"); + INSTR_ANDI: this.printIInstr("andi"); + INSTR_SLLI: this.printIuInstr("slli"); + INSTR_SRLI: this.printIuInstr("srli"); + INSTR_SRAI: this.printIuInstr("srai"); + // OP + INSTR_ADD: this.printRInstr("add"); + INSTR_SUB: this.printRInstr("sub"); + INSTR_SLL: this.printRInstr("sll"); + INSTR_SLT: this.printRInstr("slt"); + INSTR_SLTU: this.printRInstr("sltu"); + INSTR_XOR: this.printRInstr("xor"); + INSTR_SRL: this.printRInstr("srl"); + INSTR_SRA: this.printRInstr("sra"); + INSTR_OR: this.printRInstr("or"); + INSTR_AND: this.printRInstr("and"); + INSTR_EXTHS: this.printRInstr("cv.exths"); + INSTR_EXTHZ: this.printRInstr("cv.exthz"); + INSTR_EXTBS: this.printRInstr("cv.extbs"); + INSTR_EXTBZ: this.printRInstr("cv.extbz"); + INSTR_PAVG: this.printRInstr("cv.avg"); + INSTR_PAVGU: this.printRInstr("cv.avgu"); + + INSTR_PADDN: this.printAddNInstr("cv.addN"); + INSTR_PADDUN: this.printAddNInstr("cv.adduN"); + INSTR_PADDRN: this.printAddNInstr("cv.addRN"); + INSTR_PADDURN: this.printAddNInstr("cv.adduRN"); + INSTR_PSUBN: this.printAddNInstr("cv.subN"); + INSTR_PSUBUN: this.printAddNInstr("cv.subuN"); + INSTR_PSUBRN: this.printAddNInstr("cv.subRN"); + INSTR_PSUBURN: this.printAddNInstr("cv.subuRN"); + + INSTR_PADDNR: this.printR3Instr("cv.addNr"); + INSTR_PADDUNR: this.printR3Instr("cv.adduNr"); + INSTR_PADDRNR: this.printR3Instr("cv.addRNr"); + INSTR_PADDURNR: this.printR3Instr("cv.adduRNr"); + INSTR_PSUBNR: this.printR3Instr("cv.subNr"); + INSTR_PSUBUNR: this.printR3Instr("cv.subuNr"); + INSTR_PSUBRNR: this.printR3Instr("cv.subRNr"); + INSTR_PSUBURNR: this.printR3Instr("cv.subuRNr"); + + INSTR_PSLET: this.printRInstr("cv.slet"); + INSTR_PSLETU: this.printRInstr("cv.sletu"); + INSTR_PMIN: this.printRInstr("cv.min"); + INSTR_PMINU: this.printRInstr("cv.minu"); + INSTR_PMAX: this.printRInstr("cv.max"); + INSTR_PMAXU: this.printRInstr("cv.maxu"); + INSTR_PABS: this.printR1Instr("cv.abs"); + INSTR_PCLIP: this.printClipInstr("cv.clip"); + INSTR_PCLIPU: this.printClipInstr("cv.clipu"); + INSTR_PBEXT: this.printBit1Instr("cv.extract"); + INSTR_PBEXTU: this.printBit1Instr("cv.extractu"); + INSTR_PBINS: this.printBit2Instr("cv.insert"); + INSTR_PBCLR: this.printBit1Instr("cv.bclr"); + INSTR_PBSET: this.printBit1Instr("cv.bset"); + INSTR_PBREV: this.printBitRevInstr("cv.bitrev"); + + INSTR_PCLIPR: this.printRInstr("cv.clipr"); + INSTR_PCLIPUR: this.printRInstr("cv.clipur"); + INSTR_PBEXTR: this.printRInstr("cv.extractr"); + INSTR_PBEXTUR: this.printRInstr("cv.extractur"); + INSTR_PBINSR: this.printR3Instr("cv.insertr"); + INSTR_PBCLRR: this.printRInstr("cv.bclrr"); + INSTR_PBSETR: this.printRInstr("cv.bsetr"); + + + INSTR_FF1: this.printR1Instr("cv.ff1"); + INSTR_FL1: this.printR1Instr("cv.fl1"); + INSTR_CLB: this.printR1Instr("cv.clb"); + INSTR_CNT: this.printR1Instr("cv.cnt"); + INSTR_ROR: this.printRInstr("cv.ror"); + + // FENCE + INSTR_FENCE: this.printMnemonic("fence"); + INSTR_FENCEI: this.printMnemonic("fencei"); + // SYSTEM (CSR manipulation) + INSTR_CSRRW: this.printCSRInstr("csrrw"); + INSTR_CSRRS: this.printCSRInstr("csrrs"); + INSTR_CSRRC: this.printCSRInstr("csrrc"); + INSTR_CSRRWI: this.printCSRInstr("csrrwi"); + INSTR_CSRRSI: this.printCSRInstr("csrrsi"); + INSTR_CSRRCI: this.printCSRInstr("csrrci"); + // SYSTEM (others) + INSTR_ECALL: this.printMnemonic("ecall"); + INSTR_EBREAK: this.printMnemonic("ebreak"); + INSTR_URET: this.printMnemonic("uret"); + INSTR_MRET: this.printMnemonic("mret"); + INSTR_WFI: this.printMnemonic("wfi"); + + INSTR_DRET: this.printMnemonic("dret"); + + // RV32M + INSTR_PMUL: this.printRInstr("mul"); + INSTR_PMUH: this.printRInstr("mulh"); + INSTR_PMULHSU: this.printRInstr("mulhsu"); + INSTR_PMULHU: this.printRInstr("mulhu"); + INSTR_DIV: this.printRInstr("div"); + INSTR_DIVU: this.printRInstr("divu"); + INSTR_REM: this.printRInstr("rem"); + INSTR_REMU: this.printRInstr("remu"); + // PULP MULTIPLIER + INSTR_PMAC: this.printR3Instr("cv.mac"); + INSTR_PMSU: this.printR3Instr("cv.msu"); + INSTR_PMULSN: this.printMulInstr(); + INSTR_PMULHHSN: this.printMulInstr(); + INSTR_PMULSRN: this.printMulInstr(); + INSTR_PMULHHSRN: this.printMulInstr(); + INSTR_PMULUN: this.printMulInstr(); + INSTR_PMULHHUN: this.printMulInstr(); + INSTR_PMULURN: this.printMulInstr(); + INSTR_PMULHHURN: this.printMulInstr(); + INSTR_PMACSN: this.printMulInstr(); + INSTR_PMACHHSN: this.printMulInstr(); + INSTR_PMACSRN: this.printMulInstr(); + INSTR_PMACHHSRN: this.printMulInstr(); + INSTR_PMACUN: this.printMulInstr(); + INSTR_PMACHHUN: this.printMulInstr(); + INSTR_PMACURN: this.printMulInstr(); + INSTR_PMACHHURN: this.printMulInstr(); + + // FP-OP + INSTR_FMADD: begin this.printF3Instr("fmadd.s"); this.is_apu = 1; end + INSTR_FMSUB: begin this.printF3Instr("fmsub.s"); this.is_apu = 1; end + INSTR_FNMADD: begin this.printF3Instr("fnmadd.s"); this.is_apu = 1; end + INSTR_FNMSUB: begin this.printF3Instr("fnmsub.s"); this.is_apu = 1; end + INSTR_FADD: begin this.printF2Instr("fadd.s"); this.is_apu = 1; end + INSTR_FSUB: begin this.printF2Instr("fsub.s"); this.is_apu = 1; end + INSTR_FMUL: begin this.printF2Instr("fmul.s"); this.is_apu = 1; end + INSTR_FDIV: begin this.printF2Instr("fdiv.s"); this.is_apu = 1; end + INSTR_FSQRT: begin this.printFInstr("fsqrt.s"); this.is_apu = 1; end + INSTR_FSGNJS: begin this.printF2Instr("fsgnj.s"); this.is_apu = 1; end + INSTR_FSGNJNS: begin this.printF2Instr("fsgnjn.s"); this.is_apu = 1; end + INSTR_FSGNJXS: begin this.printF2Instr("fsgnjx.s"); this.is_apu = 1; end + INSTR_FMIN: begin this.printF2Instr("fmin.s"); this.is_apu = 1; end + INSTR_FMAX: begin this.printF2Instr("fmax.s"); this.is_apu = 1; end + INSTR_FCVTWS: begin this.printFIInstr("fcvt.w.s"); this.is_apu = 1; end + INSTR_FCVTWUS: begin this.printFIInstr("fcvt.wu.s"); this.is_apu = 1; end + INSTR_FMVXS: begin this.printFIInstr("fmv.x.s"); this.is_apu = 1; end + INSTR_FEQS: begin this.printF2IInstr("feq.s"); this.is_apu = 1; end + INSTR_FLTS: begin this.printF2IInstr("flt.s"); this.is_apu = 1; end + INSTR_FLES: begin this.printF2IInstr("fle.s"); this.is_apu = 1; end + INSTR_FCLASS: begin this.printFIInstr("fclass.s"); this.is_apu = 1; end + INSTR_FCVTSW: begin this.printIFInstr("fcvt.s.w"); this.is_apu = 1; end + INSTR_FCVTSWU: begin this.printIFInstr("fcvt.s.wu"); this.is_apu = 1; end + INSTR_FMVSX: begin this.printIFInstr("fmv.s.x"); this.is_apu = 1; end + + // RV32A + INSTR_LR: this.printAtomicInstr("lr.w"); + INSTR_SC: this.printAtomicInstr("sc.w"); + INSTR_AMOSWAP: this.printAtomicInstr("amoswap.w"); + INSTR_AMOADD: this.printAtomicInstr("amoadd.w"); + INSTR_AMOXOR: this.printAtomicInstr("amoxor.w"); + INSTR_AMOAND: this.printAtomicInstr("amoand.w"); + INSTR_AMOOR: this.printAtomicInstr("amoor.w"); + INSTR_AMOMIN: this.printAtomicInstr("amomin.w"); + INSTR_AMOMAX: this.printAtomicInstr("amomax.w"); + INSTR_AMOMINU: this.printAtomicInstr("amominu.w"); + INSTR_AMOMAXU: this.printAtomicInstr("amomaxu.w"); + + // opcodes with custom decoding + {25'b?, OPCODE_LOAD} : begin this.printLoadInstr(""); this.is_load = 1; end + {25'b?, OPCODE_LOAD_FP} : begin this.printLoadInstr("f"); this.is_load = 1; end + {25'b?, OPCODE_CUSTOM_0} : begin this.printLoadInstr(""); this.is_load = 1; end + {7'b000????, 10'b?, 3'b011, 5'b?, OPCODE_CUSTOM_1} : begin this.printLoadInstr(""); this.is_load = 1; end + {7'b001????, 10'b?, 3'b011, 5'b?, OPCODE_CUSTOM_1} : this.printStoreInstr(""); + {17'b?, 3'b100, 5'b?, OPCODE_CUSTOM_1} : this.printHwloopInstr(); + {25'b?, OPCODE_STORE} : this.printStoreInstr(""); + {25'b?, OPCODE_STORE_FP} : this.printStoreInstr("f"); + {17'b?, 3'b0??, 5'b?, OPCODE_CUSTOM_1} : this.printStoreInstr(""); + {25'b?, OPCODE_CUSTOM_3} : this.printVecInstr(); + default: this.printMnemonic("INVALID"); + endcase // unique case (instr) + + endfunction : init + + function bit is_regs_write_done(); + foreach (regs_write[i]) if (regs_write[i].value === 'x) return 0; + + return 1; + endfunction : is_regs_write_done + + function string regAddrToStr(input logic [5:0] addr); + begin + if (SymbolicRegs==1 && (FPU==0 || ZFINX==0)) begin // format according to RISC-V ABI + if (addr == 0) return $sformatf("zero"); + else if (addr == 1) return $sformatf(" ra"); + else if (addr == 2) return $sformatf(" sp"); + else if (addr == 3) return $sformatf(" gp"); + else if (addr == 4) return $sformatf(" tp"); + else if (addr <= 7) return $sformatf(" t%0d", addr - 5); + else if (addr <= 9) return $sformatf(" s%0d", addr - 8); + else if (addr <= 17) return $sformatf(" a%0d", addr - 10); + else if (addr <= 25) return $sformatf(" s%0d", addr - 16); + else if (addr <= 27) return $sformatf(" s%0d", addr - 16); + else if (addr <= 31) return $sformatf(" t%0d", addr - 25); + else if (addr <= 32 + 7) return $sformatf(" ft%0d", addr - 32); + else if (addr <= 32 + 9) return $sformatf(" fs%0d", addr - 40); + else if (addr <= 32 + 17) return $sformatf(" fa%0d", addr - 42); + else if (addr <= 32 + 25) return $sformatf(" fs%0d", addr - 48); + else if (addr <= 32 + 27) return $sformatf("fs%0d", addr - 48); + else if (addr <= 32 + 29) return $sformatf(" ft%0d", addr - 52); + else if (addr <= 32 + 31) return $sformatf("ft%0d", addr - 52); + else return $sformatf("UNKNOWN %0d", addr); + end else begin + if (addr >= 42) return $sformatf("f%0d", addr - 32); + else if (addr >= 32) return $sformatf(" f%0d", addr - 32); + else if (addr < 10) return $sformatf(" x%0d", addr); + else return $sformatf("x%0d", addr); + end + end + endfunction + + function void printInstrTrace(); + mem_acc_t mem_acc; + begin + string insn_str; // Accumulate writes into a single string to enable single $fwrite + + if(simtime < 100ns) begin + insn_str = $sformatf(" %t %15d %h %h %-3s %-36s", simtime, cycles, pc, instr, ctx, str); + end else if (simtime < 1us) begin + insn_str = $sformatf(" %t %15d %h %h %-3s %-36s", simtime, cycles, pc, instr, ctx, str); + end else if (simtime < 10us) begin + insn_str = $sformatf(" %t %15d %h %h %-3s %-36s", simtime, cycles, pc, instr, ctx, str); + end else if (simtime < 100us) begin + insn_str = $sformatf(" %t %15d %h %h %-3s %-36s", simtime, cycles, pc, instr, ctx, str); + end else if (simtime < 1ms) begin + insn_str = $sformatf(" %t %15d %h %h %-3s %-36s", simtime, cycles, pc, instr, ctx, str); + end else if (simtime < 10ms) begin + insn_str = $sformatf(" %t %15d %h %h %-3s %-36s", simtime, cycles, pc, instr, ctx, str); + end else if (simtime < 100ms) begin + insn_str = $sformatf(" %t %15d %h %h %-3s %-36s", simtime, cycles, pc, instr, ctx, str); + end else begin + insn_str = $sformatf("%t %15d %h %h %-3s %-36s", simtime, cycles, pc, instr, ctx, str); + end + + foreach (regs_write[i]) begin + if (regs_write[i].addr != 0) + insn_str = $sformatf( + "%s %s=%08x", insn_str, regAddrToStr(regs_write[i].addr), regs_write[i].value + ); + end + + foreach (regs_read[i]) begin + if (regs_read[i].addr != 0) + insn_str = $sformatf( + "%s %s:%08x", insn_str, regAddrToStr(regs_read[i].addr), regs_read[i].value + ); + end + + if (mem_access.size() > 0) begin + mem_acc = mem_access.pop_front(); + + insn_str = $sformatf("%s PA:%08x", insn_str, mem_acc.addr); + end + + casex (instr) + INSTR_FDIV: insn_str = $sformatf("%s %15d %t", insn_str, stopcycles, stoptime); + INSTR_FSQRT:insn_str = $sformatf("%s %15d %t", insn_str, stopcycles, stoptime); + default: ; + endcase + + $fwrite(f, "%s\n", insn_str); + end + endfunction + + function void printMnemonic(input string mnemonic); + begin + str = {compressed ? "c." : "", mnemonic}; + end + endfunction // printMnemonic + + function void printRInstr(input string mnemonic); + begin + mnemonic = {compressed ? "c." : "", mnemonic}; + regs_read.push_back('{rs1, rs1_value, 0}); + regs_read.push_back('{rs2, rs2_value, 0}); + regs_write.push_back('{rd, 'x, 0}); + str = $sformatf("%-16s %s, %s, %s", mnemonic, regAddrToStr(rd), regAddrToStr(rs1), regAddrToStr(rs2)); + end + endfunction // printRInstr + + function void printAddNInstr(input string mnemonic); + begin + regs_read.push_back('{rs1, rs1_value, 0}); + regs_read.push_back('{rs2, rs2_value, 0}); + regs_write.push_back('{rd, 'x, 0}); + str = $sformatf( + "%-16s %s, %s, %s, 0x%0h", mnemonic, regAddrToStr(rd), regAddrToStr(rs1), regAddrToStr(rs2), $unsigned(imm_s3_type[4:0]) + ); + end + endfunction // printAddNInstr + + function void printR1Instr(input string mnemonic); + begin + regs_read.push_back('{rs1, rs1_value, 0}); + regs_write.push_back('{rd, 'x, 0}); + str = $sformatf("%-16s %s, %s", mnemonic, regAddrToStr(rd), regAddrToStr(rs1)); + end + endfunction // printR1Instr + + function void printR3Instr(input string mnemonic); + begin + regs_read.push_back('{rd, rs3_value, 0}); + regs_read.push_back('{rs1, rs1_value, 0}); + regs_read.push_back('{rs2, rs2_value, 0}); + regs_write.push_back('{rd, 'x, 0}); + str = $sformatf("%-16s %s, %s, %s", mnemonic, regAddrToStr(rd), regAddrToStr(rs1), regAddrToStr(rs2)); + end + endfunction // printR3Instr + + function void printF3Instr(input string mnemonic); + begin + regs_read.push_back('{rs1, rs1_value, 0}); + regs_read.push_back('{rs2, rs2_value, 0}); + regs_read.push_back('{rs4, rs3_value, 0}); + regs_write.push_back('{rd, 'x, 0}); + str = $sformatf( + "%-16s %s, %s, %s, %s", mnemonic, regAddrToStr(rd), regAddrToStr(rs1), regAddrToStr(rs2), regAddrToStr(rs4) + ); + end + endfunction // printF3Instr + + function void printF2Instr(input string mnemonic); + begin + regs_read.push_back('{rs1, rs1_value, 0}); + regs_read.push_back('{rs2, rs2_value, 0}); + regs_write.push_back('{rd, 'x, 0}); + str = $sformatf("%-16s %s, %s, %s", mnemonic, regAddrToStr(rd), regAddrToStr(rs1), regAddrToStr(rs2)); + end + endfunction // printF2Instr + + function void printF2IInstr(input string mnemonic); + begin + regs_read.push_back('{rs1, rs1_value, 0}); + regs_read.push_back('{rs2, rs2_value, 0}); + regs_write.push_back('{rd, 'x, 0}); + str = $sformatf("%-16s %s, %s, %s", mnemonic, regAddrToStr(rd), regAddrToStr(rs1), regAddrToStr(rs2)); + end + endfunction // printF2IInstr + + function void printFInstr(input string mnemonic); + begin + regs_read.push_back('{rs1, rs1_value, 0}); + regs_write.push_back('{rd, 'x, 0}); + str = $sformatf("%-16s %s, %s", mnemonic, regAddrToStr(rd), regAddrToStr(rs1)); + end + endfunction // printFInstr + + function void printFIInstr(input string mnemonic); + begin + regs_read.push_back('{rs1, rs1_value, 0}); + regs_write.push_back('{rd, 'x, 0}); + str = $sformatf("%-16s %s, %s", mnemonic, regAddrToStr(rd), regAddrToStr(rs1)); + end + endfunction // printFIInstr + + function void printIFInstr(input string mnemonic); + begin + mnemonic = {compressed ? "c." : "", mnemonic}; + regs_read.push_back('{rs1, rs1_value, 0}); + regs_write.push_back('{rd, 'x, 0}); + str = $sformatf("%-16s %s, %s", mnemonic, regAddrToStr(rd), regAddrToStr(rs1)); + end + endfunction // printIFInstr + + function void printClipInstr(input string mnemonic); + begin + regs_read.push_back('{rs1, rs1_value, 0}); + regs_write.push_back('{rd, 'x, 0}); + str = $sformatf("%-16s %s, %s, %0d", mnemonic, regAddrToStr(rd), regAddrToStr(rs1), $unsigned(imm_clip_type)); + end + endfunction // printRInstr + + function void printIInstr(input string mnemonic); + begin + mnemonic = {compressed ? "c." : "", mnemonic}; + regs_read.push_back('{rs1, rs1_value, 0}); + regs_write.push_back('{rd, 'x, 0}); + str = $sformatf("%-16s %s, %s, %0d", mnemonic, regAddrToStr(rd), regAddrToStr(rs1), $signed(imm_i_type)); + end + endfunction // printIInstr + + function void printIuInstr(input string mnemonic); + begin + mnemonic = {compressed ? "c." : "", mnemonic}; + regs_read.push_back('{rs1, rs1_value, 0}); + regs_write.push_back('{rd, 'x, 0}); + str = $sformatf("%-16s %s, %s, 0x%0x", mnemonic, regAddrToStr(rd), regAddrToStr(rs1), imm_i_type); + end + endfunction // printIuInstr + + function void printUInstr(input string mnemonic); + begin + mnemonic = {compressed ? "c." : "", mnemonic}; + regs_write.push_back('{rd, 'x, 0}); + str = $sformatf("%-16s %s, 0x%0h", mnemonic, regAddrToStr(rd), {imm_u_type[31:12], 12'h000}); + end + endfunction // printUInstr + + function void printUJInstr(input string mnemonic); + begin + mnemonic = {compressed ? "c." : "", mnemonic}; + regs_write.push_back('{rd, 'x, 0}); + str = $sformatf("%-16s %s, %0d", mnemonic, regAddrToStr(rd), $signed(imm_uj_type)); + end + endfunction // printUJInstr + + function void printSBInstr(input string mnemonic); + begin + mnemonic = {compressed ? "c." : "", mnemonic}; + regs_read.push_back('{rs1, rs1_value, 0}); + regs_read.push_back('{rs2, rs2_value, 0}); + str = $sformatf("%-16s %s, %s, %0d", mnemonic, regAddrToStr(rs1), regAddrToStr(rs2), $signed(imm_sb_type)); + end + endfunction // printSBInstr + + function void printSBallInstr(input string mnemonic); + begin + mnemonic = {compressed ? "c." : "", mnemonic}; + regs_read.push_back('{rs1, rs1_value, 0}); + str = $sformatf("%-16s %s, %0d, %0d", mnemonic, regAddrToStr(rs1), $signed(imm_s2_type), $signed(imm_sb_type)); + end + endfunction // printSBInstr + + function void printCSRInstr(input string mnemonic); + logic [11:0] csr; + begin + csr = instr[31:20]; + + regs_write.push_back('{rd, 'x, 0}); + + if (instr[14] == 1'b0) begin + regs_read.push_back('{rs1, rs1_value, 0}); + str = $sformatf("%-16s %s, %s, 0x%h", mnemonic, regAddrToStr(rd), regAddrToStr(rs1), csr); + end else begin + str = $sformatf("%-16s %s, 0x%h, 0x%h", mnemonic, regAddrToStr(rd), imm_z_type, csr); + end + end + endfunction // printCSRInstr + + function void printBit1Instr(input string mnemonic); + begin + regs_read.push_back('{rs1, rs1_value, 0}); + regs_write.push_back('{rd, 'x, 0}); + str = $sformatf("%-16s %s, %s, %0d, %0d", mnemonic, regAddrToStr(rd), regAddrToStr(rs1), imm_s3_type, imm_s2_type); + end + endfunction + + function void printBitRevInstr(input string mnemonic); + begin + regs_read.push_back('{rs1, rs1_value, 0}); + regs_write.push_back('{rd, 'x, 0}); + str = $sformatf("%-16s %s, %s, %0d, %0d", mnemonic, regAddrToStr(rd), regAddrToStr(rs1), imm_s2_type, imm_s3_type); + end + endfunction + + function void printBit2Instr(input string mnemonic); + begin + regs_read.push_back('{rd, rs3_value, 0}); + regs_read.push_back('{rs1, rs1_value, 0}); + regs_write.push_back('{rd, 'x, 0}); + str = $sformatf("%-16s %s, %s, %0d, %0d", mnemonic, regAddrToStr(rd), regAddrToStr(rs1), imm_s3_type, imm_s2_type); + end + endfunction + + function void printAtomicInstr(input string mnemonic); + begin + regs_read.push_back('{rs1, rs1_value, 0}); + regs_read.push_back('{rs2, rs2_value, 0}); + regs_write.push_back('{rd, 'x, 0}); + if (instr[31:27] == AMO_LR) begin + // Do not print rs2 for load-reserved + str = $sformatf("%-16s %s, (%s)", mnemonic, regAddrToStr(rd), regAddrToStr(rs1)); + end else begin + str = $sformatf("%-16s %s, %s, (%s)", mnemonic, regAddrToStr(rd), regAddrToStr(rs2), regAddrToStr(rs1)); + end + end + endfunction // printAtomicInstr + + function void printLoadInstr(input string fp); + string mnemonic; + logic [2:0] size; + begin + // find size + size = instr[14:12]; + if (instr[6:0] == OPCODE_CUSTOM_1) size = {instr[28], instr[26:25]}; + + case (size) + 3'b000: mnemonic = "lb"; + 3'b001: mnemonic = "lh"; + 3'b010: mnemonic = "lw"; + 3'b011: mnemonic = "elw"; + 3'b100: mnemonic = "lbu"; + 3'b101: mnemonic = "lhu"; + default: begin + printMnemonic("INVALID"); + return; + end + endcase + if (FPU==1 && ZFINX==0) begin + mnemonic = {fp, mnemonic}; + end + mnemonic = {compressed ? "c." : "", mnemonic}; + + regs_write.push_back('{rd, 'x, 0}); + + if (instr[6:0] != OPCODE_CUSTOM_0 && instr[6:0] != OPCODE_CUSTOM_1) begin + // regular load + regs_read.push_back('{rs1, rs1_value, 0}); + str = $sformatf("%-16s %s, %0d(x%0d)", mnemonic, regAddrToStr(rd), $signed(imm_i_type), rs1); + end else if (instr[6:0] == OPCODE_CUSTOM_0 && size == 3'b011) begin + // cv.elw + regs_read.push_back('{rs1, rs1_value, 0}); + str = $sformatf("cv.%-13s %s, %0d(x%0d)", mnemonic, regAddrToStr(rd), $signed(imm_i_type), rs1); + end else if (instr[6:0] == OPCODE_CUSTOM_0) begin + // immediate post-incremented load + regs_read.push_back('{rs1, rs1_value, 0}); + regs_write.push_back('{rs1, 'x, 0}); + str = $sformatf("cv.%-13s %s, (x%0d), %0d", mnemonic, regAddrToStr(rd), rs1, $signed(imm_i_type)); + end else if (instr[6:0] == OPCODE_CUSTOM_1) begin + if (instr[27] == 1'b0) begin + // reg-reg post-incremented load + regs_read.push_back('{rs2, rs2_value, 0}); + regs_read.push_back('{rs1, rs1_value, 0}); + regs_write.push_back('{rs1, 'x, 0}); + str = $sformatf("cv.%-13s %s, (x%0d), %s", mnemonic, regAddrToStr(rd), rs1, regAddrToStr(rs2)); + end else begin + // reg-reg indexed load + regs_read.push_back('{rs2, rs2_value, 0}); + regs_read.push_back('{rs1, rs1_value, 0}); + str = $sformatf("%-16s %s, %s(x%0d)", mnemonic, regAddrToStr(rd), regAddrToStr(rs2), rs1); + end + end + end + endfunction + + function void printStoreInstr(input string fp); + string mnemonic; + logic [2:0] size; + begin + // find size + size = instr[14:12]; + if (instr[6:0] == OPCODE_CUSTOM_1 && instr[14:12] == 3'b011) size = {instr[28], instr[26:25]}; + + case (size) + 3'b000: mnemonic = "sb"; + 3'b001: mnemonic = "sh"; + 3'b010: mnemonic = "sw"; + default: begin + printMnemonic("INVALID"); + return; + end + endcase + if (FPU==1 && ZFINX==0) begin + mnemonic = {fp, mnemonic}; + end + mnemonic = {compressed ? "c." : "", mnemonic}; + + if (instr[6:0] != OPCODE_CUSTOM_1) begin + // regular store + regs_read.push_back('{rs2, rs2_value, 0}); + regs_read.push_back('{rs1, rs1_value, 0}); + str = $sformatf("%-16s %s, %0d(x%0d)", mnemonic, regAddrToStr(rs2), $signed(imm_s_type), rs1); + end else if (instr[14:12] != 3'b011 && instr[14] != 1'b1) begin + // immediate post-incremented store + regs_read.push_back('{rs2, rs2_value, 0}); + regs_read.push_back('{rs1, rs1_value, 0}); + regs_write.push_back('{rs1, 'x, 0}); + str = $sformatf("cv.%-14s %s, (x%0d), %0d", mnemonic, regAddrToStr(rs2), rs1, $signed(imm_s_type)); + end else if (instr[31:28] == 4'b0010) begin + if (instr[27] == 1'b0) begin + // reg-reg post-incremented store + regs_read.push_back('{rs2, rs2_value, 0}); + regs_read.push_back('{rs3, rs3_value, 0}); + regs_read.push_back('{rs1, rs1_value, 0}); + regs_write.push_back('{rs1, 'x, 0}); + str = $sformatf("cv.%-13s %s, (x%0d), %s", mnemonic, regAddrToStr(rs2), rs1, regAddrToStr(rs3)); + end else begin + // reg-reg indexed store + regs_read.push_back('{rs2, rs2_value, 0}); + regs_read.push_back('{rs3, rs3_value, 0}); + regs_read.push_back('{rs1, rs1_value, 0}); + str = $sformatf("cv.%-13s %s, %s(x%0d)", mnemonic, regAddrToStr(rs2), regAddrToStr(rs3), rs1); + end + end + end + endfunction // printSInstr + + function void printHwloopInstr(); + string mnemonic; + begin + // set mnemonic + case (instr[11:8]) + 4'b0000: mnemonic = "cv.starti"; + 4'b0001: mnemonic = "cv.start"; + 4'b0010: mnemonic = "cv.endi"; + 4'b0011: mnemonic = "cv.end"; + 4'b0100: mnemonic = "cv.counti"; + 4'b0101: mnemonic = "cv.count"; + 4'b0110: mnemonic = "cv.setupi"; + 4'b0111: mnemonic = "cv.setup"; + 4'b1???: begin + printMnemonic("INVALID"); + return; + end + endcase + + // decode and print instruction + case (instr[11:8]) + // cv.starti, cv.endi + 4'b0000, 4'b0010: str = $sformatf("%-16s %d, 0x%0x", mnemonic, instr[7], imm_iz_type); + // cv.counti + 4'b0100: str = $sformatf("%-16s %d, %d", mnemonic, instr[7], imm_iz_type); + // cv.start, cv.end, cv.count + 4'b0001, 4'b0011, 4'b0101: begin + regs_read.push_back('{rs1, rs1_value, 0}); + str = $sformatf("%-16s %d, %s", mnemonic, instr[7], regAddrToStr(rs1)); + end + // cv.setupi + 4'b0110: begin + str = $sformatf("%-16s %d, %d, 0x%0x", mnemonic, instr[7], imm_iz_type, rs1); + end + // cv.setup + 4'b0111: begin + regs_read.push_back('{rs1, rs1_value, 0}); + str = $sformatf("%-16s %d, %s, 0x%0x", mnemonic, instr[7], regAddrToStr(rs1), imm_iz_type); + end + endcase + end + endfunction + + function void printMulInstr(); + string mnemonic; + string str_suf; + string str_imm; + string str_asm; + begin + + // always read rs1 and rs2 and write rd + regs_read.push_back('{rs1, rs1_value, 0}); + regs_read.push_back('{rs2, rs2_value, 0}); + regs_write.push_back('{rd, 'x, 0}); + + if (instr[13]) regs_read.push_back('{rd, rs3_value, 0}); + + case ({instr[12], instr[30], instr[31]}) + 3'b000: str_suf = "s"; + 3'b001: str_suf = "sR"; + 3'b010: str_suf = "hhs"; + 3'b011: str_suf = "hhsR"; + 3'b100: str_suf = "u"; + 3'b101: str_suf = "uR"; + 3'b110: str_suf = "hhu"; + 3'b111: str_suf = "hhuR"; + endcase + + if (instr[13]) mnemonic = "cv.mac"; + else mnemonic = "cv.mul"; + + str_asm = $sformatf("%s%sN", mnemonic, str_suf); + + str = $sformatf("%-16s %s, %s, %s, %0d", str_asm, regAddrToStr(rd), regAddrToStr(rs1), regAddrToStr(rs2), $unsigned(imm_s3_type[4:0])); + end + endfunction + + function void printVecInstr(); + string mnemonic; + string str_asm; + string str_args; + string str_hb; + string str_sci; + string str_imm; + begin + + // always read rs1 and write rd + regs_read.push_back('{rs1, rs1_value, 0}); + regs_write.push_back('{rd, 'x, 0}); + + case (instr[14:13]) + 2'b00: str_sci = ""; + 2'b10: str_sci = ".sc"; + 2'b11: str_sci = ".sci"; + endcase + + if (instr[12]) str_hb = ".b"; + else str_hb = ".h"; + + // set mnemonic + casex (instr) + INSTR_CVADDH , + INSTR_CVADDSCH , + INSTR_CVADDSCIH, + INSTR_CVADDB , + INSTR_CVADDSCB , + INSTR_CVADDSCIB : begin + mnemonic = "cv.add"; + str_imm = $sformatf("0x%0h", imm_vs_type); + end + INSTR_CVSUBH , + INSTR_CVSUBSCH , + INSTR_CVSUBSCIH, + INSTR_CVSUBB , + INSTR_CVSUBSCB , + INSTR_CVSUBSCIB : begin + mnemonic = "cv.sub"; + str_imm = $sformatf("0x%0h", imm_vs_type); + end + INSTR_CVAVGH , + INSTR_CVAVGSCH , + INSTR_CVAVGSCIH , + INSTR_CVAVGB , + INSTR_CVAVGSCB , + INSTR_CVAVGSCIB : begin + mnemonic = "cv.avg"; + str_imm = $sformatf("0x%0h", imm_vs_type); + end + INSTR_CVAVGUH , + INSTR_CVAVGUSCH , + INSTR_CVAVGUSCIH, + INSTR_CVAVGUB , + INSTR_CVAVGUSCB , + INSTR_CVAVGUSCIB : begin + mnemonic = "cv.avgu"; + str_imm = $sformatf("0x%0h", imm_vu_type); + end + INSTR_CVMINH , + INSTR_CVMINSCH , + INSTR_CVMINSCIH, + INSTR_CVMINB , + INSTR_CVMINSCB , + INSTR_CVMINSCIB : begin + mnemonic = "cv.min"; + str_imm = $sformatf("0x%0h", imm_vs_type); + end + INSTR_CVMINUH , + INSTR_CVMINUSCH , + INSTR_CVMINUSCIH, + INSTR_CVMINUB , + INSTR_CVMINUSCB , + INSTR_CVMINUSCIB : begin + mnemonic = "cv.minu"; + str_imm = $sformatf("0x%0h", imm_vu_type); + end + INSTR_CVMAXH , + INSTR_CVMAXSCH , + INSTR_CVMAXSCIH , + INSTR_CVMAXB , + INSTR_CVMAXSCB , + INSTR_CVMAXSCIB : begin + mnemonic = "cv.max"; + str_imm = $sformatf("0x%0h", imm_vs_type); + end + INSTR_CVMAXUH , + INSTR_CVMAXUSCH , + INSTR_CVMAXUSCIH , + INSTR_CVMAXUB , + INSTR_CVMAXUSCB , + INSTR_CVMAXUSCIB : begin + mnemonic = "cv.maxu"; + str_imm = $sformatf("0x%0h", imm_vu_type); + end + INSTR_CVSRLH , + INSTR_CVSRLSCH , + INSTR_CVSRLSCIH , + INSTR_CVSRLB , + INSTR_CVSRLSCB , + INSTR_CVSRLSCIB : begin + mnemonic = "cv.srl"; + str_imm = $sformatf("0x%0h", imm_vs_type); + end + INSTR_CVSRAH , + INSTR_CVSRASCH , + INSTR_CVSRASCIH, + INSTR_CVSRAB , + INSTR_CVSRASCB , + INSTR_CVSRASCIB : begin + mnemonic = "cv.sra"; + str_imm = $sformatf("0x%0h", imm_vs_type); + end + INSTR_CVSLLH , + INSTR_CVSLLSCH , + INSTR_CVSLLSCIH, + INSTR_CVSLLB , + INSTR_CVSLLSCB , + INSTR_CVSLLSCIB : begin + mnemonic = "cv.sll"; + str_imm = $sformatf("0x%0h", imm_vs_type); + end + INSTR_CVORH , + INSTR_CVORSCH , + INSTR_CVORSCIH, + INSTR_CVORB , + INSTR_CVORSCB , + INSTR_CVORSCIB : begin + mnemonic = "cv.or"; + str_imm = $sformatf("0x%0h", imm_vs_type); + end + INSTR_CVXORH , + INSTR_CVXORSCH , + INSTR_CVXORSCIH , + INSTR_CVXORB , + INSTR_CVXORSCB , + INSTR_CVXORSCIB : begin + mnemonic = "cv.xor"; + str_imm = $sformatf("0x%0h", imm_vs_type); + end + INSTR_CVANDH , + INSTR_CVANDSCH , + INSTR_CVANDSCIH , + INSTR_CVANDB , + INSTR_CVANDSCB , + INSTR_CVANDSCIB : begin + mnemonic = "cv.and"; + str_imm = $sformatf("0x%0h", imm_vs_type); + end + INSTR_CVABSH, + INSTR_CVABSB : begin + mnemonic = "cv.abs"; + str_imm = $sformatf("0x%0h", imm_vs_type); + end + // dot products + INSTR_CVDOTUPH , + INSTR_CVDOTUPSCH , + INSTR_CVDOTUPSCIH, + INSTR_CVDOTUPB , + INSTR_CVDOTUPSCB , + INSTR_CVDOTUPSCIB : begin + mnemonic = "cv.dotup"; + str_imm = $sformatf("0x%0h", imm_vu_type); + end + INSTR_CVDOTUSPH , + INSTR_CVDOTUSPSCH , + INSTR_CVDOTUSPSCIH, + INSTR_CVDOTUSPB , + INSTR_CVDOTUSPSCB , + INSTR_CVDOTUSPSCIB : begin + mnemonic = "cv.dotusp"; + str_imm = $sformatf("0x%0h", imm_vs_type); + end + INSTR_CVDOTSPH , + INSTR_CVDOTSPSCH , + INSTR_CVDOTSPSCIH, + INSTR_CVDOTSPB , + INSTR_CVDOTSPSCB , + INSTR_CVDOTSPSCIB : begin + mnemonic = "cv.dotsp"; + str_imm = $sformatf("0x%0h", imm_vs_type); + end + INSTR_CVSDOTUPH , + INSTR_CVSDOTUPSCH , + INSTR_CVSDOTUPSCIH, + INSTR_CVSDOTUPB , + INSTR_CVSDOTUPSCB , + INSTR_CVSDOTUPSCIB : begin + mnemonic = "cv.sdotup"; + str_imm = $sformatf("0x%0h", imm_vu_type); + end + INSTR_CVSDOTUSPH , + INSTR_CVSDOTUSPSCH , + INSTR_CVSDOTUSPSCIH, + INSTR_CVSDOTUSPB , + INSTR_CVSDOTUSPSCB , + INSTR_CVSDOTUSPSCIB : begin + mnemonic = "cv.sdotusp"; + str_imm = $sformatf("0x%0h", imm_vs_type); + end + INSTR_CVSDOTSPH , + INSTR_CVSDOTSPSCH , + INSTR_CVSDOTSPSCIH, + INSTR_CVSDOTSPB , + INSTR_CVSDOTSPSCB , + INSTR_CVSDOTSPSCIB : begin + mnemonic = "cv.sdotsp"; + str_imm = $sformatf("0x%0h", imm_vs_type); + end + + INSTR_CVEXTRACTH, + INSTR_CVEXTRACTB : begin + mnemonic = "cv.extract"; + str_imm = $sformatf("0x%0h", imm_vs_type); + str_sci = ""; + end + INSTR_CVEXTRACTUH, + INSTR_CVEXTRACTUB : begin + mnemonic = "cv.extractu"; + str_imm = $sformatf("0x%0h", imm_vu_type); + str_sci = ""; + end + INSTR_CVINSERTH, + INSTR_CVINSERTB : begin + mnemonic = "cv.insert"; + str_imm = $sformatf("0x%0h", imm_vs_type); + str_sci = ""; + end + + // shuffle/pack + INSTR_CVSHUFFLEH , + INSTR_CVSHUFFLESCIH, + INSTR_CVSHUFFLEB : begin + mnemonic = "cv.shuffle"; + if (instr[14:12] == 3'b110) begin + str_imm = $sformatf("0x%8h", imm_shuffle_type); + end + end + + INSTR_CVSHUFFLEL0SCIB : begin + mnemonic = "cv.shuffleI0"; + str_imm = $sformatf("0x%8h", imm_shuffle_type); + end + INSTR_CVSHUFFLEL1SCIB : begin + mnemonic = "cv.shuffleI1"; + str_imm = $sformatf("0x%8h", imm_shuffle_type); + end + INSTR_CVSHUFFLEL2SCIB : begin + mnemonic = "cv.shuffleI2"; + str_imm = $sformatf("0x%8h", imm_shuffle_type); + end + INSTR_CVSHUFFLEL3SCIB : begin + mnemonic = "cv.shuffleI3"; + str_imm = $sformatf("0x%8h", imm_shuffle_type); + end + INSTR_CVSHUFFLE2H, + INSTR_CVSHUFFLE2B : begin + mnemonic = "cv.shuffle2"; + end + INSTR_CVPACK, + INSTR_CVPACKH : begin + mnemonic = "cv.pack"; + if (instr[25] == 1'b0) begin + str_hb = ""; + end + end + INSTR_CVPACKHIB : mnemonic = "cv.packhi"; + INSTR_CVPACKLOB : mnemonic = "cv.packlo"; + + // comparisons + INSTR_CVCMPEQH , + INSTR_CVCMPEQSCH , + INSTR_CVCMPEQSCIH, + INSTR_CVCMPEQB , + INSTR_CVCMPEQSCB , + INSTR_CVCMPEQSCIB : begin + mnemonic = "cv.cmpeq"; + str_imm = $sformatf("0x%0h", imm_vs_type); + end + INSTR_CVCMPNEH , + INSTR_CVCMPNESCH , + INSTR_CVCMPNESCIH, + INSTR_CVCMPNEB , + INSTR_CVCMPNESCB , + INSTR_CVCMPNESCIB : begin + mnemonic = "cv.cmpne"; + str_imm = $sformatf("0x%0h", imm_vs_type); + end + INSTR_CVCMPGTH , + INSTR_CVCMPGTSCH , + INSTR_CVCMPGTSCIH, + INSTR_CVCMPGTB , + INSTR_CVCMPGTSCB , + INSTR_CVCMPGTSCIB : begin + mnemonic = "cv.cmpgt"; + str_imm = $sformatf("0x%0h", imm_vs_type); + end + INSTR_CVCMPGEH , + INSTR_CVCMPGESCH , + INSTR_CVCMPGESCIH, + INSTR_CVCMPGEB , + INSTR_CVCMPGESCB , + INSTR_CVCMPGESCIB : begin + mnemonic = "cv.cmpge"; + str_imm = $sformatf("0x%0h", imm_vs_type); + end + INSTR_CVCMPLTH , + INSTR_CVCMPLTSCH , + INSTR_CVCMPLTSCIH, + INSTR_CVCMPLTB , + INSTR_CVCMPLTSCB , + INSTR_CVCMPLTSCIB : begin + mnemonic = "cv.cmplt"; + str_imm = $sformatf("0x%0h", imm_vs_type); + end + INSTR_CVCMPLEH , + INSTR_CVCMPLESCH , + INSTR_CVCMPLESCIH, + INSTR_CVCMPLEB , + INSTR_CVCMPLESCB , + INSTR_CVCMPLESCIB : begin + mnemonic = "cv.cmple"; + str_imm = $sformatf("0x%0h", imm_vs_type); + end + INSTR_CVCMPGTUH , + INSTR_CVCMPGTUSCH , + INSTR_CVCMPGTUSCIH, + INSTR_CVCMPGTUB , + INSTR_CVCMPGTUSCB , + INSTR_CVCMPGTUSCIB : begin + mnemonic = "cv.cmpgtu"; + str_imm = $sformatf("0x%0h", imm_vu_type); + end + INSTR_CVCMPGEUH , + INSTR_CVCMPGEUSCH , + INSTR_CVCMPGEUSCIH, + INSTR_CVCMPGEUB , + INSTR_CVCMPGEUSCB , + INSTR_CVCMPGEUSCIB : begin + mnemonic = "cv.cmpgeu"; + str_imm = $sformatf("0x%0h", imm_vu_type); + end + INSTR_CVCMPLTUH , + INSTR_CVCMPLTUSCH , + INSTR_CVCMPLTUSCIH, + INSTR_CVCMPLTUB , + INSTR_CVCMPLTUSCB , + INSTR_CVCMPLTUSCIB : begin + mnemonic = "cv.cmpltu"; + str_imm = $sformatf("0x%0h", imm_vu_type); + end + INSTR_CVCMPLEUH , + INSTR_CVCMPLEUSCH , + INSTR_CVCMPLEUSCIH, + INSTR_CVCMPLEUB , + INSTR_CVCMPLEUSCB , + INSTR_CVCMPLEUSCIB : begin + mnemonic = "cv.cmpleu"; + str_imm = $sformatf("0x%0h", imm_vu_type); + end + + INSTR_CVCPLXMULR, + INSTR_CVCPLXMULI : begin + mnemonic = instr[25] == 1'b0 ? "cv.cplxmul.r" : "cv.cplxmul.i"; + str_sci = ""; + str_hb = ""; + end + INSTR_CVCPLXMULRDIV2, + INSTR_CVCPLXMULIDIV2 : begin + mnemonic = instr[25] == 1'b0 ? "cv.cplxmul.r.div2" : "cv.cplxmul.i.div2"; + str_sci = ""; + str_hb = ""; + end + INSTR_CVCPLXMULRDIV4, + INSTR_CVCPLXMULIDIV4 : begin + mnemonic = instr[25] == 1'b0 ? "cv.cplxmul.r.div4" : "cv.cplxmul.i.div4"; + str_sci = ""; + str_hb = ""; + end + INSTR_CVCPLXMULRDIV8, + INSTR_CVCPLXMULIDIV8 : begin + mnemonic = instr[25] == 1'b0 ? "cv.cplxmul.r.div8" : "cv.cplxmul.i.div8"; + str_sci = ""; + str_hb = ""; + end + + INSTR_CVCPLXCONJ : begin + mnemonic = "cv.cplxconj"; + str_sci = ""; + str_hb = ""; + end + + INSTR_CVSUBROTMJ : begin + mnemonic = "cv.subrotmj"; + str_sci = ""; + str_hb = ""; + end + INSTR_CVSUBROTMJDIV2 : begin + mnemonic = "cv.subrotmj.div2"; + str_sci = ""; + str_hb = ""; + end + INSTR_CVSUBROTMJDIV4 : begin + mnemonic = "cv.subrotmj.div4"; + str_sci = ""; + str_hb = ""; + end + INSTR_CVSUBROTMJDIV8 : begin + mnemonic = "cv.subrotmj.div8"; + str_sci = ""; + str_hb = ""; + end + + INSTR_CVADDIV2 : begin + mnemonic = "cv.add.div2"; + str_sci = ""; + str_hb = ""; + end + INSTR_CVADDIV4 : begin + mnemonic = "cv.add.div4"; + str_sci = ""; + str_hb = ""; + end + INSTR_CVADDIV8 : begin + mnemonic = "cv.add.div8"; + str_sci = ""; + str_hb = ""; + end + + INSTR_CVSUBIV2 : begin + mnemonic = "cv.sub.div2"; + str_sci = ""; + str_hb = ""; + end + INSTR_CVSUBIV4 : begin + mnemonic = "cv.sub.div4"; + str_sci = ""; + str_hb = ""; + end + INSTR_CVSUBIV8 : begin + mnemonic = "cv.sub.div8"; + str_sci = ""; + str_hb = ""; + end + + default: begin + printMnemonic("INVALID"); + return; + end + endcase + + if (mnemonic == "cv.cplxconj") begin + //special case, one operand only + str_args = $sformatf("%s, %s", regAddrToStr(rd), regAddrToStr(rs1)); + end else begin + if (str_sci == "") begin + regs_read.push_back('{rs2, rs2_value, 0}); + str_args = $sformatf("%s, %s, %s", regAddrToStr(rd), regAddrToStr(rs1), regAddrToStr(rs2)); + end else if (str_sci == ".sc") begin + regs_read.push_back('{rs2, rs2_value_vec, 0}); + str_args = $sformatf("%s, %s, %s", regAddrToStr(rd), regAddrToStr(rs1), regAddrToStr(rs2)); + end else if (str_sci == ".sci") begin + str_args = $sformatf("%s, %s, %s", regAddrToStr(rd), regAddrToStr(rs1), str_imm); + end + end + + str_asm = $sformatf("%s%s%s", mnemonic, str_sci, str_hb); + + str = $sformatf("%-16s %s", str_asm, str_args); + end + endfunction +endclass diff --git a/target/verilator/src/cv32e40p_tracer.sv b/target/verilator/src/cv32e40p_tracer.sv index 0abd2b96..f6809d3c 100644 --- a/target/verilator/src/cv32e40p_tracer.sv +++ b/target/verilator/src/cv32e40p_tracer.sv @@ -9,8 +9,9 @@ // // It is picked up because the flow's makefile puts target/verilator/src on the // include path ahead of the cv32e40p checkout's bhv/, and cv32e40p_wrapper.sv -// pulls the tracer in as `include "cv32e40p_tracer.sv"`. Both changes are -// marked "MAGIA verilator:" below. Re-vendorize on any cv32e40p bump. +// pulls the tracer in as `include "cv32e40p_tracer.sv"`. All changes are +// marked "MAGIA verilator:" below; the trace class is vendorized next to it +// (cv32e40p_instr_trace.svh). Re-vendorize both on any cv32e40p bump. // --------------------------------------------------------------------------- // Copyright 2018 ETH Zurich and University of Bologna. @@ -269,6 +270,30 @@ module cv32e40p_tracer instr_trace_t trace; trace = new(); + // MAGIA verilator: hand this instance's state to the object, see cv32e40p_instr_trace.svh + trace.f = f; + trace.rd = rd; + trace.rs1 = rs1; + trace.rs2 = rs2; + trace.rs3 = rs3; + trace.rs4 = rs4; + trace.rs1_value = rs1_value; + trace.rs2_value = rs2_value; + trace.rs2_value_vec = rs2_value_vec; + trace.rs3_value = rs3_value; + trace.imm_u_type = imm_u_type; + trace.imm_uj_type = imm_uj_type; + trace.imm_i_type = imm_i_type; + trace.imm_iz_type = imm_iz_type; + trace.imm_z_type = imm_z_type; + trace.imm_s_type = imm_s_type; + trace.imm_sb_type = imm_sb_type; + trace.imm_s2_type = imm_s2_type; + trace.imm_s3_type = imm_s3_type; + trace.imm_vs_type = imm_vs_type; + trace.imm_vu_type = imm_vu_type; + trace.imm_shuffle_type = imm_shuffle_type; + trace.imm_clip_type = imm_clip_type; trace.init(.cycles(cycles), .pc(pc), .compressed(compressed), .instr(instr)); return trace; diff --git a/target/verilator/src/cv32e40x_rvfi_sim_trace.sv b/target/verilator/src/cv32e40x_rvfi_sim_trace.sv new file mode 100644 index 00000000..2cf42098 --- /dev/null +++ b/target/verilator/src/cv32e40x_rvfi_sim_trace.sv @@ -0,0 +1,247 @@ +// VENDORIZED COPY for the Questa and Verilator flows: cv32e40x bhv/cv32e40x_rvfi_sim_trace.sv at rev a9010121 plus the "MAGIA" changes +// Copyright 2022 Silicon Labs, Inc. +// +// This file, and derivatives thereof are licensed under the +// Solderpad License, Version 2.0 (the "License"); +// Use of this file means you agree to the terms and conditions +// of the license and are in full compliance with the License. +// You may obtain a copy of the License at +// +// https://solderpad.org/licenses/SHL-2.0/ +// +// Unless required by applicable law or agreed to in writing, software +// and hardware implementations thereof +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESSED OR IMPLIED. +// See the License for the specific language governing permissions and +// limitations under the License. + +//////////////////////////////////////////////////////////////////////////////// +// // +// Authors: Oivind Ekelund - oivind.ekelund@silabs.com // +// // +// Description: RVFI tracer. // +// Parses itb file and generates trace based on retired // +// instruction address // +// The path of the .itb file is given using the plusarg // +// defined by ITB_PLUSARG // +// // +//////////////////////////////////////////////////////////////////////////////// + +module cv32e40x_rvfi_sim_trace + import cv32e40x_rvfi_pkg::*; + #(parameter string ITB_PLUSARG = "itb_file", + parameter string LOGFILE_PATH_PLUSARG = "log_file", + parameter logic ITRACE_ENABLE = 1) + ( + // MAGIA: bound with .* into cv32e40x_rvfi, so the hart id names the log at run time + input logic rst_ni, + input logic [31:0] csr_mhartid_i, + input logic rvfi_valid, + input logic [31:0] rvfi_pc_rdata, + input logic [4:0] rvfi_rs1_addr, + input logic [31:0] rvfi_rs1_rdata, + input logic [4:0] rvfi_rs2_addr, + input logic [31:0] rvfi_rs2_rdata, + input logic [4:0] rvfi_rd_addr, + input logic [31:0] rvfi_rd_wdata, + input logic [32*NMEM-1:0] rvfi_mem_addr , + input logic [ 4*NMEM-1:0] rvfi_mem_rmask, + input logic [ 4*NMEM-1:0] rvfi_mem_wmask, + input logic [32*NMEM-1:0] rvfi_mem_rdata, + input logic [32*NMEM-1:0] rvfi_mem_wdata + ); + + typedef struct { + string c_file; + string c_func; + int c_line; + logic[31:0] addr; + logic[31:0] mcode; + string asm; + } trace_t; + + localparam trace_t TRACE_UNKNOWN = '{c_func : "NA", + c_file : "NA", + c_line : -1, + addr : 'x, + mcode : 'x, + asm : "NA"}; + + trace_t itrace, tmp_trace; + trace_t imap[int]; + int file, logfile; + int elements_found, asmlen, num_memop, num_trace_lines; + string filename, logfilename, line; + string logfile_plusarg; + string words[$]; + int num_words; + string asms[5]; + string asm_string, rvfi_info_string; + bit itb_file_ok, logfile_ok; + + // MAGIA verilator: Verilator's $sscanf returns -1 when a line has fewer fields than the format, so split by hand + function automatic int split_words(string text, ref string words[$]); + string word; + words = {}; + word = ""; + for (int i = 0; i < text.len(); i++) begin + // Carriage return as "\015": "\r" is not an IEEE 1800 escape and Questa reads it as 'r' + if (text[i] inside {" ", "\t", "\n", "\015"}) begin + if (word.len() > 0) words.push_back(word); + word = ""; + end else begin + word = {word, text.substr(i, i)}; + end + end + if (word.len() > 0) words.push_back(word); + return words.size(); + endfunction : split_words + + // Return number of memory operations based on rvfi_mem_rmask/wmask + function int get_num_memop(bit [4*NMEM-1:0] rvfi_mem_mask); + + int num_memop; + num_memop = 0; + + for (int i=0; i 0 ? num_memop : 1; + + for (int unsigned i_trace=0; i_trace < num_trace_lines; i_trace++) begin + rvfi_info_string = $sformatf( + "0x%8h | x%-2d (0x%8h) | x%-2d (0x%8h) | x%-2d (0x%8h) | 0x%8h | 0x%4b | 0x%8h | 0x%4b | 0x%8h || ", + rvfi_pc_rdata, + rvfi_rs1_addr, rvfi_rs1_rdata, + rvfi_rs2_addr, rvfi_rs2_rdata, + rvfi_rd_addr, rvfi_rd_wdata, + rvfi_mem_addr[i_trace*32+:32], + rvfi_mem_rmask[i_trace*4+:4], rvfi_mem_rdata[i_trace*32+:32], + rvfi_mem_wmask[i_trace*4+:4], rvfi_mem_wdata[i_trace*32+:32]); + asm_string = $sformatf("%-s %-s", rvfi_info_string, string'(itrace.asm)); + $fdisplay(logfile, asm_string); + asm_string = ""; + end + end + + end + end + + // Parse the listing file + initial begin + + // MAGIA: one plusarg per hart (log_file_), so every tile of the mesh writes its own trace + wait (rst_ni === 1'b0); + wait (rst_ni === 1'b1); + logfile_plusarg = $sformatf("%s_%0d", LOGFILE_PATH_PLUSARG, csr_mhartid_i); + $display("RISC-V Trace: Using log file path defined by plusarg: %s", logfile_plusarg); + if (!$value$plusargs({logfile_plusarg,"=%s"}, logfilename)) begin + $display($sformatf("Not generating instruction trace log file, please supply +%0s= if desired.", logfile_plusarg)); + end + else begin + logfile = $fopen(logfilename, "w"); + if (logfile == 0) begin + $warning("RISC-V Trace: Failed to open log file: %0s", logfilename); + logfile_ok = 1'b0; + end + else begin + $display("RISC-V Trace: Writing log to: %s", logfilename); + + logfile_ok = 1'b1; + $fdisplay(logfile, {$sformatf("%-10s | %-3s (%-10s) | %-3s (%-10s) | %-3s (%-10s) | ", + "pc", "rs1", " data", "rs2", " data", "rd", " data"), + $sformatf("%-10s | %-6s | %-10s | %-6s | %-10s || Assembly", + "memaddr", "rmask", "rdata", "wmask", "wdata") + }); + $fdisplay(logfile, {$sformatf("=================================================================="), + $sformatf("==========================================================================")}); + end + end + + $display("RISC-V Trace: Using itb path defined by plusarg: %s", ITB_PLUSARG); + if (!$value$plusargs({ITB_PLUSARG,"=%s"}, filename)) begin + $display("RISC-V Trace: No instruction table file found."); + end + else begin + + file = $fopen(filename, "r"); + + if (file == 0) begin + $display("RISC-V Trace: Failed to open instruction table file %s", filename); + itb_file_ok = 1'b0; + end + else begin + + $display("RISC-V Trace: Loading instruction table file %s", filename); + itb_file_ok = 1'b1; + + // Iterate through itb file + while ($fgets(line, file)) begin + // Skip comments + if(line[0] != "#") begin + + // Search for expected pattern in line + // MAGIA verilator: the six fixed fields with $sscanf, the assembly words by hand + elements_found = $sscanf(line, "%d %s %s %d %h %d", + tmp_trace.addr, tmp_trace.c_func, tmp_trace.c_file, tmp_trace.c_line, tmp_trace.mcode, asmlen); + if (elements_found == 6) begin + num_words = split_words(line, words); + for (int i = 0; i < 5; i++) asms[i] = (6 + i < num_words) ? words[6 + i] : ""; + elements_found = 6 + ((num_words - 6 < 5) ? num_words - 6 : 5); + end + + if (elements_found > 6) begin + // Fetch assembly instruction + for (int i=0; i < asmlen; i++) begin + if(asms[i] == "#") break; // Disregard comments + + // Concatenate assembly instruction + $cast(tmp_trace.asm, $sformatf("%-0s %-0s", tmp_trace.asm, asms[i])); + end + + imap[tmp_trace.addr] = tmp_trace; + tmp_trace.asm = ""; + end + end + end + end + $fclose(file); + $display("RISC-V Trace: Loaded %d instructions.", imap.size()); + end + end + + final begin + if (logfile_ok) begin + $fclose(logfile); + end + end + end + end + endgenerate +endmodule diff --git a/target/verilator/src/cv32e40x_wrapper.sv b/target/verilator/src/cv32e40x_wrapper.sv new file mode 100644 index 00000000..fbae24a0 --- /dev/null +++ b/target/verilator/src/cv32e40x_wrapper.sv @@ -0,0 +1,874 @@ +// VENDORIZED COPY for the Questa and Verilator flows: cv32e40x bhv/cv32e40x_wrapper.sv at rev a9010121 plus the "MAGIA" changes +// Copyright 2018 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +// Wrapper for a cv32e40x, containing cv32e40x and RVFI +// Contributors: Davide Schiavone +// Halfdan Bechmann + +`ifndef COREV_ASSERT_OFF + `include "cv32e40x_alignment_buffer_sva.sv" + `include "cv32e40x_controller_fsm_sva.sv" + `include "cv32e40x_core_sva.sv" + `include "cv32e40x_cs_registers_sva.sv" + `include "cv32e40x_decoder_sva.sv" + `include "cv32e40x_div_sva.sv" + `include "cv32e40x_if_stage_sva.sv" + `include "cv32e40x_id_stage_sva.sv" + `include "cv32e40x_ex_stage_sva.sv" + `include "cv32e40x_wb_stage_sva.sv" + `include "cv32e40x_load_store_unit_sva.sv" + `include "cv32e40x_write_buffer_sva.sv" + `include "cv32e40x_lsu_response_filter_sva.sv" + `include "cv32e40x_mpu_sva.sv" + `include "cv32e40x_mult_sva.sv" + `include "cv32e40x_prefetcher_sva.sv" + `include "cv32e40x_prefetch_unit_sva.sv" + `include "cv32e40x_sleep_unit_sva.sv" + `include "cv32e40x_rvfi_sva.sv" + `include "cv32e40x_sequencer_sva.sv" + `include "cv32e40x_clic_int_controller_sva.sv" + `include "cv32e40x_register_file_sva.sv" + `include "cv32e40x_wpt_sva.sv" + `include "cv32e40x_debug_triggers_sva.sv" +`endif + +`include "cv32e40x_wrapper.vh" +`include "cv32e40x_core_log.sv" +`include "cv32e40x_dbg_helper.sv" + +`ifdef RISCV_FORMAL + `include "rvfi_macros.vh" +`endif + +module cv32e40x_wrapper + import cv32e40x_pkg::*; +#( + parameter LIB = 0, + parameter rv32_e RV32 = RV32I, + parameter a_ext_e A_EXT = A_NONE, + parameter b_ext_e B_EXT = B_NONE, + parameter m_ext_e M_EXT = M, + parameter bit X_EXT = 0, + parameter int unsigned X_NUM_RS = 2, + parameter int unsigned X_ID_WIDTH = 4, + parameter int unsigned X_MEM_WIDTH = 32, + parameter int unsigned X_RFR_WIDTH = 32, + parameter int unsigned X_RFW_WIDTH = 32, + parameter logic [31:0] X_MISA = 32'h00000000, + parameter logic [1:0] X_ECS_XS = 2'b00, + parameter int unsigned NUM_MHPMCOUNTERS = 1, + parameter bit CLIC = 0, + parameter int unsigned CLIC_ID_WIDTH = 5, + parameter int DBG_NUM_TRIGGERS = 1, + parameter int PMA_NUM_REGIONS = 0, + parameter pma_cfg_t PMA_CFG[PMA_NUM_REGIONS-1:0] = '{default:PMA_R_DEFAULT}, + parameter bit CORE_LOG_ENABLE = 1, + parameter bit DEBUG = 1, + parameter logic [31:0] DM_REGION_START = 32'hF0000000, + parameter logic [31:0] DM_REGION_END = 32'hF0003FFF +) +( + // Clock and Reset + input logic clk_i, + input logic rst_ni, + + input logic scan_cg_en_i, // Enable all clock gates for testing + + // Core ID, Cluster ID, debug mode halt address and boot address are considered more or less static + input logic [31:0] boot_addr_i, + input logic [31:0] mtvec_addr_i, + input logic [31:0] dm_halt_addr_i, + input logic [31:0] mhartid_i, + input logic [3:0] mimpid_patch_i, + input logic [31:0] dm_exception_addr_i, + + // Instruction memory interface + output logic instr_req_o, + input logic instr_gnt_i, + input logic instr_rvalid_i, + output logic [31:0] instr_addr_o, + output logic [1:0] instr_memtype_o, + output logic [2:0] instr_prot_o, + output logic instr_dbg_o, + input logic [31:0] instr_rdata_i, + input logic instr_err_i, + + // Data memory interface + output logic data_req_o, + input logic data_gnt_i, + input logic data_rvalid_i, + output logic data_we_o, + output logic [3:0] data_be_o, + output logic [31:0] data_addr_o, + output logic [1:0] data_memtype_o, + output logic [2:0] data_prot_o, + output logic data_dbg_o, + output logic [31:0] data_wdata_o, + input logic [31:0] data_rdata_i, + input logic data_err_i, + output logic [5:0] data_atop_o, + input logic data_exokay_i, + + // Cycle Count + output logic [63:0] mcycle_o, + + // Time input + input logic [63:0] time_i, + + // eXtension interface + cv32e40x_if_xif.cpu_compressed xif_compressed_if, + cv32e40x_if_xif.cpu_issue xif_issue_if, + cv32e40x_if_xif.cpu_commit xif_commit_if, + cv32e40x_if_xif.cpu_mem xif_mem_if, + cv32e40x_if_xif.cpu_mem_result xif_mem_result_if, + cv32e40x_if_xif.cpu_result xif_result_if, + + // Interrupt inputs + input logic [31:0] irq_i, // CLINT interrupts + CLINT extension interrupts + + // WFE input + input logic wu_wfe_i, + + // CLIC Interface + input logic clic_irq_i, + input logic [CLIC_ID_WIDTH-1:0] clic_irq_id_i, + input logic [ 7:0] clic_irq_level_i, + input logic [ 1:0] clic_irq_priv_i, + input logic clic_irq_shv_i, + + + // Fencei flush handshake + output logic fencei_flush_req_o, + input logic fencei_flush_ack_i, + // Debug Interface + input logic debug_req_i, + output logic debug_havereset_o, + output logic debug_running_o, + output logic debug_halted_o, + output logic debug_pc_valid_o, + output logic [31:0] debug_pc_o, + + // CPU Control Signals + input logic fetch_enable_i, + output logic core_sleep_o + +`ifdef RISCV_FORMAL + ,`RVFI_OUTPUTS +`endif +); + + +`ifndef COREV_ASSERT_OFF + + // RTL Assertions + + bind cv32e40x_if_stage: + core_i.if_stage_i cv32e40x_if_stage_sva #(.CLIC(CLIC)) if_stage_sva + ( + .m_c_obi_instr_if (core_i.m_c_obi_instr_if), // SVA monitor modport cannot connect to a master modport + .* + ); + + bind cv32e40x_id_stage: + core_i.id_stage_i cv32e40x_id_stage_sva #(.RV32(RV32)) id_stage_sva + ( + .jmp_taken_id_ctrl_i (core_i.controller_i.controller_fsm_i.jump_taken_id), + .* + ); + + bind cv32e40x_ex_stage: + core_i.ex_stage_i cv32e40x_ex_stage_sva #(.X_EXT(X_EXT)) ex_stage_sva + ( + .branch_taken_ex_ctrl_i (core_i.controller_i.controller_fsm_i.branch_taken_ex), + .wb_valid_i (core_i.wb_valid ), + .* + ); + + bind cv32e40x_wb_stage: + core_i.wb_stage_i cv32e40x_wb_stage_sva #(.DEBUG(DEBUG)) wb_stage_sva + ( + .* + ); + + bind cv32e40x_id_stage: + core_i.id_stage_i + cv32e40x_dbg_helper + dbg_help_i(.is_compressed (if_id_pipe_i.instr_meta.compressed), + .rf_re (core_i.rf_re_id ), + .rf_raddr (core_i.rf_raddr_id ), + .rf_we (core_i.id_stage_i.rf_we ), + .rf_waddr (core_i.id_stage_i.rf_waddr ), + .illegal_insn (core_i.id_stage_i.illegal_insn ), + .*); + + bind cv32e40x_register_file: + core_i.register_file_wrapper_i.register_file_i cv32e40x_register_file_sva #(.RV32(RV32)) + register_file_sva + (.*); + + generate + if(M_EXT != M_NONE) begin: mul_sva + bind cv32e40x_mult: + core_i.ex_stage_i.mul.mult_i cv32e40x_mult_sva mult_sva (.*); + end + endgenerate + + bind cv32e40x_controller_fsm: + core_i.controller_i.controller_fsm_i + cv32e40x_controller_fsm_sva + #(.X_EXT(X_EXT), + .DEBUG(DEBUG), + .CLIC(CLIC), + .CLIC_ID_WIDTH(CLIC_ID_WIDTH), + .RV32(RV32)) + controller_fsm_sva ( + .lsu_outstanding_cnt (core_i.load_store_unit_i.cnt_q), + .rf_we_wb_i (core_i.wb_stage_i.rf_we_wb_o ), + .csr_we_i (core_i.cs_registers_i.csr_we_int ), + .csr_illegal_i (core_i.cs_registers_i.csr_illegal_o), + .xif_commit_kill (core_i.xif_commit_if.commit.commit_kill), + .xif_commit_valid (core_i.xif_commit_if.commit_valid), + .first_op_if_i (core_i.if_stage_i.first_op), + .first_op_ex_i (core_i.ex_stage_i.first_op), + .prefetch_valid_if_i (core_i.if_stage_i.prefetch_valid), + .prefetch_is_tbljmp_ptr_if_i (core_i.if_stage_i.prefetch_is_tbljmp_ptr), + .prefetch_is_mret_ptr_if_i (core_i.if_stage_i.prefetch_is_mret_ptr), + .lsu_trans_valid_i (core_i.load_store_unit_i.trans_valid), + .csr_en_id_i (core_i.id_stage_i.csr_en), + .ptr_in_if_i (core_i.if_stage_i.ptr_in_if_o), + .instr_req_o (core_i.instr_req_o), + .instr_dbg_o (core_i.instr_dbg_o), + .mstatus_i (core_i.cs_registers_i.mstatus_rdata), + .rf_mem_i (core_i.register_file_wrapper_i.register_file_i.mem), + .alu_jmpr_id_i (core_i.alu_jmpr_id), + .jalr_fw_id_i (core_i.id_stage_i.jalr_fw), + .response_filter_bus_cnt_q_i (core_i.load_store_unit_i.response_filter_i.bus_cnt_q), + .*); + bind cv32e40x_cs_registers: + core_i.cs_registers_i + cv32e40x_cs_registers_sva + #(.CLIC (CLIC), + .DEBUG (DEBUG)) + cs_registers_sva (.wb_valid_i (core_i.wb_valid ), + .ctrl_fsm_cs (core_i.controller_i.controller_fsm_i.ctrl_fsm_cs), + .*); + + + bind cv32e40x_load_store_unit: + core_i.load_store_unit_i cv32e40x_load_store_unit_sva #(.DEPTH (DEPTH), .DEBUG(DEBUG), .A_EXT(A_EXT)) load_store_unit_sva ( + // The SVA's monitor modport can't connect to a master modport, so it is connected to the interface instance directly: + .m_c_obi_data_if(core_i.m_c_obi_data_if), + .ex_wb_pipe_i (core_i.ex_wb_pipe), + .write_buffer_state_i (core_i.load_store_unit_i.write_buffer_i.state), + .id_valid (core_i.id_valid), + .ex_ready (core_i.ex_ready), + .lsu_en_id (core_i.id_stage_i.lsu_en), + .ctrl_fsm_cs (core_i.controller_i.controller_fsm_i.ctrl_fsm_cs), + .ctrl_fsm_ns (core_i.controller_i.controller_fsm_i.ctrl_fsm_ns), + .mpu_err_i (core_i.load_store_unit_i.mpu_i.mpu_err), + .align_err_i (core_i.load_store_unit_i.align_check_i.align_err), + .*); + + generate + if (DBG_NUM_TRIGGERS > 0) begin : debug_sva + bind cv32e40x_wpt: + core_i.load_store_unit_i.gen_wpt.wpt_i + cv32e40x_wpt_sva wpt_sva( + .mpu_state (core_i.load_store_unit_i.mpu_i.state_q), + .*); + + bind cv32e40x_debug_triggers: + core_i.cs_registers_i.debug_triggers_i + cv32e40x_debug_triggers_sva + #(.DBG_NUM_TRIGGERS(DBG_NUM_TRIGGERS), + .A_EXT (A_EXT)) + debug_triggers_sva (.csr_wdata (core_i.cs_registers_i.csr_wdata), + .csr_waddr (core_i.cs_registers_i.csr_waddr), + .csr_op (core_i.cs_registers_i.csr_op), + .ex_wb_pipe_i (core_i.ex_wb_pipe), + .tselect_q (core_i.cs_registers_i.debug_triggers_i.gen_triggers.tselect_q), + .tdata1_q (core_i.cs_registers_i.debug_triggers_i.gen_triggers.tdata1_q), + .tdata2_q (core_i.cs_registers_i.debug_triggers_i.gen_triggers.tdata2_q), + .lsu_addr_match_en (core_i.cs_registers_i.debug_triggers_i.gen_triggers.lsu_addr_match_en), + .trigger_match_if_wb (core_i.ex_wb_pipe.trigger_match), + .trigger_match_ex_wb (core_i.wpt_match_wb), + .wb_valid_i (core_i.wb_valid), + .*); + end + endgenerate + bind cv32e40x_prefetch_unit: + core_i.if_stage_i.prefetch_unit_i + cv32e40x_prefetch_unit_sva + #(.CLIC(CLIC)) + prefetch_unit_sva ( + .ctrl_fsm_cs (core_i.controller_i.controller_fsm_i.ctrl_fsm_cs), + .debug_req_i (core_i.debug_req_i), + .*); + + generate + if(M_EXT == M) begin: div_sva + bind cv32e40x_div: + core_i.ex_stage_i.div.div_i cv32e40x_div_sva div_sva (.*); + end + endgenerate + + bind cv32e40x_alignment_buffer: + core_i.if_stage_i.prefetch_unit_i.alignment_buffer_i + cv32e40x_alignment_buffer_sva + alignment_buffer_sva (.*); + + bind cv32e40x_prefetcher: + core_i.if_stage_i.prefetch_unit_i.prefetcher_i + cv32e40x_prefetcher_sva + #(.CLIC(CLIC)) + prefetcher_sva ( .prefetch_is_clic_ptr (core_i.if_stage_i.prefetch_unit_i.prefetch_is_clic_ptr_o), + .*); + + bind cv32e40x_core: + core_i cv32e40x_core_sva + #(.A_EXT(A_EXT), + .DEBUG(DEBUG), + .PMA_NUM_REGIONS(PMA_NUM_REGIONS), + .CLIC(CLIC), + .DBG_NUM_TRIGGERS(DBG_NUM_TRIGGERS)) + core_sva (// probed cs_registers signals + .cs_registers_mie_q (core_i.cs_registers_i.mie_q), + .cs_registers_mepc_n (core_i.cs_registers_i.mepc_n), + .cs_registers_mcause_q (core_i.cs_registers_i.mcause_q), + .cs_registers_mstatus_q (core_i.cs_registers_i.mstatus_q), + .cs_registers_csr_cause_i (core_i.cs_registers_i.ctrl_fsm_i.csr_cause), + .branch_taken_in_ex (core_i.controller_i.controller_fsm_i.branch_taken_ex), + .exc_cause (core_i.controller_i.controller_fsm_i.exc_cause), + // probed controller signals + .ctrl_debug_mode_n (core_i.controller_i.controller_fsm_i.debug_mode_n), + .ctrl_pending_async_debug (core_i.controller_i.controller_fsm_i.pending_async_debug), + .ctrl_async_debug_allowed (core_i.controller_i.controller_fsm_i.async_debug_allowed), + .ctrl_pending_sync_debug (core_i.controller_i.controller_fsm_i.pending_sync_debug), + .ctrl_sync_debug_allowed (core_i.controller_i.controller_fsm_i.sync_debug_allowed), + .ctrl_pending_interrupt (core_i.controller_i.controller_fsm_i.pending_interrupt), + .ctrl_interrupt_allowed (core_i.controller_i.controller_fsm_i.interrupt_allowed), + .ctrl_debug_cause_n (core_i.controller_i.controller_fsm_i.debug_cause_n), + .ctrl_pending_nmi (core_i.controller_i.controller_fsm_i.pending_nmi), + .ctrl_fsm_cs (core_i.controller_i.controller_fsm_i.ctrl_fsm_cs), + + .id_stage_id_valid (core_i.id_stage_i.id_valid_o), + .alu_op_a_mux_sel_id_i (core_i.id_stage_i.alu_op_a_mux_sel), + .alu_op_b_mux_sel_id_i (core_i.id_stage_i.alu_op_b_mux_sel), + .operand_a_id_i (core_i.id_stage_i.operand_a), + .operand_b_id_i (core_i.id_stage_i.operand_b), + .jalr_fw_id_i (core_i.id_stage_i.jalr_fw), + .alu_en_id_i (core_i.id_stage_i.alu_en), + .alu_jmpr_id_i (core_i.alu_jmpr_id), + .irq_ack (core_i.irq_ack), + .mie_n (core_i.cs_registers_i.mie_n), + .mie_we (core_i.cs_registers_i.mie_we), + .lsu_exception_wb (core_i.wb_stage_i.lsu_exception), + .lsu_wpt_match_wb (core_i.wb_stage_i.lsu_wpt_match), + .lsu_exokay_wb (core_i.load_store_unit_i.resp.bus_resp.exokay), + .prefetch_is_mret_ptr_i (core_i.if_stage_i.prefetch_is_mret_ptr), + .first_op_if (core_i.if_stage_i.first_op), + .xif_compressed_valid (core_i.xif_compressed_if.compressed_valid), + .xif_issue_valid (core_i.xif_issue_if.issue_valid), + .xif_commit_valid (core_i.xif_commit_if.commit_valid), + .xif_mem_ready (core_i.xif_mem_if.mem_ready), + .xif_mem_result_valid (core_i.xif_mem_result_if.mem_result_valid), + .xif_result_ready (core_i.xif_result_if.result_ready), + .lsu_cnt_q (core_i.load_store_unit_i.cnt_q), + .resp_filter_bus_cnt_q (core_i.load_store_unit_i.response_filter_i.bus_cnt_q), + .resp_filter_core_cnt_q (core_i.load_store_unit_i.response_filter_i.core_cnt_q), + .write_buffer_state (core_i.load_store_unit_i.write_buffer_i.state), + .*); +generate +if (CLIC) begin : clic_asserts + bind cv32e40x_clic_int_controller: + core_i.gen_clic_interrupt.clic_int_controller_i + cv32e40x_clic_int_controller_sva + clic_int_controller_sva (.ctrl_pending_interrupt (core_i.controller_i.controller_fsm_i.pending_interrupt), + .ctrl_interrupt_allowed (core_i.controller_i.controller_fsm_i.interrupt_allowed), + .ctrl_pending_nmi (core_i.controller_i.controller_fsm_i.pending_nmi), + .ctrl_pending_async_debug(core_i.controller_i.controller_fsm_i.pending_async_debug), + .ctrl_fsm_cs (core_i.controller_i.controller_fsm_i.ctrl_fsm_cs), + .ctrl_fsm (core_i.ctrl_fsm), + .dcsr (core_i.dcsr), + .*); +end +endgenerate + + bind cv32e40x_sleep_unit: + core_i.sleep_unit_i cv32e40x_sleep_unit_sva + sleep_unit_sva (// probed id_stage_i.controller_i signals + .ctrl_fsm_cs (core_i.controller_i.controller_fsm_i.ctrl_fsm_cs), + .ctrl_fsm_ns (core_i.controller_i.controller_fsm_i.ctrl_fsm_ns), + .*); + + bind cv32e40x_decoder: core_i.id_stage_i.decoder_i cv32e40x_decoder_sva #(.A_EXT(A_EXT)) + decoder_sva(.clk (core_i.id_stage_i.clk), + .rst_n (core_i.id_stage_i.rst_n), + .if_id_pipe (core_i.if_id_pipe), + .*); + + // MPU assertions + bind cv32e40x_mpu: + core_i.if_stage_i.mpu_i + cv32e40x_mpu_sva + #(.PMA_NUM_REGIONS (PMA_NUM_REGIONS), + .PMA_CFG (PMA_CFG), + .IS_INSTR_SIDE (1), + .CORE_RESP_TYPE (cv32e40x_pkg::inst_resp_t), + .CORE_REQ_TYPE (cv32e40x_pkg::obi_inst_req_t), + .DEBUG (DEBUG), + .DM_REGION_START (DM_REGION_START), + .DM_REGION_END (DM_REGION_END)) + mpu_if_sva(.pma_addr (pma_i.trans_addr_i), + .pma_cfg (pma_i.pma_cfg), + .pma_dbg (core_i.if_stage_i.mpu_i.core_trans_i.dbg), + .obi_memtype (core_i.instr_memtype_o), + .obi_addr (core_i.instr_addr_o), + .obi_req (core_i.instr_req_o), + .obi_gnt (core_i.instr_gnt_i), + .obi_dbg (core_i.instr_dbg_o), + .write_buffer_state (cv32e40x_pkg::WBUF_EMPTY), + .write_buffer_valid_o ('0), + .write_buffer_txn_bufferable ('0), + .write_buffer_txn_cacheable ('0), + .obi_if_state (core_i.if_stage_i.instruction_obi_i.state_q), + .lsu_split_0 (1'b0), + .lsu_split_q (1'b0), + .lsu_ctrl_update (1'b0), + .ctrl_exception_wb (1'b0), + .*); + + bind cv32e40x_mpu: + core_i.load_store_unit_i.mpu_i + cv32e40x_mpu_sva + #(.PMA_NUM_REGIONS (PMA_NUM_REGIONS), + .PMA_CFG (PMA_CFG), + .IS_INSTR_SIDE (0), + .CORE_RESP_TYPE (cv32e40x_pkg::data_resp_t), + .CORE_REQ_TYPE (cv32e40x_pkg::obi_data_req_t), + .A_EXT (A_EXT), + .DEBUG (DEBUG), + .DM_REGION_START (DM_REGION_START), + .DM_REGION_END (DM_REGION_END)) + mpu_lsu_sva(.pma_addr (pma_i.trans_addr_i), + .pma_cfg (pma_i.pma_cfg), + .pma_dbg (core_i.load_store_unit_i.mpu_i.core_trans_i.dbg), + .obi_memtype (core_i.data_memtype_o), + .obi_addr (core_i.data_addr_o), + .obi_req (core_i.data_req_o), + .obi_gnt (core_i.data_gnt_i), + .obi_dbg (core_i.data_dbg_o), + .write_buffer_state (core_i.load_store_unit_i.write_buffer_i.state), + .write_buffer_valid_o (core_i.load_store_unit_i.write_buffer_i.valid_o), + .write_buffer_txn_bufferable (core_i.load_store_unit_i.write_buffer_i.trans_o.memtype[0]), + .write_buffer_txn_cacheable (core_i.load_store_unit_i.write_buffer_i.trans_o.memtype[1]), + .obi_if_state (cv32e40x_pkg::TRANSPARENT), + .lsu_split_0 (core_i.load_store_unit_i.lsu_split_0_o), + .lsu_split_q (core_i.load_store_unit_i.split_q), + .lsu_ctrl_update (core_i.load_store_unit_i.ctrl_update), + .ctrl_exception_wb (core_i.controller_i.controller_fsm_i.exception_in_wb), + .*); + + bind cv32e40x_lsu_response_filter : + core_i.load_store_unit_i.response_filter_i + cv32e40x_lsu_response_filter_sva #(.DEPTH(DEPTH)) + lsu_response_filter_sva (.*); + + bind cv32e40x_write_buffer: + core_i.load_store_unit_i.write_buffer_i + cv32e40x_write_buffer_sva + #(.PMA_NUM_REGIONS(PMA_NUM_REGIONS), + .PMA_CFG(PMA_CFG)) + write_buffer_sva(.*); + + bind cv32e40x_sequencer: + core_i.if_stage_i.gen_seq.sequencer_i + cv32e40x_sequencer_sva + #(.RV32(RV32)) + sequencer_sva (.ex_wb_pipe_i (core_i.ex_wb_pipe ), + .wb_valid_i (core_i.wb_stage_i.wb_valid_o ), + .exception_in_wb_i (core_i.controller_i.controller_fsm_i.exception_in_wb ), + .pending_sync_debug_i (core_i.controller_i.controller_fsm_i.pending_sync_debug), + .*); + + bind cv32e40x_rvfi: + rvfi_i + cv32e40x_rvfi_sva + #(.CLIC (CLIC), + .DEBUG (DEBUG), + .A_EXT (A_EXT)) + rvfi_sva(.irq_ack(core_i.irq_ack), + .dbg_ack(core_i.dbg_ack), + .ebreak_in_wb_i(core_i.controller_i.controller_fsm_i.ebreak_in_wb), + .mtvec_addr_i(core_i.mtvec_addr), + .obi_instr_fifo_q(rvfi_i.rvfi_instr_obi_i.fifo_q), + .obi_instr_rptr_q_inc(rvfi_i.rvfi_instr_obi_i.rptr_q_inc), + .obi_instr_rptr_q(rvfi_i.rvfi_instr_obi_i.rptr_q), + .lsu_atomic_wb_i (core_i.lsu_atomic_wb), + .lsu_en_wb_i (core_i.ex_wb_pipe.lsu_en), + .lsu_split_q_wb_i (core_i.load_store_unit_i.split_q), + .pc_ex_i (core_i.id_ex_pipe.pc), + .m_c_obi_data_if (core_i.m_c_obi_data_if), + .*); + +`endif // `ifndef COREV_ASSERT_OFF + +`ifdef CORE_TRACES +`ifdef VERILATOR + // MAGIA verilator: no bind instance lists in Verilator; the wrapper has a single cv32e40x_rvfi + bind cv32e40x_rvfi +`else + // MAGIA: Questa repeats a module-wide bind for every wrapper instance, so keep the instance list + bind cv32e40x_rvfi: rvfi_i +`endif + cv32e40x_rvfi_sim_trace + tracer_i(.*); +`endif + + cv32e40x_core_log + #( .ENABLE ( CORE_LOG_ENABLE ), + .RV32 ( RV32 ), + .A_EXT ( A_EXT ), + .B_EXT ( B_EXT ), + .M_EXT ( M_EXT ), + .X_EXT ( X_EXT ), + .X_NUM_RS ( X_NUM_RS ), + .X_ID_WIDTH ( X_ID_WIDTH ), + .X_MEM_WIDTH ( X_MEM_WIDTH ), + .X_RFR_WIDTH ( X_RFR_WIDTH ), + .X_RFW_WIDTH ( X_RFW_WIDTH ), + .X_MISA ( X_MISA ), + .X_ECS_XS ( X_ECS_XS ), + .NUM_MHPMCOUNTERS ( NUM_MHPMCOUNTERS ), + .CLIC ( CLIC ), + .CLIC_ID_WIDTH ( CLIC_ID_WIDTH ), + .DEBUG ( DEBUG ), + .DM_REGION_START ( DM_REGION_START ), + .DM_REGION_END ( DM_REGION_END ), + .DBG_NUM_TRIGGERS ( DBG_NUM_TRIGGERS ), + .PMA_NUM_REGIONS ( PMA_NUM_REGIONS ), + .PMA_CFG ( PMA_CFG ) + ) + core_log_i( + .clk_i ( core_i.id_stage_i.clk ), + .ex_wb_pipe_i ( core_i.ex_wb_pipe ), + .mhartid_i ( core_i.mhartid_i ) + + ); + + // MAGIA verilator: Verilator cannot bind an interface port to a hierarchical interface, so mirror it locally + cv32e40x_if_c_obi #(.REQ_TYPE(obi_inst_req_t), .RESP_TYPE(obi_inst_resp_t)) rvfi_instr_obi_if(); + assign rvfi_instr_obi_if.s_req = core_i.m_c_obi_instr_if.s_req; + assign rvfi_instr_obi_if.req_payload = core_i.m_c_obi_instr_if.req_payload; + assign rvfi_instr_obi_if.s_gnt = core_i.m_c_obi_instr_if.s_gnt; + assign rvfi_instr_obi_if.s_rvalid = core_i.m_c_obi_instr_if.s_rvalid; + assign rvfi_instr_obi_if.resp_payload = core_i.m_c_obi_instr_if.resp_payload; + + cv32e40x_rvfi + #(.CLIC (CLIC), + .DEBUG (DEBUG), + .A_EXT (A_EXT)) + rvfi_i + (.clk_i ( clk_i ), + .rst_ni ( rst_ni ), + + // Non-pipeline Probes + .m_c_obi_instr_if ( rvfi_instr_obi_if ), + + // IF Probes + .if_valid_i ( core_i.if_stage_i.if_valid_o ), + .pc_if_i ( core_i.if_stage_i.pc_if_o ), + .instr_pmp_err_if_i ( 1'b0 /* PMP not implemented in cv32e40x */ ), + .last_op_if_i ( core_i.if_stage_i.last_op_o ), + .abort_op_if_i ( core_i.if_stage_i.abort_op_o ), + .prefetch_valid_if_i ( core_i.if_stage_i.prefetch_unit_i.prefetch_valid_o ), + .prefetch_ready_if_i ( core_i.if_stage_i.prefetch_unit_i.prefetch_ready_i ), + .prefetch_addr_if_i ( core_i.if_stage_i.prefetch_unit_i.prefetch_addr_o ), + .prefetch_compressed_if_i ( core_i.if_stage_i.instr_compressed ), + .prefetch_instr_if_i ( core_i.if_stage_i.prefetch_unit_i.prefetch_instr_o ), + .clic_ptr_if_i ( core_i.if_stage_i.prefetch_is_clic_ptr ), + .mret_ptr_if_i ( core_i.if_stage_i.prefetch_is_mret_ptr ), + .mpu_status_i ( core_i.if_stage_i.mpu_i.core_resp_o.mpu_status ), + .prefetch_trans_valid_i ( core_i.if_stage_i.prefetch_trans_valid ), + .prefetch_trans_ready_i ( core_i.if_stage_i.prefetch_trans_ready ), + .prefetch_resp_valid_i ( core_i.if_stage_i.prefetch_resp_valid ), + + // ID Probes + .id_valid_i ( core_i.id_stage_i.id_valid_o ), + .id_ready_i ( core_i.id_stage_i.id_ready_o ), + .pc_id_i ( core_i.id_stage_i.if_id_pipe_i.pc ), + // MAGIA: with X_NUM_RS = 3 the core has a third read port (rs3) that this RVFI does not trace + .rf_re_id_i ( core_i.id_stage_i.rf_re_o[1:0] ), + .sys_mret_id_i ( core_i.controller_i.controller_fsm_i.sys_mret_id ), + .tbljmp_id_i ( core_i.id_stage_i.if_id_pipe_i.instr_meta.tbljmp ), + .jump_in_id_i ( core_i.controller_i.controller_fsm_i.jump_in_id ), + .is_compressed_id_i ( core_i.id_stage_i.if_id_pipe_i.instr_meta.compressed ), + .lsu_en_id_i ( core_i.id_stage_i.lsu_en ), + .lsu_we_id_i ( core_i.id_stage_i.lsu_we ), + .lsu_size_id_i ( core_i.id_stage_i.lsu_size ), + .rs1_addr_id_i ( core_i.register_file_wrapper_i.raddr_i[0] ), + .rs2_addr_id_i ( core_i.register_file_wrapper_i.raddr_i[1] ), + .operand_a_fw_id_i ( core_i.id_stage_i.operand_a_fw ), + .operand_b_fw_id_i ( core_i.id_stage_i.operand_b_fw ), + .first_op_id_i ( core_i.id_stage_i.if_id_pipe_i.first_op ), + .clic_ptr_in_id_i ( core_i.controller_i.controller_fsm_i.clic_ptr_in_id ), + .mret_ptr_in_id_i ( core_i.controller_i.controller_fsm_i.mret_ptr_in_id ), + // EX Probes + .ex_ready_i ( core_i.ex_stage_i.ex_ready_o ), + .ex_valid_i ( core_i.ex_stage_i.ex_valid_o ), + .branch_in_ex_i ( core_i.controller_i.controller_fsm_i.branch_in_ex ), + .branch_decision_ex_i ( core_i.ex_stage_i.branch_decision_o ), + .dret_in_ex_i ( core_i.ex_stage_i.id_ex_pipe_i.sys_dret_insn ), + .lsu_en_ex_i ( core_i.ex_stage_i.id_ex_pipe_i.lsu_en ), + .lsu_pmp_err_ex_i ( 1'b0 /* PMP not implemented in cv32e40x */ ), + .lsu_pma_err_ex_i ( core_i.load_store_unit_i.mpu_i.pma_i.pma_err_o ), + .lsu_pma_atomic_ex_i ( core_i.load_store_unit_i.mpu_i.pma_i.atomic_access_i ), + .lsu_pma_cfg_ex_i ( core_i.load_store_unit_i.mpu_i.pma_i.pma_cfg ), + .lsu_misaligned_ex_i ( core_i.load_store_unit_i.misaligned_access ), + .buffer_trans_ex_i ( core_i.load_store_unit_i.buffer_trans ), + .buffer_trans_valid_ex_i ( core_i.load_store_unit_i.buffer_trans_valid ), + .lsu_split_q_ex_i ( core_i.load_store_unit_i.split_q ), + .lsu_split_0_ex_i ( core_i.load_store_unit_i.lsu_split_0_o ), + + // WB Probes + .wb_valid_i ( core_i.wb_stage_i.wb_valid_o ), + .wb_ready_i ( core_i.wb_stage_i.wb_ready_o ), + .pc_wb_i ( core_i.wb_stage_i.ex_wb_pipe_i.pc ), + .instr_rdata_wb_i ( core_i.wb_stage_i.ex_wb_pipe_i.instr.bus_resp.rdata ), + .ebreak_in_wb_i ( core_i.controller_i.controller_fsm_i.ebreak_in_wb ), + .csr_en_wb_i ( core_i.wb_stage_i.ex_wb_pipe_i.csr_en ), + .sys_wfi_insn_wb_i ( core_i.wb_stage_i.ex_wb_pipe_i.sys_wfi_insn ), + .sys_en_wb_i ( core_i.wb_stage_i.ex_wb_pipe_i.sys_en ), + .last_op_wb_i ( core_i.wb_stage_i.last_op_o ), + .first_op_wb_i ( core_i.wb_stage_i.ex_wb_pipe_i.first_op ), + .rf_we_wb_i ( core_i.wb_stage_i.rf_we_wb_o ), + .rf_addr_wb_i ( core_i.wb_stage_i.rf_waddr_wb_o ), + .rf_wdata_wb_i ( core_i.wb_stage_i.rf_wdata_wb_o ), + .lsu_rdata_wb_i ( core_i.load_store_unit_i.lsu_rdata_1_o ), + .abort_op_wb_i ( core_i.wb_stage_i.abort_op_o ), + .clic_ptr_wb_i ( core_i.wb_stage_i.ex_wb_pipe_i.instr_meta.clic_ptr ), + .mret_ptr_wb_i ( core_i.wb_stage_i.ex_wb_pipe_i.instr_meta.mret_ptr ), + .wpt_match_wb_i ( core_i.wb_stage_i.wpt_match_wb_o ), + .mpu_status_wb_i ( core_i.wb_stage_i.mpu_status_wb_o ), + .align_status_wb_i ( core_i.wb_stage_i.align_status_wb_o ), + .csr_mscratchcsw_in_wb_i ( 1'b0 /* Not implemented in cv32e40x */ ), + .csr_mscratchcswl_in_wb_i ( core_i.cs_registers_i.mscratchcswl_in_wb ), + .csr_mnxti_in_wb_i ( core_i.cs_registers_i.mnxti_in_wb ), + + .branch_addr_n_i ( core_i.if_stage_i.branch_addr_n ), + + .priv_lvl_i ( PRIV_LVL_M /* Not implemented in cv32e40x */ ), + .ctrl_fsm_i ( core_i.ctrl_fsm ), + .ctrl_fsm_cs_i ( core_i.controller_i.controller_fsm_i.ctrl_fsm_cs ), + .ctrl_fsm_ns_i ( core_i.controller_i.controller_fsm_i.ctrl_fsm_ns ), + .pending_single_step_i ( core_i.controller_i.controller_fsm_i.pending_single_step ), + .single_step_allowed_i ( core_i.controller_i.controller_fsm_i.single_step_allowed ), + .nmi_pending_i ( core_i.controller_i.controller_fsm_i.nmi_pending_q ), + .nmi_is_store_i ( core_i.controller_i.controller_fsm_i.nmi_is_store_q ), + .debug_mode_q_i ( core_i.controller_i.controller_fsm_i.debug_mode_q ), + .debug_cause_n_i ( core_i.controller_i.controller_fsm_i.debug_cause_n ), + .etrigger_in_wb_i ( core_i.controller_i.controller_fsm_i.etrigger_in_wb ), + .irq_i ( core_i.irq_i & IRQ_MASK ), + .irq_wu_ctrl_i ( core_i.irq_wu_ctrl ), + .irq_id_ctrl_i ( core_i.irq_id_ctrl ), + + // CSRs + .csr_jvt_n_i ( core_i.cs_registers_i.jvt_n ), + .csr_jvt_q_i ( core_i.cs_registers_i.jvt_rdata ), + .csr_jvt_we_i ( core_i.cs_registers_i.jvt_we ), + .csr_mstatus_n_i ( core_i.cs_registers_i.mstatus_n ), + .csr_mstatus_q_i ( core_i.cs_registers_i.mstatus_rdata ), + .csr_mstatus_we_i ( core_i.cs_registers_i.mstatus_we ), + .csr_misa_n_i ( core_i.cs_registers_i.misa_n ), + .csr_misa_q_i ( core_i.cs_registers_i.misa_rdata ), + .csr_misa_we_i ( core_i.cs_registers_i.misa_we ), + .csr_mie_n_i ( core_i.cs_registers_i.mie_n ), + .csr_mie_q_i ( core_i.cs_registers_i.mie_rdata ), + .csr_mie_we_i ( core_i.cs_registers_i.mie_we ), + .csr_mtvec_n_i ( core_i.cs_registers_i.mtvec_n ), + .csr_mtvec_q_i ( core_i.cs_registers_i.mtvec_rdata ), + .csr_mtvec_we_i ( core_i.cs_registers_i.mtvec_we ), + .csr_mtvt_n_i ( core_i.cs_registers_i.mtvt_n ), + .csr_mtvt_q_i ( core_i.cs_registers_i.mtvt_rdata ), + .csr_mtvt_we_i ( core_i.cs_registers_i.mtvt_we ), + .csr_mcountinhibit_n_i ( core_i.cs_registers_i.mcountinhibit_n ), + .csr_mcountinhibit_q_i ( core_i.cs_registers_i.mcountinhibit_rdata ), + .csr_mcountinhibit_we_i ( core_i.cs_registers_i.mcountinhibit_we ), + .csr_mhpmevent_n_i ( core_i.cs_registers_i.mhpmevent_n ), + .csr_mhpmevent_q_i ( core_i.cs_registers_i.mhpmevent_rdata ), + .csr_mhpmevent_we_i ( {31'h0, core_i.cs_registers_i.mhpmevent_we} << + core_i.cs_registers_i.csr_waddr[4:0] ), + .csr_mscratch_n_i ( core_i.cs_registers_i.mscratch_n ), + .csr_mscratch_q_i ( core_i.cs_registers_i.mscratch_rdata ), + .csr_mscratch_we_i ( core_i.cs_registers_i.mscratch_we ), + .csr_mepc_n_i ( core_i.cs_registers_i.mepc_n ), + .csr_mepc_q_i ( core_i.cs_registers_i.mepc_rdata ), + .csr_mepc_we_i ( core_i.cs_registers_i.mepc_we ), + .csr_mcause_n_i ( core_i.cs_registers_i.mcause_n ), + .csr_mcause_q_i ( core_i.cs_registers_i.mcause_rdata ), + .csr_mcause_we_i ( core_i.cs_registers_i.mcause_we ), + .csr_mip_n_i ( core_i.cs_registers_i.mip_n ), + .csr_mip_q_i ( core_i.cs_registers_i.mip_rdata ), + .csr_mip_we_i ( core_i.cs_registers_i.mip_we ), + .csr_mnxti_n_i ( core_i.cs_registers_i.mnxti_n ), + .csr_mnxti_q_i ( core_i.cs_registers_i.mnxti_rdata ), + .csr_mnxti_we_i ( core_i.cs_registers_i.mnxti_we ), + .csr_mintstatus_n_i ( core_i.cs_registers_i.mintstatus_n ), + .csr_mintstatus_q_i ( core_i.cs_registers_i.mintstatus_rdata ), + .csr_mintstatus_we_i ( core_i.cs_registers_i.mintstatus_we ), + .csr_mintthresh_n_i ( core_i.cs_registers_i.mintthresh_n ), + .csr_mintthresh_q_i ( core_i.cs_registers_i.mintthresh_rdata ), + .csr_mintthresh_we_i ( core_i.cs_registers_i.mintthresh_we ), + .csr_mscratchcsw_n_i ( 32'd0 /* Not implemented in cv32e40x */ ), + .csr_mscratchcsw_q_i ( 32'd0 /* Not implemented in cv32e40x */ ), + .csr_mscratchcsw_we_i ( 1'b0 /* Not implemented in cv32e40x */ ), + .csr_mscratchcswl_n_i ( core_i.cs_registers_i.mscratchcswl_n ), + .csr_mscratchcswl_q_i ( core_i.cs_registers_i.mscratchcswl_rdata ), + .csr_mscratchcswl_we_i ( core_i.cs_registers_i.mscratchcswl_we ), + .csr_tdata1_n_i ( core_i.cs_registers_i.debug_triggers_i.tdata1_n_r ), + .csr_tdata1_q_i ( core_i.cs_registers_i.tdata1_rdata ), + .csr_tdata1_we_i ( core_i.cs_registers_i.debug_triggers_i.tdata1_we_r ), + .csr_tdata2_n_i ( core_i.cs_registers_i.debug_triggers_i.tdata2_n_r ), + .csr_tdata2_q_i ( core_i.cs_registers_i.tdata2_rdata ), + .csr_tdata2_we_i ( core_i.cs_registers_i.debug_triggers_i.tdata2_we_r ), + .csr_tinfo_n_i ( core_i.cs_registers_i.debug_triggers_i.tinfo_n ), + .csr_tinfo_q_i ( core_i.cs_registers_i.tinfo_rdata ), + .csr_tinfo_we_i ( core_i.cs_registers_i.tinfo_we ), + .csr_dcsr_n_i ( core_i.cs_registers_i.dcsr_n ), + .csr_dcsr_q_i ( core_i.cs_registers_i.dcsr_rdata ), + .csr_dcsr_we_i ( core_i.cs_registers_i.dcsr_we ), + .csr_dpc_n_i ( core_i.cs_registers_i.dpc_n ), + .csr_dpc_q_i ( core_i.cs_registers_i.dpc_rdata ), + .csr_dpc_we_i ( core_i.cs_registers_i.dpc_we ), + .csr_dscratch0_n_i ( core_i.cs_registers_i.dscratch0_n ), + .csr_dscratch0_q_i ( core_i.cs_registers_i.dscratch0_rdata ), + .csr_dscratch0_we_i ( core_i.cs_registers_i.dscratch0_we ), + .csr_dscratch1_n_i ( core_i.cs_registers_i.dscratch1_n ), + .csr_dscratch1_q_i ( core_i.cs_registers_i.dscratch1_rdata ), + .csr_dscratch1_we_i ( core_i.cs_registers_i.dscratch1_we ), + .csr_mhpmcounter_n_i ( core_i.cs_registers_i.mhpmcounter_n ), + .csr_mhpmcounter_q_i ( core_i.cs_registers_i.mhpmcounter_rdata ), + .csr_mhpmcounter_we_i ( core_i.cs_registers_i.mhpmcounter_we ), + .csr_mvendorid_i ( core_i.cs_registers_i.mvendorid_rdata ), + .csr_marchid_i ( core_i.cs_registers_i.marchid_rdata ), + .csr_mhartid_i ( core_i.cs_registers_i.mhartid_rdata ), + .csr_mimpid_i ( core_i.cs_registers_i.mimpid_rdata ), + .csr_mstatush_n_i ( core_i.cs_registers_i.mstatush_n ), + .csr_mstatush_q_i ( core_i.cs_registers_i.mstatush_rdata ), + .csr_mstatush_we_i ( core_i.cs_registers_i.mstatush_we ), + .csr_tselect_n_i ( core_i.cs_registers_i.debug_triggers_i.tselect_n ), + .csr_tselect_q_i ( core_i.cs_registers_i.tselect_rdata ), + .csr_tselect_we_i ( core_i.cs_registers_i.tselect_we ), + .csr_mconfigptr_n_i ( core_i.cs_registers_i.mconfigptr_n ), + .csr_mconfigptr_q_i ( core_i.cs_registers_i.mconfigptr_rdata ), + .csr_mconfigptr_we_i ( core_i.cs_registers_i.mconfigptr_we ), + .csr_mcounteren_n_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mcounteren_q_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mcounteren_we_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_pmpcfg_n_i ( '{16{8'h0}} /* Not supported in cv32e40x*/ ), + .csr_pmpcfg_q_i ( '{16{8'h0}} /* Not supported in cv32e40x*/ ), + .csr_pmpcfg_we_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_pmpaddr_n_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_pmpaddr_q_i ( '{16{32'h0}} /* Not supported in cv32e40x*/ ), + .csr_pmpaddr_we_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mseccfg_n_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mseccfg_q_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mseccfg_we_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mseccfgh_n_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mseccfgh_q_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mseccfgh_we_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_menvcfg_n_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_menvcfg_q_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_menvcfg_we_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_menvcfgh_n_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_menvcfgh_q_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_menvcfgh_we_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_cpuctrl_n_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_cpuctrl_q_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_cpuctrl_we_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_secureseed0_n_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_secureseed0_q_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_secureseed0_we_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_secureseed1_n_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_secureseed1_q_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_secureseed1_we_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_secureseed2_n_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_secureseed2_q_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_secureseed2_we_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mstateen0_n_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mstateen0_q_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mstateen0_we_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mstateen1_n_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mstateen1_q_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mstateen1_we_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mstateen2_n_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mstateen2_q_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mstateen2_we_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mstateen3_n_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mstateen3_q_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mstateen3_we_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mstateen0h_n_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mstateen0h_q_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mstateen0h_we_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mstateen1h_n_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mstateen1h_q_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mstateen1h_we_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mstateen2h_n_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mstateen2h_q_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mstateen2h_we_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mstateen3h_n_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mstateen3h_q_i ( '0 /* Not supported in cv32e40x*/ ), + .csr_mstateen3h_we_i ( '0 /* Not supported in cv32e40x*/ ) + + +`ifdef RISCV_FORMAL + ,`RVFI_CONN +`else + ,`RVFI_TIEOFF +`endif + ); + + + // instantiate the core + cv32e40x_core + #( + .LIB ( LIB ), + .RV32 ( RV32 ), + .A_EXT ( A_EXT ), + .B_EXT ( B_EXT ), + .M_EXT ( M_EXT ), + .X_EXT ( X_EXT ), + .X_NUM_RS ( X_NUM_RS ), + .X_ID_WIDTH ( X_ID_WIDTH ), + .X_MEM_WIDTH ( X_MEM_WIDTH ), + .X_RFR_WIDTH ( X_RFR_WIDTH ), + .X_RFW_WIDTH ( X_RFW_WIDTH ), + .X_MISA ( X_MISA ), + .X_ECS_XS ( X_ECS_XS ), + .NUM_MHPMCOUNTERS ( NUM_MHPMCOUNTERS ), + .CLIC ( CLIC ), + .CLIC_ID_WIDTH ( CLIC_ID_WIDTH ), + .DEBUG ( DEBUG ), + .DM_REGION_START ( DM_REGION_START ), + .DM_REGION_END ( DM_REGION_END ), + .DBG_NUM_TRIGGERS ( DBG_NUM_TRIGGERS ), + .PMA_NUM_REGIONS ( PMA_NUM_REGIONS ), + .PMA_CFG ( PMA_CFG )) + core_i ( + .xif_compressed_if(xif_compressed_if), + .xif_issue_if(xif_issue_if), + .xif_commit_if(xif_commit_if), + .xif_mem_if(xif_mem_if), + .xif_mem_result_if(xif_mem_result_if), + .xif_result_if(xif_result_if), + .*); + +endmodule diff --git a/target/verilator/src/magia_fixture.sv b/target/verilator/src/magia_fixture.sv index cdaf6cd3..9ec6446b 100644 --- a/target/verilator/src/magia_fixture.sv +++ b/target/verilator/src/magia_fixture.sv @@ -5,10 +5,10 @@ * (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://solderpad.org/licenses/SHL-0.51 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Unless required by applicable law or agreed to in writing, software, hardware + * and materials distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -79,12 +79,7 @@ module magia_fixture; magia #( .N_TILES_Y ( magia_tb_pkg::N_TILES_Y ), .N_TILES_X ( magia_tb_pkg::N_TILES_X ), - .N_TILES ( magia_tb_pkg::N_TILES ), - .N_MEM_BANKS ( magia_tb_pkg::N_MEM_BANKS ), - .N_WORDS_BANK ( magia_tb_pkg::N_WORDS_BANK ), - .TILE_FSYNC_AGGR_W ( magia_tb_pkg::TILE_FSYNC_AGGR_W ), - .TILE_FSYNC_LVL_W ( magia_tb_pkg::TILE_FSYNC_LVL_W ), - .TILE_FSYNC_ID_W ( magia_tb_pkg::TILE_FSYNC_ID_W ) + .N_TILES ( magia_tb_pkg::N_TILES ) ) i_magia ( .clk_i ( clk ), .rst_ni ( rst_n ), diff --git a/target/verilator/src/magia_hier_params.v b/target/verilator/src/magia_hier_params.v index af8a5434..4c503571 100644 --- a/target/verilator/src/magia_hier_params.v +++ b/target/verilator/src/magia_hier_params.v @@ -1,5 +1,5 @@ // Copyright 2026 ETH Zurich and University of Bologna -// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: SHL-0.51 // // Deliberately empty because: Verilator 5.046 only substitutes a prebuilt hier_block // library for its instances when ParameterizedHierBlocks::m_hierSubRun is set diff --git a/target/verilator/src/magia_main.cpp b/target/verilator/src/magia_main.cpp index 3e3d4e1b..fca7a1fd 100644 --- a/target/verilator/src/magia_main.cpp +++ b/target/verilator/src/magia_main.cpp @@ -1,9 +1,7 @@ // Copyright 2026 ETH Zurich and University of Bologna // SPDX-License-Identifier: Apache-2.0 -// Simulation entry point for the hierarchical Verilator build, replacing the -// one Verilator generates with --main. It exists to own waveform dumping, -// which the testbench cannot do correctly for a --hierarchical model. +// Verilator main of the mesh and tile models: owns +FST dumping, which a --hierarchical testbench cannot do // // A hier_block instance is a protect-library child model: it is constructed by // the DPI call in the generated wrapper during the *first* evaluation of the @@ -16,12 +14,20 @@ #include "verilated.h" -#include "Vmagia_tb.h" +// Model class from verilator.mk: Vmagia_tb (mesh) or Vmagia_tile_tb (tile) +#ifndef MAGIA_TOP +#define MAGIA_TOP Vmagia_tb +#endif +#define MAGIA_STR_(x) #x +#define MAGIA_STR(x) MAGIA_STR_(x) +#include MAGIA_STR(MAGIA_TOP.h) #if VM_TRACE #include "verilated_fst_c.h" #endif +#include +#include #include #include @@ -40,10 +46,25 @@ static const char* fstPath(VerilatedContext* contextp) { } #endif +// SIGINT/SIGTERM stop at the next time slot so the FST gets closed; a second signal kills +static volatile std::sig_atomic_t g_stop = 0; + +static void onStopSignal(int sig) { + if (g_stop) { + std::signal(sig, SIG_DFL); + std::raise(sig); + } + g_stop = 1; +} + int main(int argc, char** argv, char**) { + std::signal(SIGINT, onStopSignal); + std::signal(SIGTERM, onStopSignal); Verilated::debug(0); const std::unique_ptr contextp{new VerilatedContext}; contextp->threads(MAGIA_THREADS); + // Like Questa, $error reports and goes on; +verilator+error+limit+N still overrides it + contextp->errorLimit(1000000); contextp->commandArgs(argc, argv); #if VM_TRACE @@ -60,7 +81,7 @@ int main(int argc, char** argv, char**) { // first dump segfaults inside fstWriterEmitValueChange. Any non-empty name // works; "TOP" is Verilator's own convention and prefixes every dumped // signal path with a "TOP" scope. - const std::unique_ptr topp{new Vmagia_tb{contextp.get(), "TOP"}}; + const std::unique_ptr topp{new MAGIA_TOP{contextp.get(), "TOP"}}; // Constructs every hier_block child and registers its trace callbacks. topp->eval(); @@ -76,8 +97,17 @@ int main(int argc, char** argv, char**) { } #endif - while (VL_LIKELY(!contextp->gotFinish())) { + // +STOP_AT=