From df5f74c7afe1ee8fb0f330d5d3eb5f6d2062e59a Mon Sep 17 00:00:00 2001 From: Francesco Conti Date: Fri, 4 Jul 2025 12:36:37 +0200 Subject: [PATCH 1/2] Squash of Luca Codeluppi's thesis - Verif part initial commit multi-hwpe extension adjustment in write check corrected few errors push test QoS: bandwidth adjusted an error in read check few tests handled the scenario with 0 hwpe, core, ext, or dma waveform to check few modifies debug waveform correct the previous commit: debug this waveform PATH: corrected list of forbidden addresses, assign correct data during read transaction, create path if does't exist modified the makefile to automatically generate the stimuli corrected a small error in the python code small error in the upper bound (address generation) parametric number of HWPE_WIDTH added latency TEST QoS arbitration multi-hwpe: debug photo of waveforms for arbitration problem Enriched the makefile: setup targets updated python documentation corrected an error in tb_top: PRIORITY_CHECK and RANDOM_REQ macros adjusted QoS metrics example config modified hci_arbiter, added mode 1 cleaned the code eliminated task check_hwpe_read_task: redundant cleaned the code changed the description of the arbiter added another mode for the hci_arbiter changed description of the hci_arbiter removed unnecessary from tb_top.sv modified a name in the makefile removed nested generate in the arbiter propagate arbiter mode through the hci added TEST_RATIO: ratio between the number of transactions in the two branches debug corrected small error in tb_top Improved the makefile and changed the python script accordingly Eliminate few targets from makefile Eliminated the following targets: setup_bandwidth, setup_data_integ, setup_arbiter_stall, setup_arbiter_no_stall. Replaced with test_1.mk, test_2.mk, test_3.mk, test_4.mk in config folder forgot to add makefile to the staging area in the previous commit Clean makefile Fix MACRO_TB in the Makefile Eliminate unnecessary in tb_top.sv Change few messages in tb_top.sv Change name N_TEST in config files to N_TRANSACTION and add EXACT_OR_MAX_OFFSET Adapt python script to support EXACT_OR_MAX_OFFSET parameter Implement hci_inteconnect_wrap.sv and fix small error in hci_arbiter.sv Set default value for memory access pattern Eliminate WIDTH_OF_MEMORY and improve readability of sim_time metric Fix few comments Add module queue_stimuli.sv Add modules: queues_out and queues_rdata Add comments to write transaction checker Create verificaion_hci_package Define parameters, structs and tasks in the package Add arbiter_checker module Add macro in hci_package.sv and set ecc to 0 Add progress bar Modularize logic to compute QoS metrics Add end_simulation, progress_bar modules and fix bugs in hci_wrapper Add assignment modules between masters and hci Eliminate data_for_read_transaction method from python class stimuli_generator Fix output warning Add comments to tb_top for clarity Fix error in previous commit [Update] python documentation [Update] process_txt.py and class_stimuli_generator.py documentation [Clean] verification_hci_package.sv [Clean] the code [Clean] [FIX] small error in stimuli generation [Documentation] Update [FIX] README.md [Documentation] Update [Removed] unnecessary print --- .gitignore | 1 + Bender.lock | 42 + Bender.yml | 37 + Makefile | 140 ++++ README.md | 30 + config/config.mk | 11 + config/hardware_config/hci_config.mk | 26 + .../masters_config/hwpe0_config.mk | 18 + .../masters_config/log0_config.mk | 18 + .../masters_config/log1_config.mk | 18 + .../masters_config/log2_config.mk | 18 + .../masters_config/log3_config.mk | 18 + .../masters_config/log4_config.mk | 18 + .../masters_config/log5_config.mk | 18 + .../masters_config/log6_config.mk | 18 + .../masters_config/log7_config.mk | 18 + .../masters_config/log8_config.mk | 18 + .../masters_config/log9_config.mk | 18 + config/sim_config/arbiter_mode0_check.mk | 32 + config/sim_config/arbiter_mode1_check.mk | 32 + config/sim_config/bandwidth_check.mk | 32 + config/sim_config/data_integrity_check.mk | 32 + .../class_stimuli_generator.py | 208 +++++ .../classes_and_functions/process_txt.py | 118 +++ verif/stimuli_generator/stimuli_gen_main.py | 253 ++++++ verif/sv/clock_and_reset/clk_rst_gen_prova.sv | 31 + verif/sv/clock_and_reset/rst_gen_prova.sv | 56 ++ verif/sv/common/verification_hci_package.sv | 159 ++++ verif/sv/other_modules/application_driver.sv | 91 +++ verif/sv/other_modules/arbiter_checker.sv | 162 ++++ .../assign_drivers_to_hwpebranch.sv | 39 + .../assign_drivers_to_logbranch.sv | 34 + .../compute_latency_per_transaction.sv | 121 +++ .../compute_througput_and_simtime.sv | 64 ++ .../end_simulation_and_final_report.sv | 87 ++ verif/sv/other_modules/progress_bar.sv | 33 + verif/sv/other_modules/queues_out.sv | 46 ++ verif/sv/other_modules/queues_rdata.sv | 107 +++ verif/sv/other_modules/queues_stimuli.sv | 72 ++ verif/sv/other_modules/tcdm_banks_wrap.sv | 100 +++ verif/sv/tb_top.sv | 753 ++++++++++++++++++ 41 files changed, 3147 insertions(+) create mode 100644 .gitignore create mode 100644 Bender.lock create mode 100644 Makefile create mode 100644 config/config.mk create mode 100644 config/hardware_config/hci_config.mk create mode 100644 config/hardware_config/masters_config/hwpe0_config.mk create mode 100644 config/hardware_config/masters_config/log0_config.mk create mode 100644 config/hardware_config/masters_config/log1_config.mk create mode 100644 config/hardware_config/masters_config/log2_config.mk create mode 100644 config/hardware_config/masters_config/log3_config.mk create mode 100644 config/hardware_config/masters_config/log4_config.mk create mode 100644 config/hardware_config/masters_config/log5_config.mk create mode 100644 config/hardware_config/masters_config/log6_config.mk create mode 100644 config/hardware_config/masters_config/log7_config.mk create mode 100644 config/hardware_config/masters_config/log8_config.mk create mode 100644 config/hardware_config/masters_config/log9_config.mk create mode 100644 config/sim_config/arbiter_mode0_check.mk create mode 100644 config/sim_config/arbiter_mode1_check.mk create mode 100644 config/sim_config/bandwidth_check.mk create mode 100644 config/sim_config/data_integrity_check.mk create mode 100644 verif/stimuli_generator/classes_and_functions/class_stimuli_generator.py create mode 100644 verif/stimuli_generator/classes_and_functions/process_txt.py create mode 100644 verif/stimuli_generator/stimuli_gen_main.py create mode 100644 verif/sv/clock_and_reset/clk_rst_gen_prova.sv create mode 100644 verif/sv/clock_and_reset/rst_gen_prova.sv create mode 100644 verif/sv/common/verification_hci_package.sv create mode 100644 verif/sv/other_modules/application_driver.sv create mode 100644 verif/sv/other_modules/arbiter_checker.sv create mode 100644 verif/sv/other_modules/assign_drivers_to_hwpebranch.sv create mode 100644 verif/sv/other_modules/assign_drivers_to_logbranch.sv create mode 100644 verif/sv/other_modules/compute_latency_per_transaction.sv create mode 100644 verif/sv/other_modules/compute_througput_and_simtime.sv create mode 100644 verif/sv/other_modules/end_simulation_and_final_report.sv create mode 100644 verif/sv/other_modules/progress_bar.sv create mode 100644 verif/sv/other_modules/queues_out.sv create mode 100644 verif/sv/other_modules/queues_rdata.sv create mode 100644 verif/sv/other_modules/queues_stimuli.sv create mode 100644 verif/sv/other_modules/tcdm_banks_wrap.sv create mode 100644 verif/sv/tb_top.sv diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..de7757f --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +config/__pycache__ diff --git a/Bender.lock b/Bender.lock new file mode 100644 index 0000000..b595a1a --- /dev/null +++ b/Bender.lock @@ -0,0 +1,42 @@ +packages: + cluster_interconnect: + revision: 1284def6c0b7f7e9355eb093d00883ad9dead1b7 + version: null + source: + Git: https://github.com/pulp-platform/cluster_interconnect.git + dependencies: + - common_cells + common_cells: + revision: c27bce39ebb2e6bae52f60960814a2afca7bd4cb + version: 1.37.0 + source: + Git: https://github.com/pulp-platform/common_cells.git + dependencies: + - common_verification + - tech_cells_generic + common_verification: + revision: fa2630f61666f61d9d78451c4d8b4d1ea403944e + version: 0.2.4 + source: + Git: https://github.com/pulp-platform/common_verification.git + dependencies: [] + hwpe-stream: + revision: 65c99a4a2f37a79acee800ab0151f67dfb1edef1 + version: 1.8.0 + source: + Git: https://github.com/pulp-platform/hwpe-stream.git + dependencies: + - tech_cells_generic + l2_tcdm_hybrid_interco: + revision: fa55e72859dcfb117a2788a77352193bef94ff2b + version: 1.0.0 + source: + Git: https://github.com/pulp-platform/L2_tcdm_hybrid_interco.git + dependencies: [] + tech_cells_generic: + revision: 7968dd6e6180df2c644636bc6d2908a49f2190cf + version: 0.2.13 + source: + Git: https://github.com/pulp-platform/tech_cells_generic.git + dependencies: + - common_verification diff --git a/Bender.yml b/Bender.yml index 9c57081..12a6d5b 100644 --- a/Bender.yml +++ b/Bender.yml @@ -62,3 +62,40 @@ sources: - rtl/ecc/hci_ecc_interconnect.sv - rtl/ecc/hci_ecc_sink.sv - rtl/hci_interconnect.sv + - target: any(test, test_wrap, test_wrap_netlist) + files: + # Level 0 + - verif/sv/common/verification_hci_package.sv + # Level 1 + - verif/sv/clock_and_reset/rst_gen_prova.sv + - verif/sv/clock_and_reset/clk_rst_gen_prova.sv + - verif/sv/other_modules/application_driver.sv + - verif/sv/other_modules/queues_stimuli.sv + - verif/sv/other_modules/queues_rdata.sv + - verif/sv/other_modules/queues_out.sv + - verif/sv/other_modules/arbiter_checker.sv + - verif/sv/other_modules/compute_latency_per_transaction.sv + - verif/sv/other_modules/compute_througput_and_simtime.sv + - verif/sv/other_modules/tcdm_banks_wrap.sv + - verif/sv/other_modules/end_simulation_and_final_report.sv + - verif/sv/other_modules/progress_bar.sv + - verif/sv/other_modules/assign_drivers_to_hwpebranch.sv + - verif/sv/other_modules/assign_drivers_to_logbranch.sv + - target: test + files: + # Level 2 + - verif/sv/tb_top.sv + - target: test_wrap + files: + - rtl/hci_interconnect_wrap.sv + # Level 2 + - backend/sourcecode/tb_top_wrap.sv + - target: test_wrap_netlist + files: + - backend/synopsys/out/hci_interconnect_wrap.v + # Level 2 + - backend/sourcecode/tb_top_wrap_netlist.sv + - target: synthesis + files: + # Level 0 + - rtl/hci_interconnect_wrap.sv diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..930e491 --- /dev/null +++ b/Makefile @@ -0,0 +1,140 @@ +include config/config.mk + +ROOT_DIR := $(strip $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))) # set the absolute path of the directory where the makefile is located +VLIB ?= vlib +library ?= work +VSIM ?= vsim +top_level ?= hci_tb +TARGET_BENDER ?= test +VOPT ?= vopt +PYTHON ?= python +PYTHON_STIMULI_SCRIPT ?= verif/stimuli_generator/stimuli_gen_main.py +N_LOG := $(strip $(shell echo $(N_CORE) + $(N_DMA) + $(N_EXT) | bc)) + +VLOG_ARGS += -suppress vlog-2583 -suppress vlog-13314 -suppress vlog-13233 -timescale \"1 ns / 1 ps\" \"+incdir+$(shell pwd)/include\" +MACROS_TB := +define+N_HWPE=$(N_HWPE) +define+HWPE_WIDTH=$(HWPE_WIDTH) +define+N_CORE=$(N_CORE) +define+N_DMA=$(N_DMA) +define+N_EXT=$(N_EXT) \ ++define+TS_BIT=$(TS_BIT) +define+EXPFIFO=$(EXPFIFO) +define+SEL_LIC=$(SEL_LIC) +define+DATA_WIDTH=$(DATA_WIDTH) +define+TOT_MEM_SIZE=$(TOT_MEM_SIZE) \ ++define+N_BANKS=$(N_BANKS) +define+N_TRANSACTION_LOG=$(N_TRANSACTION_LOG) +define+TRANSACTION_RATIO=$(TRANSACTION_RATIO) +define+CLK_PERIOD=$(CLK_PERIOD) \ ++define+RST_CLK_CYCLES=$(RST_CLK_CYCLES) +define+MAX_CYCLES_BETWEEN_GNT_RVALID=$(MAX_CYCLES_BETWEEN_GNT_RVALID) +define+RANDOM_GNT=$(RANDOM_GNT) \ ++define+PRIORITY_CHECK_MODE_ONE=$(PRIORITY_CHECK_MODE_ONE) +define+PRIORITY_CHECK_MODE_ZERO=$(PRIORITY_CHECK_MODE_ZERO) \ ++define+INVERT_PRIO=$(INVERT_PRIO) +define+LOW_PRIO_MAX_STALL=$(LOW_PRIO_MAX_STALL) + +define generate_vsim + echo 'set ROOT [file normalize [file dirname [info script]]/$3]' > $1 + bender script vsim --vlog-arg="$(VLOG_ARGS)" $2 --vlog-arg="$(MACROS_TB)" | grep -v "set ROOT" >> $1 + echo >> $1 +endef + +######################## +# DEPENDENCIES # +######################## + +.PHONY: checkout +## Checkout/update dependencies using Bender +checkout: + bender checkout + touch Bender.lock + make scripts/compile.tcl + +Bender.lock: + bender checkout + touch Bender.lock + +# Create config files for the masters +clean_setup: + rm -rf config/hardware_config/masters_config + +setup: clean_setup + @for i in $(shell seq 0 $(shell echo $(N_LOG)-1 | bc) ); do \ + LOG_PATH="config/hardware_config/masters_config/log"$$i"_config.mk"; \ + echo "Creating log"$$i"_config.mk..."; \ + mkdir -p config/hardware_config/masters_config; \ + echo "###########################################" > $$LOG_PATH; \ + echo "# LOG$$i MEMORY ACCESS PARAMETERS #" >> $$LOG_PATH; \ + echo "###########################################" >> $$LOG_PATH; \ + echo -e "\n# Memory access type: 0 (random), 1 (linear), 2 (2D), 3 (3D)" >> $$LOG_PATH; \ + echo "MEM_ACCESS_TYPE_LOG$$i?=0" >> $$LOG_PATH; \ + echo "# Starting address in binary (required for linear, 2D, and 3D accesses). Set to 0 if not needed" >> $$LOG_PATH; \ + echo "START_ADDRESS_LOG$$i?=0" >> $$LOG_PATH; \ + echo "# Stride0 (required for linear, 2D, and 3D accesses). Set to 0 if not needed" >> $$LOG_PATH; \ + echo "STRIDE0_LOG$$i?=0" >> $$LOG_PATH; \ + echo "# Len_d0 (required for 2D and 3D accesses). Set to 0 if not needed" >> $$LOG_PATH; \ + echo "LEN_D0_LOG$$i?=0" >> $$LOG_PATH; \ + echo "# Stride1 (required for 2D and 3D accesses). Set to 0 if not needed" >> $$LOG_PATH; \ + echo "STRIDE1_LOG$$i?=0" >> $$LOG_PATH; \ + echo "# Len_d1 (required for 3D accesses). Set to 0 if not needed" >> $$LOG_PATH; \ + echo "LEN_D1_LOG$$i?=0" >> $$LOG_PATH; \ + echo "# Stride2 (required for 3D accesses). Set to 0 if not needed" >> $$LOG_PATH; \ + echo "STRIDE2_LOG$$i?=0" >> $$LOG_PATH; \ + echo "Done!";\ + done + @for i in $(shell seq 0 $(shell echo $(N_HWPE)-1 | bc) ); do \ + HWPE_PATH="config/hardware_config/masters_config/hwpe"$$i"_config.mk"; \ + echo "Creating hwpe"$$i"_config.mk..."; \ + mkdir -p config/hardware_config/masters_config; \ + echo "###########################################" > $$HWPE_PATH; \ + echo "# HWPE$$i MEMORY ACCESS PARAMETERS #" >> $$HWPE_PATH; \ + echo "###########################################" >> $$HWPE_PATH; \ + echo -e "\n# Memory access type: 0 (random), 1 (linear), 2 (2D), 3 (3D)" >> $$HWPE_PATH; \ + echo "MEM_ACCESS_TYPE_HWPE$$i?=0" >> $$HWPE_PATH; \ + echo "# Starting address in binary (required for linear, 2D, and 3D accesses). Set to 0 if not needed" >> $$HWPE_PATH; \ + echo "START_ADDRESS_HWPE$$i?=0" >> $$HWPE_PATH; \ + echo "# Stride0 (required for linear, 2D, and 3D accesses). Set to 0 if not needed" >> $$HWPE_PATH; \ + echo "STRIDE0_HWPE$$i?=0" >> $$HWPE_PATH; \ + echo "# Len_d0 (required for 2D and 3D accesses). Set to 0 if not needed" >> $$HWPE_PATH; \ + echo "LEN_D0_HWPE$$i?=0" >> $$HWPE_PATH; \ + echo "# Stride1 (required for 2D and 3D accesses). Set to 0 if not needed" >> $$HWPE_PATH; \ + echo "STRIDE1_HWPE$$i?=0" >> $$HWPE_PATH; \ + echo "# Len_d1 (required for 3D accesses). Set to 0 if not needed" >> $$HWPE_PATH; \ + echo "LEN_D1_HWPE$$i?=0" >> $$HWPE_PATH; \ + echo "# Stride2 (required for 3D accesses). Set to 0 if not needed" >> $$HWPE_PATH; \ + echo "STRIDE2_HWPE$$i?=0" >> $$HWPE_PATH; \ + echo "Done!";\ + done + + +######################## +# CREATE STIMULI # +######################## + +clean_stimuli: + @echo -e "\nRemove old stimuli..." + @rm -rf verif/simvectors + +PYTHON_SIM_AND_HARDWARE_ARGS := --sim_and_hardware_params $(N_BANKS) $(TOT_MEM_SIZE) $(DATA_WIDTH) $(N_CORE) $(N_DMA) $(N_EXT) $(N_HWPE) $(HWPE_WIDTH) $(TRANSACTION_RATIO) $(N_TRANSACTION_LOG) $(CYCLE_OFFSET_LOG) $(CYCLE_OFFSET_HWPE) $(EXACT_OR_MAX_OFFSET) +PYTHON_LOG_ARGS := $(foreach i, $(shell seq 0 $(shell echo $(N_LOG) - 1 | bc)), --master_log $(MEM_ACCESS_TYPE_LOG$(i)) $(START_ADDRESS_LOG$(i)) $(STRIDE0_LOG$(i)) $(LEN_D0_LOG$(i)) $(STRIDE1_LOG$(i)) $(LEN_D1_LOG$(i)) $(STRIDE2_LOG$(i))) +PYTHON_HWPE_ARGS := $(foreach i, $(shell seq 0 $(shell echo $(N_HWPE) - 1 | bc)), --master_hwpe $(MEM_ACCESS_TYPE_HWPE$(i)) $(START_ADDRESS_HWPE$(i)) $(STRIDE0_HWPE$(i)) $(LEN_D0_HWPE$(i)) $(STRIDE1_HWPE$(i)) $(LEN_D1_HWPE$(i)) $(STRIDE2_HWPE$(i))) + +stimuli: clean_stimuli + @echo -e "\n### START! ###" + @$(PYTHON) $(PYTHON_STIMULI_SCRIPT) $(PYTHON_SIM_AND_HARDWARE_ARGS) $(PYTHON_LOG_ARGS) $(PYTHON_HWPE_ARGS) + @echo -e "\nDONE! New stimuli created" + +######################## +# BUILD AND SIMULATE # +######################## + +clean: + rm -rf scripts/compile.tcl + rm -rf work + +scripts/compile.tcl: | Bender.lock + $(call generate_vsim, $@, -t $(TARGET_BENDER) ,..) + +$(library): + $(VLIB) $(library) + +compile: $(library) scripts/compile.tcl + @test -f Bender.lock || { echo "ERROR: Bender.lock file does not exist. Did you run make checkout in bender mode?"; exit 1; } + @test -f scripts/compile.tcl || { echo "ERROR: scripts/compile.tcl file does not exist. Did you run make scripts in bender mode?"; exit 1; } + $(VSIM) -c -do 'source scripts/compile.tcl; quit' -msgmode both + +build: compile + $(VOPT) $(compile_flag) -suppress 3053 -suppress 8885 -work $(library) $(top_level) -o $(top_level)_optimized -debug + +run: + $(VSIM) +permissive $(questa-flags) $(questa-cmd) -suppress 3053 -suppress 8885 -lib $(library) +MAX_CYCLES=$(max_cycles) +UVM_TESTNAME=$(test_case) +APP=$(elf-bin) +notimingchecks +nospecify -t 1ps \ + ${top_level}_optimized +permissive-off ++$(elf-bin) ++$(target-options) ++$(cl-bin) | tee sim.log + +#include backend/backend.mk +include backend/backend_copy.mk \ No newline at end of file diff --git a/README.md b/README.md index 96a0511..fde223d 100644 --- a/README.md +++ b/README.md @@ -47,4 +47,34 @@ If you are using HCI IPs for an academic publication, we recommend citing one or keywords={Power demand;Design automation;Wearable computers;Pipelines;Gaze tracking;Energy efficiency;Task analysis}, doi={10.1109/DAC56929.2023.10247945} } +``` +# HCI Verification Environment + +This repository also contains an environment for verifying the Heterogeneous Cluster Interconnect (HCI) + +## Setup Instructions + +Before running the simulation, follow these steps: + +1. **Configure HCI Parameters**
+Edit the 'hci_config.mk' file inside config/hardware_config folder and insert the correct configuration values as needed for your verification environment.
+ +2. **Run Setup** +```bash +make setup +``` +3. **Configure the Parameters of the Masters**
+Edit the files in the folder /config/hardware_config/masters_config to set the parameters of the masters + +4. **Choose the Test**
+Choose the test in /config/config.mk + +5. **Create stimuli**
+```bash +make stimuli +``` + +6. **Run the simulation**
+```bash +make clean build run & ``` \ No newline at end of file diff --git a/config/config.mk b/config/config.mk new file mode 100644 index 0000000..8a704f2 --- /dev/null +++ b/config/config.mk @@ -0,0 +1,11 @@ +# Select desired test configuration +SELECT_TEST ?= bandwidth_check + + +MASTERS_CONFIG_PATH := config/hardware_config/masters_config +HCI_CONFIG_PATH := config/hardware_config +SIM_CONFIG_PATH := config/sim_config +SELECT_TEST_MK := $(SELECT_TEST).mk +-include $(MASTERS_CONFIG_PATH)/*.mk +include $(SIM_CONFIG_PATH)/$(SELECT_TEST_MK) +include $(HCI_CONFIG_PATH)/hci_config.mk \ No newline at end of file diff --git a/config/hardware_config/hci_config.mk b/config/hardware_config/hci_config.mk new file mode 100644 index 0000000..1ed8ae6 --- /dev/null +++ b/config/hardware_config/hci_config.mk @@ -0,0 +1,26 @@ +############################## +# HCI parameters # +############################## + +# Number of HWPEs attached to the port +N_HWPE?=1 +# Width of an HWPE wide-word (as a multiple of DATA_WIDTH) +HWPE_WIDTH?=4 +# Number of Core ports +N_CORE?=8 +# Number of DMA ports +N_DMA?=1 +# Number of External ports +N_EXT?=1 +# TEST_SET_BIT (for Log Interconnect) +TS_BIT?=21 +# FIFO Depth for HWPE Interconnect +EXPFIFO?=0 +# Log interconnect type selector +SEL_LIC?=0 +# Width of DATA in bits +DATA_WIDTH?=32 +# Total memory size (kB) +TOT_MEM_SIZE?=32 +# Number of memory banks +N_BANKS?=64 \ No newline at end of file diff --git a/config/hardware_config/masters_config/hwpe0_config.mk b/config/hardware_config/masters_config/hwpe0_config.mk new file mode 100644 index 0000000..0bd714e --- /dev/null +++ b/config/hardware_config/masters_config/hwpe0_config.mk @@ -0,0 +1,18 @@ +########################################### +# HWPE0 MEMORY ACCESS PARAMETERS # +########################################### + +# Memory access type: 0 (random), 1 (linear), 2 (2D), 3 (3D) +MEM_ACCESS_TYPE_HWPE0?=0 +# Starting address in binary (required for linear, 2D, and 3D accesses). Set to 0 if not needed +START_ADDRESS_HWPE0?=0 +# Stride0 (required for linear, 2D, and 3D accesses). Set to 0 if not needed +STRIDE0_HWPE0?=0 +# Len_d0 (required for 2D and 3D accesses). Set to 0 if not needed +LEN_D0_HWPE0?=0 +# Stride1 (required for 2D and 3D accesses). Set to 0 if not needed +STRIDE1_HWPE0?=0 +# Len_d1 (required for 3D accesses). Set to 0 if not needed +LEN_D1_HWPE0?=0 +# Stride2 (required for 3D accesses). Set to 0 if not needed +STRIDE2_HWPE0?=0 diff --git a/config/hardware_config/masters_config/log0_config.mk b/config/hardware_config/masters_config/log0_config.mk new file mode 100644 index 0000000..dd5bf8c --- /dev/null +++ b/config/hardware_config/masters_config/log0_config.mk @@ -0,0 +1,18 @@ +########################################### +# LOG0 MEMORY ACCESS PARAMETERS # +########################################### + +# Memory access type: 0 (random), 1 (linear), 2 (2D), 3 (3D) +MEM_ACCESS_TYPE_LOG0?=0 +# Starting address in binary (required for linear, 2D, and 3D accesses). Set to 0 if not needed +START_ADDRESS_LOG0?=0 +# Stride0 (required for linear, 2D, and 3D accesses). Set to 0 if not needed +STRIDE0_LOG0?=0 +# Len_d0 (required for 2D and 3D accesses). Set to 0 if not needed +LEN_D0_LOG0?=0 +# Stride1 (required for 2D and 3D accesses). Set to 0 if not needed +STRIDE1_LOG0?=0 +# Len_d1 (required for 3D accesses). Set to 0 if not needed +LEN_D1_LOG0?=0 +# Stride2 (required for 3D accesses). Set to 0 if not needed +STRIDE2_LOG0?=0 diff --git a/config/hardware_config/masters_config/log1_config.mk b/config/hardware_config/masters_config/log1_config.mk new file mode 100644 index 0000000..d87cf14 --- /dev/null +++ b/config/hardware_config/masters_config/log1_config.mk @@ -0,0 +1,18 @@ +########################################### +# LOG1 MEMORY ACCESS PARAMETERS # +########################################### + +# Memory access type: 0 (random), 1 (linear), 2 (2D), 3 (3D) +MEM_ACCESS_TYPE_LOG1?=0 +# Starting address in binary (required for linear, 2D, and 3D accesses). Set to 0 if not needed +START_ADDRESS_LOG1?=0 +# Stride0 (required for linear, 2D, and 3D accesses). Set to 0 if not needed +STRIDE0_LOG1?=0 +# Len_d0 (required for 2D and 3D accesses). Set to 0 if not needed +LEN_D0_LOG1?=0 +# Stride1 (required for 2D and 3D accesses). Set to 0 if not needed +STRIDE1_LOG1?=0 +# Len_d1 (required for 3D accesses). Set to 0 if not needed +LEN_D1_LOG1?=0 +# Stride2 (required for 3D accesses). Set to 0 if not needed +STRIDE2_LOG1?=0 diff --git a/config/hardware_config/masters_config/log2_config.mk b/config/hardware_config/masters_config/log2_config.mk new file mode 100644 index 0000000..b4552bf --- /dev/null +++ b/config/hardware_config/masters_config/log2_config.mk @@ -0,0 +1,18 @@ +########################################### +# LOG2 MEMORY ACCESS PARAMETERS # +########################################### + +# Memory access type: 0 (random), 1 (linear), 2 (2D), 3 (3D) +MEM_ACCESS_TYPE_LOG2?=0 +# Starting address in binary (required for linear, 2D, and 3D accesses). Set to 0 if not needed +START_ADDRESS_LOG2?=0 +# Stride0 (required for linear, 2D, and 3D accesses). Set to 0 if not needed +STRIDE0_LOG2?=0 +# Len_d0 (required for 2D and 3D accesses). Set to 0 if not needed +LEN_D0_LOG2?=0 +# Stride1 (required for 2D and 3D accesses). Set to 0 if not needed +STRIDE1_LOG2?=0 +# Len_d1 (required for 3D accesses). Set to 0 if not needed +LEN_D1_LOG2?=0 +# Stride2 (required for 3D accesses). Set to 0 if not needed +STRIDE2_LOG2?=0 diff --git a/config/hardware_config/masters_config/log3_config.mk b/config/hardware_config/masters_config/log3_config.mk new file mode 100644 index 0000000..cc4721f --- /dev/null +++ b/config/hardware_config/masters_config/log3_config.mk @@ -0,0 +1,18 @@ +########################################### +# LOG3 MEMORY ACCESS PARAMETERS # +########################################### + +# Memory access type: 0 (random), 1 (linear), 2 (2D), 3 (3D) +MEM_ACCESS_TYPE_LOG3?=0 +# Starting address in binary (required for linear, 2D, and 3D accesses). Set to 0 if not needed +START_ADDRESS_LOG3?=0 +# Stride0 (required for linear, 2D, and 3D accesses). Set to 0 if not needed +STRIDE0_LOG3?=0 +# Len_d0 (required for 2D and 3D accesses). Set to 0 if not needed +LEN_D0_LOG3?=0 +# Stride1 (required for 2D and 3D accesses). Set to 0 if not needed +STRIDE1_LOG3?=0 +# Len_d1 (required for 3D accesses). Set to 0 if not needed +LEN_D1_LOG3?=0 +# Stride2 (required for 3D accesses). Set to 0 if not needed +STRIDE2_LOG3?=0 diff --git a/config/hardware_config/masters_config/log4_config.mk b/config/hardware_config/masters_config/log4_config.mk new file mode 100644 index 0000000..10bbd3b --- /dev/null +++ b/config/hardware_config/masters_config/log4_config.mk @@ -0,0 +1,18 @@ +########################################### +# LOG4 MEMORY ACCESS PARAMETERS # +########################################### + +# Memory access type: 0 (random), 1 (linear), 2 (2D), 3 (3D) +MEM_ACCESS_TYPE_LOG4?=0 +# Starting address in binary (required for linear, 2D, and 3D accesses). Set to 0 if not needed +START_ADDRESS_LOG4?=0 +# Stride0 (required for linear, 2D, and 3D accesses). Set to 0 if not needed +STRIDE0_LOG4?=0 +# Len_d0 (required for 2D and 3D accesses). Set to 0 if not needed +LEN_D0_LOG4?=0 +# Stride1 (required for 2D and 3D accesses). Set to 0 if not needed +STRIDE1_LOG4?=0 +# Len_d1 (required for 3D accesses). Set to 0 if not needed +LEN_D1_LOG4?=0 +# Stride2 (required for 3D accesses). Set to 0 if not needed +STRIDE2_LOG4?=0 diff --git a/config/hardware_config/masters_config/log5_config.mk b/config/hardware_config/masters_config/log5_config.mk new file mode 100644 index 0000000..7097241 --- /dev/null +++ b/config/hardware_config/masters_config/log5_config.mk @@ -0,0 +1,18 @@ +########################################### +# LOG5 MEMORY ACCESS PARAMETERS # +########################################### + +# Memory access type: 0 (random), 1 (linear), 2 (2D), 3 (3D) +MEM_ACCESS_TYPE_LOG5?=0 +# Starting address in binary (required for linear, 2D, and 3D accesses). Set to 0 if not needed +START_ADDRESS_LOG5?=0 +# Stride0 (required for linear, 2D, and 3D accesses). Set to 0 if not needed +STRIDE0_LOG5?=0 +# Len_d0 (required for 2D and 3D accesses). Set to 0 if not needed +LEN_D0_LOG5?=0 +# Stride1 (required for 2D and 3D accesses). Set to 0 if not needed +STRIDE1_LOG5?=0 +# Len_d1 (required for 3D accesses). Set to 0 if not needed +LEN_D1_LOG5?=0 +# Stride2 (required for 3D accesses). Set to 0 if not needed +STRIDE2_LOG5?=0 diff --git a/config/hardware_config/masters_config/log6_config.mk b/config/hardware_config/masters_config/log6_config.mk new file mode 100644 index 0000000..0690871 --- /dev/null +++ b/config/hardware_config/masters_config/log6_config.mk @@ -0,0 +1,18 @@ +########################################### +# LOG6 MEMORY ACCESS PARAMETERS # +########################################### + +# Memory access type: 0 (random), 1 (linear), 2 (2D), 3 (3D) +MEM_ACCESS_TYPE_LOG6?=0 +# Starting address in binary (required for linear, 2D, and 3D accesses). Set to 0 if not needed +START_ADDRESS_LOG6?=0 +# Stride0 (required for linear, 2D, and 3D accesses). Set to 0 if not needed +STRIDE0_LOG6?=0 +# Len_d0 (required for 2D and 3D accesses). Set to 0 if not needed +LEN_D0_LOG6?=0 +# Stride1 (required for 2D and 3D accesses). Set to 0 if not needed +STRIDE1_LOG6?=0 +# Len_d1 (required for 3D accesses). Set to 0 if not needed +LEN_D1_LOG6?=0 +# Stride2 (required for 3D accesses). Set to 0 if not needed +STRIDE2_LOG6?=0 diff --git a/config/hardware_config/masters_config/log7_config.mk b/config/hardware_config/masters_config/log7_config.mk new file mode 100644 index 0000000..415fadf --- /dev/null +++ b/config/hardware_config/masters_config/log7_config.mk @@ -0,0 +1,18 @@ +########################################### +# LOG7 MEMORY ACCESS PARAMETERS # +########################################### + +# Memory access type: 0 (random), 1 (linear), 2 (2D), 3 (3D) +MEM_ACCESS_TYPE_LOG7?=0 +# Starting address in binary (required for linear, 2D, and 3D accesses). Set to 0 if not needed +START_ADDRESS_LOG7?=0 +# Stride0 (required for linear, 2D, and 3D accesses). Set to 0 if not needed +STRIDE0_LOG7?=0 +# Len_d0 (required for 2D and 3D accesses). Set to 0 if not needed +LEN_D0_LOG7?=0 +# Stride1 (required for 2D and 3D accesses). Set to 0 if not needed +STRIDE1_LOG7?=0 +# Len_d1 (required for 3D accesses). Set to 0 if not needed +LEN_D1_LOG7?=0 +# Stride2 (required for 3D accesses). Set to 0 if not needed +STRIDE2_LOG7?=0 diff --git a/config/hardware_config/masters_config/log8_config.mk b/config/hardware_config/masters_config/log8_config.mk new file mode 100644 index 0000000..9d88577 --- /dev/null +++ b/config/hardware_config/masters_config/log8_config.mk @@ -0,0 +1,18 @@ +########################################### +# LOG8 MEMORY ACCESS PARAMETERS # +########################################### + +# Memory access type: 0 (random), 1 (linear), 2 (2D), 3 (3D) +MEM_ACCESS_TYPE_LOG8?=0 +# Starting address in binary (required for linear, 2D, and 3D accesses). Set to 0 if not needed +START_ADDRESS_LOG8?=0 +# Stride0 (required for linear, 2D, and 3D accesses). Set to 0 if not needed +STRIDE0_LOG8?=0 +# Len_d0 (required for 2D and 3D accesses). Set to 0 if not needed +LEN_D0_LOG8?=0 +# Stride1 (required for 2D and 3D accesses). Set to 0 if not needed +STRIDE1_LOG8?=0 +# Len_d1 (required for 3D accesses). Set to 0 if not needed +LEN_D1_LOG8?=0 +# Stride2 (required for 3D accesses). Set to 0 if not needed +STRIDE2_LOG8?=0 diff --git a/config/hardware_config/masters_config/log9_config.mk b/config/hardware_config/masters_config/log9_config.mk new file mode 100644 index 0000000..70634c8 --- /dev/null +++ b/config/hardware_config/masters_config/log9_config.mk @@ -0,0 +1,18 @@ +########################################### +# LOG9 MEMORY ACCESS PARAMETERS # +########################################### + +# Memory access type: 0 (random), 1 (linear), 2 (2D), 3 (3D) +MEM_ACCESS_TYPE_LOG9?=0 +# Starting address in binary (required for linear, 2D, and 3D accesses). Set to 0 if not needed +START_ADDRESS_LOG9?=0 +# Stride0 (required for linear, 2D, and 3D accesses). Set to 0 if not needed +STRIDE0_LOG9?=0 +# Len_d0 (required for 2D and 3D accesses). Set to 0 if not needed +LEN_D0_LOG9?=0 +# Stride1 (required for 2D and 3D accesses). Set to 0 if not needed +STRIDE1_LOG9?=0 +# Len_d1 (required for 3D accesses). Set to 0 if not needed +LEN_D1_LOG9?=0 +# Stride2 (required for 3D accesses). Set to 0 if not needed +STRIDE2_LOG9?=0 diff --git a/config/sim_config/arbiter_mode0_check.mk b/config/sim_config/arbiter_mode0_check.mk new file mode 100644 index 0000000..61913d8 --- /dev/null +++ b/config/sim_config/arbiter_mode0_check.mk @@ -0,0 +1,32 @@ +################################# +# SIMULATION SETUP # +################################# +# Can be used to verify the mode0 of the arbiter + +# Number of transactions for each master in the log branch +N_TRANSACTION_LOG?=1000 +# Ratio between the number of transactions for a master in the hwpe branch and log branch +TRANSACTION_RATIO?=1 +# This three parameters define the maximum number of clock cycles between two consecutive requests coming from the same master +# If EXACT_OR_MAX_OFFSET = 0 ---> CYCLE_OFFSET defines the exact number of clock cycles between two consecutive requests +# If EXACT_OR_MAX_OFFSET = 1 ---> CYCLE_OFFSET defines the maximum number of clock cycles between two consecutive requests (the exact value is determined randomly) +# NOTE: the minimum value for CYCLE_OFFSET is 1 +EXACT_OR_MAX_OFFSET?=1 +CYCLE_OFFSET_LOG?=7 +CYCLE_OFFSET_HWPE?=7 +# Clock period in ns +CLK_PERIOD?=50 +# Number of clock cycles after which the reset signal is deasserted +RST_CLK_CYCLES?=10 +#Maximum expected number of cycles between the gnt signal and the r_valid signal +MAX_CYCLES_BETWEEN_GNT_RVALID?=1 +# Flag for the random generation of the gnt signal (TCDM side) +RANDOM_GNT?=0 +# Flag to activate the priority handling check, where it is consider as LOW_PRIO_MAX_STALL the maximum number of consecutive stalls on low-priority channel. +PRIORITY_CHECK_MODE_ONE?=0 +# Flag to activate the priority handling check, where it is consider as LOW_PRIO_MAX_STALL the maximum number of consecutive cycles where there is at least 1 req both in the high and low priority channel +PRIORITY_CHECK_MODE_ZERO?=1 +# Invert default priority in the hci_arbiter module +INVERT_PRIO?=0 +# Maximum number of stalls in the lower priority channel of the hci_arbiter +LOW_PRIO_MAX_STALL?=10 \ No newline at end of file diff --git a/config/sim_config/arbiter_mode1_check.mk b/config/sim_config/arbiter_mode1_check.mk new file mode 100644 index 0000000..b45fdd9 --- /dev/null +++ b/config/sim_config/arbiter_mode1_check.mk @@ -0,0 +1,32 @@ +################################# +# SIMULATION SETUP # +################################# +# Can be used to verify the mode1 of the arbiter + +# Number of transactions for each master in the log branch +N_TRANSACTION_LOG?=1000 +# Ratio between the number of transactions for a master in the hwpe branch and log branch +TRANSACTION_RATIO?=1 +# This three parameters define the maximum number of clock cycles between two consecutive requests coming from the same master +# If EXACT_OR_MAX_OFFSET = 0 ---> CYCLE_OFFSET defines the exact number of clock cycles between two consecutive requests +# If EXACT_OR_MAX_OFFSET = 1 ---> CYCLE_OFFSET defines the maximum number of clock cycles between two consecutive requests (the exact value is determined randomly) +# NOTE: the minimum value for CYCLE_OFFSET is 1 +EXACT_OR_MAX_OFFSET?=1 +CYCLE_OFFSET_LOG?=7 +CYCLE_OFFSET_HWPE?=7 +# Clock period in ns +CLK_PERIOD?=50 +# Number of clock cycles after which the reset signal is deasserted +RST_CLK_CYCLES?=10 +#Maximum expected number of cycles between the gnt signal and the r_valid signal +MAX_CYCLES_BETWEEN_GNT_RVALID?=1 +# Flag for the random generation of the gnt signal (TCDM side) +RANDOM_GNT?=0 +# Flag to activate the priority handling check, where it is consider as LOW_PRIO_MAX_STALL the maximum number of consecutive stalls on low-priority channel. +PRIORITY_CHECK_MODE_ONE?=1 +# Flag to activate the priority handling check, where it is consider as LOW_PRIO_MAX_STALL the maximum number of consecutive cycles where there is at least 1 req both in the high and low priority channel +PRIORITY_CHECK_MODE_ZERO?=0 +# Invert default priority in the hci_arbiter module +INVERT_PRIO?=0 +# Maximum number of stalls in the lower priority channel of the hci_arbiter +LOW_PRIO_MAX_STALL?=3 \ No newline at end of file diff --git a/config/sim_config/bandwidth_check.mk b/config/sim_config/bandwidth_check.mk new file mode 100644 index 0000000..5eb600d --- /dev/null +++ b/config/sim_config/bandwidth_check.mk @@ -0,0 +1,32 @@ +################################# +# SIMULATION SETUP # +################################# +# Can be used to measure bandwidth + +# Number of transactions for each master in the log branch +N_TRANSACTION_LOG?=1000 +# Ratio between the number of transactions for a master in the hwpe branch and log branch +TRANSACTION_RATIO?=1 +# This three parameters define the maximum number of clock cycles between two consecutive requests coming from the same master +# If EXACT_OR_MAX_OFFSET = 0 ---> CYCLE_OFFSET defines the exact number of clock cycles between two consecutive requests +# If EXACT_OR_MAX_OFFSET = 1 ---> CYCLE_OFFSET defines the maximum number of clock cycles between two consecutive requests (the exact value is determined randomly) +# NOTE: the minimum value for CYCLE_OFFSET is 1 +EXACT_OR_MAX_OFFSET?=0 +CYCLE_OFFSET_LOG?=1 +CYCLE_OFFSET_HWPE?=1 +# Clock period in ns +CLK_PERIOD?=50 +# Number of clock cycles after which the reset signal is deasserted +RST_CLK_CYCLES?=10 +# Maximum expected number of cycles between the gnt signal and the r_valid signal +MAX_CYCLES_BETWEEN_GNT_RVALID?=1 +# Flag for the random generation of the gnt signal (TCDM side) +RANDOM_GNT?=0 +# Flag to activate the priority handling check, where it is consider as LOW_PRIO_MAX_STALL the maximum number of consecutive stalls on low-priority channel. +PRIORITY_CHECK_MODE_ONE?=0 +# Flag to activate the priority handling check, where it is consider as LOW_PRIO_MAX_STALL the maximum number of consecutive cycles where there is at least 1 req both in the high and low priority channel +PRIORITY_CHECK_MODE_ZERO?=0 +# Invert default priority in the hci_arbiter module +INVERT_PRIO?=0 +# Maximum number of stalls in the lower priority channel of the hci_arbiter +LOW_PRIO_MAX_STALL?=10 diff --git a/config/sim_config/data_integrity_check.mk b/config/sim_config/data_integrity_check.mk new file mode 100644 index 0000000..cccf60f --- /dev/null +++ b/config/sim_config/data_integrity_check.mk @@ -0,0 +1,32 @@ +################################# +# SIMULATION SETUP # +################################# +# Can be used to evaluate data integrity + +# Number of transactions for each master in the log branch +N_TRANSACTION_LOG?=1000 +# Ratio between the number of transactions for a master in the hwpe branch and log branch +TRANSACTION_RATIO?=1 +# This three parameters define the maximum number of clock cycles between two consecutive requests coming from the same master +# If EXACT_OR_MAX_OFFSET = 0 ---> CYCLE_OFFSET defines the exact number of clock cycles between two consecutive requests +# If EXACT_OR_MAX_OFFSET = 1 ---> CYCLE_OFFSET defines the maximum number of clock cycles between two consecutive requests (the exact value is determined randomly) +# NOTE: the minimum value for CYCLE_OFFSET is 1 +EXACT_OR_MAX_OFFSET?=1 +CYCLE_OFFSET_LOG?=3 +CYCLE_OFFSET_HWPE?=10 +# Clock period in ns +CLK_PERIOD?=50 +# Number of clock cycles after which the reset signal is deasserted +RST_CLK_CYCLES?=10 +# Maximum expected number of cycles between the gnt signal and the r_valid signal +MAX_CYCLES_BETWEEN_GNT_RVALID?=1 +# Flag for the random generation of the gnt signal (TCDM side) +RANDOM_GNT?=1 +# Flag to activate the priority handling check, where it is consider as LOW_PRIO_MAX_STALL the maximum number of consecutive stalls on low-priority channel. +PRIORITY_CHECK_MODE_ONE?=0 +# Flag to activate the priority handling check, where it is consider as LOW_PRIO_MAX_STALL the maximum number of consecutive cycles where there is at least 1 req both in the high and low priority channel +PRIORITY_CHECK_MODE_ZERO?=0 +# Invert default priority in the hci_arbiter module +INVERT_PRIO?=0 +# Maximum number of stalls in the lower priority channel of the hci_arbiter +LOW_PRIO_MAX_STALL?=10 diff --git a/verif/stimuli_generator/classes_and_functions/class_stimuli_generator.py b/verif/stimuli_generator/classes_and_functions/class_stimuli_generator.py new file mode 100644 index 0000000..2ddbbde --- /dev/null +++ b/verif/stimuli_generator/classes_and_functions/class_stimuli_generator.py @@ -0,0 +1,208 @@ +################################# +# STIMULI GENERATOR CLASS # +################################# +# +# Class stimuli_generator used in the main python code `masters_main.py`. +# +# ---------------METHODS OVERVIEW------------------ +# +# 1) METHODS RELATED TO MEM ACCESS PATTERN GENERATION: +# -random_gen: random data and RANDOM address computation +# -linear_gen: random data and LINEAR address computation +# -gen_2d: random data and 2D address computation +# -gen_3d: random data and 3D address computation +# +# 2) METHODS RELATED TO DATA GENERATION: +# -random_data: generate random data +# -data_wen_offset: generate random data, write enable signal and cycle offset +# +# 3) INITIALIZATION: +# -__init__: initialize the class +# +# ------------------------------------------------ +import random +import numpy as np +import os + +class stimuli_generator: + def __init__(self,IW,WIDTH_OF_MEMORY,N_BANKS,TOT_MEM_SIZE,DATA_WIDTH,ADD_WIDTH,filepath,N_TEST,EXACT_OR_MAX_OFFSET,CYCLE_OFFSET,MASTER_NUMBER_IDENTIFICATION): + self.WIDTH_OF_MEMORY = WIDTH_OF_MEMORY + self.WIDTH_OF_MEMORY_BYTE = int(WIDTH_OF_MEMORY/8) + self.N_BANKS = N_BANKS + self.TOT_MEM_SIZE = TOT_MEM_SIZE + self.DATA_WIDTH = DATA_WIDTH + self.ADD_WIDTH = int(ADD_WIDTH) + self.filepath = filepath + os.makedirs(os.path.dirname(filepath),exist_ok=True) + self.N_TEST = N_TEST + self.EXACT_OR_MAX_OFFSET = EXACT_OR_MAX_OFFSET + self.CYCLE_OFFSET = CYCLE_OFFSET + self.IW = IW + self.MASTER_NUMBER_IDENTIFICATION = MASTER_NUMBER_IDENTIFICATION + + def random_data(self): + data_decimal = random.randint(0, (2**(self.DATA_WIDTH))-1) # generate random data + data = bin(data_decimal)[2:].zfill(self.DATA_WIDTH) + return data + + def data_wen_offset(self): + wen = random.randint(0,1) # write enable signal (1 = read, 0 = write) + if (self.EXACT_OR_MAX_OFFSET): + cycle_offset = random.randint(1,self.CYCLE_OFFSET) + else: + cycle_offset = self.CYCLE_OFFSET + if wen: + data = "0" * self.DATA_WIDTH + else: + data = self.random_data() + return data, wen, cycle_offset + + + def random_gen(self,id_start,LIST_OF_FORBIDDEN_ADDRESSES_READ,LIST_OF_FORBIDDEN_ADDRESSES_WRITE): + id = id_start + LIST_OF_FORBIDDEN_ADDRESSES_READ_NEW = [] + LIST_OF_FORBIDDEN_ADDRESSES_WRITE_NEW = [] + with open(self.filepath, 'w', encoding="ascii") as file: #write an ascii file for each port of each generator + for test in range(self.N_TEST): + data, wen, cycle_offset = self.data_wen_offset() + while True: + add_decimal = int((random.randint(0, int((self.TOT_MEM_SIZE*1024-self.WIDTH_OF_MEMORY_BYTE)/self.WIDTH_OF_MEMORY_BYTE)))*(self.WIDTH_OF_MEMORY_BYTE)) # generate a random word-aligned memory address. + if add_decimal > self.TOT_MEM_SIZE*1024-self.WIDTH_OF_MEMORY_BYTE : + add_decimal = add_decimal - self.TOT_MEM_SIZE*1024 #rolls over + add = bin(add_decimal)[2:].zfill(self.ADD_WIDTH) + + if wen: + if add not in LIST_OF_FORBIDDEN_ADDRESSES_READ: + LIST_OF_FORBIDDEN_ADDRESSES_WRITE_NEW.append(add) + break + else: + if add not in LIST_OF_FORBIDDEN_ADDRESSES_WRITE: + LIST_OF_FORBIDDEN_ADDRESSES_WRITE_NEW.append(add) + LIST_OF_FORBIDDEN_ADDRESSES_READ_NEW.append(add) + break + file.write(bin(id)[2:].zfill(self.IW) + " " + str(cycle_offset) + " " + str(wen) + " " + data + " " + add + "\n") + id = id + 1 + LIST_OF_FORBIDDEN_ADDRESSES_READ.extend(LIST_OF_FORBIDDEN_ADDRESSES_READ_NEW) + LIST_OF_FORBIDDEN_ADDRESSES_WRITE.extend(LIST_OF_FORBIDDEN_ADDRESSES_WRITE_NEW) + return id + + def linear_gen(self,stride0,start_address,id_start,LIST_OF_FORBIDDEN_ADDRESSES_READ,LIST_OF_FORBIDDEN_ADDRESSES_WRITE): + id = id_start + LIST_OF_FORBIDDEN_ADDRESSES_READ_NEW = [] + LIST_OF_FORBIDDEN_ADDRESSES_WRITE_NEW = [] + with open(self.filepath, 'w', encoding="ascii") as file: #write an ascii file for each port of each generator + next_address = int(start_address,2) + if next_address > self.TOT_MEM_SIZE*1024-self.WIDTH_OF_MEMORY_BYTE : + next_address = next_address - self.TOT_MEM_SIZE*1024 #rolls over + for test in range(self.N_TEST): + data, wen, cycle_offset = self.data_wen_offset() + + add = bin(next_address)[2:].zfill(self.ADD_WIDTH) + next_address += (self.WIDTH_OF_MEMORY_BYTE)*stride0 #word-aligned memory address + if next_address > self.TOT_MEM_SIZE*1024-self.WIDTH_OF_MEMORY_BYTE : + next_address = next_address - self.TOT_MEM_SIZE*1024 #rolls over + if wen: + if add not in LIST_OF_FORBIDDEN_ADDRESSES_READ: + LIST_OF_FORBIDDEN_ADDRESSES_WRITE_NEW.append(add) + break + else: + if add not in LIST_OF_FORBIDDEN_ADDRESSES_WRITE: + LIST_OF_FORBIDDEN_ADDRESSES_WRITE_NEW.append(add) + LIST_OF_FORBIDDEN_ADDRESSES_READ_NEW.append(add) + break + file.write(bin(id)[2:].zfill(self.IW) + " " + str(cycle_offset) + " " + str(wen) + " " + data + " " + add + "\n") + id = id + 1 + + LIST_OF_FORBIDDEN_ADDRESSES_READ.extend(LIST_OF_FORBIDDEN_ADDRESSES_READ_NEW) + LIST_OF_FORBIDDEN_ADDRESSES_WRITE.extend(LIST_OF_FORBIDDEN_ADDRESSES_WRITE_NEW) + + return id + + def gen_2d(self,stride0,len_d0,stride1,start_address,id_start,LIST_OF_FORBIDDEN_ADDRESSES_READ,LIST_OF_FORBIDDEN_ADDRESSES_WRITE): + id = id_start + LIST_OF_FORBIDDEN_ADDRESSES_READ_NEW = [] + LIST_OF_FORBIDDEN_ADDRESSES_WRITE_NEW = [] + with open(self.filepath, 'w', encoding="ascii") as file: #write an ascii file for each port of each generator + start_address = int(start_address,2) + next_address = start_address + j = 0 + STOP = 0 + while True: + for i in range(len_d0): + data, wen, cycle_offset = self.data_wen_offset() + next_address = start_address + i*(self.WIDTH_OF_MEMORY_BYTE)*stride0 + j*(self.WIDTH_OF_MEMORY_BYTE)*stride1 #word-aligned memory address + add = bin(next_address)[2:].zfill(self.ADD_WIDTH) + if next_address > self.TOT_MEM_SIZE*1024-self.WIDTH_OF_MEMORY_BYTE : + next_address = next_address - self.TOT_MEM_SIZE*1024 #rolls over + + if wen: + if add not in LIST_OF_FORBIDDEN_ADDRESSES_READ: + LIST_OF_FORBIDDEN_ADDRESSES_WRITE_NEW.append(add) + file.write(bin(id)[2:].zfill(self.IW) + " " + str(cycle_offset) + " " + str(wen) + " " + data + " " + add + "\n") + id = id + 1 + if id - id_start >= self.N_TEST : + STOP = 1 + break + else: + if add not in LIST_OF_FORBIDDEN_ADDRESSES_WRITE: + LIST_OF_FORBIDDEN_ADDRESSES_WRITE_NEW.append(add) + LIST_OF_FORBIDDEN_ADDRESSES_READ_NEW.append(add) + file.write(bin(id)[2:].zfill(self.IW) + " " + str(cycle_offset) + " " + str(wen) + " " + data + " " + add + "\n") + id = id + 1 + if id - id_start >= self.N_TEST : + STOP = 1 + break + if STOP: + break + j = j + 1 + + LIST_OF_FORBIDDEN_ADDRESSES_READ.extend(LIST_OF_FORBIDDEN_ADDRESSES_READ_NEW) + LIST_OF_FORBIDDEN_ADDRESSES_WRITE.extend(LIST_OF_FORBIDDEN_ADDRESSES_WRITE_NEW) + return id + + def gen_3d(self,stride0,len_d0,stride1,len_d1,stride2,start_address,id_start,LIST_OF_FORBIDDEN_ADDRESSES_READ,LIST_OF_FORBIDDEN_ADDRESSES_WRITE): + id = id_start + LIST_OF_FORBIDDEN_ADDRESSES_READ_NEW = [] + LIST_OF_FORBIDDEN_ADDRESSES_WRITE_NEW = [] + with open(self.filepath, 'w', encoding="ascii") as file: #write an ascii file for each port of each generator + start_address = int(start_address,2) + next_address = start_address + k = 0 + STOP = 0 + while True: + for j in range(len_d1): + for i in range(len_d0): + data, wen, cycle_offset = self.data_wen_offset() + next_address = start_address + i*(self.WIDTH_OF_MEMORY_BYTE)*stride0 + j*(self.WIDTH_OF_MEMORY_BYTE)*stride1 + k*(self.WIDTH_OF_MEMORY_BYTE)*stride2 #word-aligned memory address + if next_address > self.TOT_MEM_SIZE*1024-self.WIDTH_OF_MEMORY_BYTE : + next_address = next_address - self.TOT_MEM_SIZE*1024 #rolls over + add = bin(next_address)[2:].zfill(self.ADD_WIDTH) + + if wen: + if add not in LIST_OF_FORBIDDEN_ADDRESSES_READ: + LIST_OF_FORBIDDEN_ADDRESSES_WRITE_NEW.append(add) + file.write(bin(id)[2:].zfill(self.IW) + " " + str(cycle_offset) + " " + str(wen) + " " + data + " " + add + "\n") + id = id + 1 + if id - id_start >= self.N_TEST : + STOP = 1 + break + else: + if add not in LIST_OF_FORBIDDEN_ADDRESSES_WRITE: + LIST_OF_FORBIDDEN_ADDRESSES_WRITE_NEW.append(add) + LIST_OF_FORBIDDEN_ADDRESSES_READ_NEW.append(add) + file.write(bin(id)[2:].zfill(self.IW) + " " + str(cycle_offset) + " " + str(wen) + " " + data + " " + add + "\n") + id = id + 1 + if id - id_start >= self.N_TEST : + STOP = 1 + break + if STOP: + break + if STOP: + break + k = k + 1 + + LIST_OF_FORBIDDEN_ADDRESSES_READ.extend(LIST_OF_FORBIDDEN_ADDRESSES_READ_NEW) + LIST_OF_FORBIDDEN_ADDRESSES_WRITE.extend(LIST_OF_FORBIDDEN_ADDRESSES_WRITE_NEW) + return id + + diff --git a/verif/stimuli_generator/classes_and_functions/process_txt.py b/verif/stimuli_generator/classes_and_functions/process_txt.py new file mode 100644 index 0000000..25a4e93 --- /dev/null +++ b/verif/stimuli_generator/classes_and_functions/process_txt.py @@ -0,0 +1,118 @@ +################################# +# PROCESS STIMULI TXT FILES # +################################# +# +# This Python code provides a set of functions to easily process the raw .txt files. + +import numpy as np +import os + + +# 1) ++UNFOLD++ the transactions in the .txt files into a cycle-level list. +# -folder_path_raw --> String that specifies the path of the folder containing the raw txt files (where the cycle offset is still indicated) +# -folder_path_processed --> String that specifies the path of the folder containing the new txt files created by this function +def unfold_raw_txt(folder_path_raw,folder_path_processed,IW,DATA_WIDTH,ADD_WIDTH,HWPE_WIDTH): + file_names = [file for file in os.listdir(folder_path_raw) if file.endswith(".txt")] + for file in file_names: + filepath_read = os.path.join(folder_path_raw,file) + filepath_write = os.path.join(folder_path_processed, file) + os.makedirs(os.path.dirname(filepath_write),exist_ok=True) + with open(filepath_read, 'r', encoding = "ascii") as file_read: + with open(filepath_write, 'w', encoding="ascii") as file_write: + for line in file_read: + if line != 'zero': + values = line.split() + id = values[0] + cycle_offset = values[1] + wen = values[2] + data = values[3] + add = values[4] + if "log" in file: + for _ in range(int(cycle_offset)-1): + file_write.write("0 " + '0'*IW + " " + '0' + " " + '0'*int(DATA_WIDTH) + " " + '0'*ADD_WIDTH + "\n") + else: + for _ in range(int(cycle_offset)-1): + file_write.write("0 " + '0'*IW + " " + '0' + " " + '0'*int(HWPE_WIDTH*DATA_WIDTH) + " " + '0'*ADD_WIDTH + "\n") + file_write.write('1 ' + id + " " + wen + " " + data + " " + add + "\n") + else: + if "log" in file: + file_write.write("0 " + '0'*IW + " " + '0' + " " + '0'*int(DATA_WIDTH) + " " + '0'*ADD_WIDTH + "\n") + else: + file_write.write("0 " + '0'*IW + " " + '0' + " " + '0'*int(HWPE_WIDTH*DATA_WIDTH) + " " + '0'*ADD_WIDTH + "\n") + + +# 2) ++PAD++ txt files to have the same number of lines +# -Folder_path --> path of the folder containing the txt files to be padded +def pad_txt_files(folder_path,IW,DATA_WIDTH,ADD_WIDTH,HWPE_WIDTH): + file_names = [file for file in os.listdir(folder_path) if file.endswith(".txt")] # List of the txt file names in the folder + max_lines = 0 + line_count = {} # Dictionary to store the number of lines in each txt file + # Determining the maximum number of lines among the txt files + for file in file_names: + file_path = os.path.join(folder_path,file) + with open(file_path,'r', encoding = 'ascii') as f: + line_count[file] = sum(1 for _ in f) + max_lines = max(max_lines, line_count[file]) + # Pad files + for file in file_names: + padding_needed = max_lines - line_count[file] + if padding_needed > 0: + file_path = os.path.join(folder_path,file) + with open(file_path, 'a', encoding = 'ascii') as f: + if "log" in file: + for _ in range(padding_needed): + f.write("0 " + '0'*IW + " " + '0' + " " + '0'*int(DATA_WIDTH) + " " + '0'*ADD_WIDTH + "\n") + else: + for _ in range(padding_needed): + f.write("0 " + '0'*IW + " " + '0' + " " + '0'*int(HWPE_WIDTH*DATA_WIDTH) + " " + '0'*ADD_WIDTH + "\n") + + + ###################### DEPRECATED ############################ +# # 3) ++CHECK++ if during a same clock cycle two or more masters want to write to the same address +# def check_write_address(folder_path,ADD_WIDTH): +# file_names = [file for file in os.listdir(folder_path) if file.endswith(".txt")] # List of the txt file names in the folder +# N_MASTER = len(file_names) +# transactions_from_all_masters = [] # List containing different lists of req, id, wen, data, add signals for each master +# modified_masters = [0] * N_MASTER +# for file in file_names: +# file_path = os.path.join(folder_path,file) +# transactions = [] +# with open(file_path, 'r', encoding = 'ascii') as f: +# for line in f: +# values = line.split() +# transactions.append([values[0],values[1],values[2],values[3],values[4]]) +# transactions_from_all_masters.append(transactions) +# n_cycles = len(transactions_from_all_masters[0]) +# # Check and eventually change the address +# for i in range(n_cycles): +# for n0 in range(1,N_MASTER): +# for n1 in range(n0): +# recheck = 1 +# while recheck: +# recheck = 0 +# check0 = int(transactions_from_all_masters[n0][i][0]) and (not int(transactions_from_all_masters[n0][i][2])) # req and (not wen) +# check1 = int(transactions_from_all_masters[n1][i][0]) and (not int(transactions_from_all_masters[n1][i][2])) +# add0 = transactions_from_all_masters[n0][i][4] +# add1 = transactions_from_all_masters[n1][i][4] +# if check0 and check1: # We check the address only if we have req = 1 and wen = 0 +# if add0 == add1: +# new_add = int(transactions_from_all_masters[n0][i][4],2) + 1 # Add 1 to the integer representation of the old address +# max_value = 2 ** ADD_WIDTH +# new_add %= max_value # Modular arithmetic for overflow +# transactions_from_all_masters[n0][i][4] = bin(new_add)[2:].zfill(ADD_WIDTH) # Reconvert the address back into the binary representation +# recheck = 1 # We check again only if we changed the address +# modified_masters[n0] = 1 +# # Correct txt files +# for j in range(N_MASTER): +# if modified_masters[j]: +# file_path = os.path.join(folder_path,file_names[j]) +# with open(file_path, 'w', encoding = 'ascii') as f: +# for line in range(n_cycles): +# req = transactions_from_all_masters[j][line][0] +# id = transactions_from_all_masters[j][line][1] +# wen = transactions_from_all_masters[j][line][2] +# data = transactions_from_all_masters[j][line][3] +# add = transactions_from_all_masters[j][line][4] +# f.write(str(req) + " " + str(id) + " " + str(wen) + " " + str(data) + " " + str(add) + "\n") + + diff --git a/verif/stimuli_generator/stimuli_gen_main.py b/verif/stimuli_generator/stimuli_gen_main.py new file mode 100644 index 0000000..38a764c --- /dev/null +++ b/verif/stimuli_generator/stimuli_gen_main.py @@ -0,0 +1,253 @@ +#################################################### +# STIMULI GENERATOR for HCI verification suite # +#################################################### +# +# INTRODUCTION: +# +# This code is used to generate the stimuli for the verification suite of the Heterogeneous Cluster Interconnect. +# Depending on a set of configuration parameters, this code will generate many different .txt files, one for each master and each containing +# a list of all the transactions that will occur during the simulation. These .txt files will be used by the application drivers in the verification suite +# to emulate the behaviour of a multi-master system +# +# USAGE GUIDE: +# Run the command 'python stimuli_gen_main.py', specifying the necessary arguments +# 1) Specify the software and hardware parameters used to generate the stimuli with the argument --sim_and_hardware_params, in the following order: +# - N_BANKS +# - TOT_MEM_SIZE +# - DATA_WIDTH +# - N_CORE +# - N_DMA +# - N_EXT +# - N_HWPE +# - HWPE_WIDTH +# - TEST_RATIO +# - N_TEST_LOG +# - CYCLE_OFFSET_LOG +# - CYCLE_OFFSET_HWPE +# - EXACT_OR_MAX_OFFSET +# +# 2) Each --master_log and --master_hwpe argument is used to define the memory access type of a master, in particular it is possible to specify: +# - Memory access type: 0 (random), 1 (linear), 2 (2D), 3 (3D) +# - Starting address in binary (required for linear, 2D, and 3D accesses) +# - Stride0 (required for linear, 2D, and 3D accesses) +# - Len_d0 (required for 2D and 3D accesses) +# - Stride1 (required for 2D and 3D accesses) +# - Len_d1 (required for 3D accesses) +# - Stride2 (required for 3D accesses) +# note: There is no need to specify the "outer" length for linear, 2D, and 3D accesses, +# as the program will automatically stop once the specified `N_TEST` number of vectors is reached. +# +# For the masters in the logarithmic branch, use --master_log0 --master_log1 --master_log2 ecc... +# The first arguments are used for the COREs, followed by DMA and EXT, in order and depending on the number of cores, DMAs, and EXT specified with --sim_and_hardware_params. +# For the masters in the hwpe branch (shallow interconnect), use --master_hwpe0 --master_hwpe1 ecc... +# +# EXAMPLE: +# Parameters: N_BANKS = 8, TOT_MEM_SIZE = 32, DATA_WIDTH = 32, N_CORE = 1, N_DMA = 0, N_EXT = 1, N_HWPE = 1, +# HWPE_WIDTH = 4, TEST_RATIO = 2, N_TEST_LOG = 1000, CYCLE_OFFSET_LOG = 3, CYCLE_OFFSET_HWPE = 4, EXACT_OR_MAX_OFFSET = 1 +# +# Command: python stimuli_gen_main.py --sim_and_hardware_params 8 32 32 1 0 1 1 4 2 1000 3 4 1 --master_log 0 0101001 2 --master_hwpe 2 1100100 2 3 10 +# +# Result: The code will generate the following .txt files in the folder verif/simvectors/stimuli_processed: +# - stimuli with random memory access pattern (CORE) +# - stimuli with linear memory access pattern, starting address 0101001 and stride0 = 2 (EXT) +# - stimuli with a 2D memory access pattern, starting address 1100100, stride0 = 2, led_d0 = 3, stride2 = 2 (HWPE) +# +# "MAKE" YOUR LIFE EASIER: +# You can also use the makefile to configure the verification setup and automatically generate the correct stimuli for the most common scenarios. Otherwise, if a finer +# and more specific simulation is needed, you can manually invoke this script following the previous steps. + +### LIBRARIES AND DEPENDENCIES ### +import random +import os +from pathlib import Path +import sys +import numpy as np +from classes_and_functions.class_stimuli_generator import stimuli_generator +import classes_and_functions.process_txt as process +code_directory = os.path.dirname(os.path.abspath(__file__)) +config_directory = os.path.abspath(os.path.join(code_directory, "../../config_folder")) +sys.path.append(config_directory) +import argparse + +### ARGPARSE ### +parser = argparse.ArgumentParser(description="This script generates .txt files containing stimuli for use in the HCI verification suite.\n\n" + "# EXAMPLE:\n" + "Parameters: N_BANKS = 8, TOT_MEM_SIZE = 32, DATA_WIDTH = 32, N_CORE = 1, N_DMA = 0, N_EXT = 1, N_HWPE = 1,\n" + " HWPE_WIDTH = 4, TEST_RATIO = 2, N_TEST_LOG = 1000, CYCLE_OFFSET_LOG = 3, CYCLE_OFFSET_HWPE = 4, EXACT_OR_MAX_OFFSET = 1\n" + "Command: python stimuli_gen_main.py --sim_and_hardware_params 8 32 32 1 0 1 1 4 2 1000 3 4 1 --master_log 0 0101001 2 --master_hwpe 2 1100100 2 3 10\n" + "Result: The code will generate the following .txt files in the folder verif/simvectors/stimuli_processed:\n" + " - stimuli with random memory access pattern (CORE)\n" + " - stimuli with linear memory access pattern, starting address 0101001 and stride0 = 2 (EXT)\n" + " - stimuli with a 2D memory access pattern, starting address 1100100, stride0 = 2, led_d0 = 3, stride2 = 2 (HWPE)", + formatter_class=argparse.RawTextHelpFormatter) + +parser.add_argument(f'--sim_and_hardware_params', nargs='+', default=[], required=True, type=int, help=f"Specify the software and hardware parameters used to generate the stimuli:\n" + " - N_BANKS \n" + " - TOT_MEM_SIZE \n" + " - DATA_WIDTH \n" + " - N_CORE \n" + " - N_DMA \n" + " - N_EXT \n" + " - N_HWPE\n" + " - HWPE_WIDTH\n" + " - TEST_RATIO\n" + " - N_TEST_LOG\n" + " - CYCLE_OFFSET_LOG\n" + " - CYCLE_OFFSET_HWPE\n" + " - EXACT_OR_MAX_OFFSET") + +parser.add_argument(f'--master_log', nargs='*', default=[], action="extend", help=f"Specify the parameters for memory access related to masters in log branch:\n" + " - Memory access type: 0 (random), 1 (linear), 2 (2D), 3 (3D) \n" + " - Starting address in binary (required for linear, 2D, and 3D accesses)\n" + " - Stride0 (required for linear, 2D, and 3D accesses)\n" + " - Len_d0 (required for 2D and 3D accesses)\n" + " - Stride1 (required for 2D and 3D accesses)\n" + " - Len_d1 (required for 3D accesses)\n" + " - Stride2 (required for 3D accesses)\n\n" + "NOTE: There is no need to specify the \"outer\" length for linear, 2D, and 3D accesses,\n" + "as the program will automatically stop once the specified `N_TEST` vectors are reached.") + +parser.add_argument(f'--master_hwpe', nargs='*', default=[], action="extend", help=f"Specify the parameters for memory access related to masters in hwpe branch:\n" + " - Memory access type: 0 (random), 1 (linear), 2 (2D), 3 (3D) \n" + " - Starting address in binary (required for linear, 2D, and 3D accesses)\n" + " - Stride0 (required for linear, 2D, and 3D accesses)\n" + " - Len_d0 (required for 2D and 3D accesses)\n" + " - Stride1 (required for 2D and 3D accesses)\n" + " - Len_d1 (required for 3D accesses)\n" + " - Stride2 (required for 3D accesses)\n\n" + "NOTE: There is no need to specify the \"outer\" length for linear, 2D, and 3D accesses,\n" + "as the program will automatically stop once the specified `N_TEST` vectors are reached.") + +args = parser.parse_args() + +### PARAMETERS ### +N_BANKS, TOT_MEM_SIZE, DATA_WIDTH, N_CORE, N_DMA,\ +N_EXT, N_HWPE, HWPE_WIDTH, TEST_RATIO,\ +N_TEST_LOG, CYCLE_OFFSET_LOG, CYCLE_OFFSET_HWPE, EXACT_OR_MAX_OFFSET= getattr(args,"sim_and_hardware_params") + +WIDTH_OF_MEMORY = DATA_WIDTH +WIDTH_OF_MEMORY_BYTE = WIDTH_OF_MEMORY/8 +N_WORDS = (TOT_MEM_SIZE*1000/N_BANKS)/WIDTH_OF_MEMORY_BYTE +ADD_WIDTH = int(np.ceil(np.log2(TOT_MEM_SIZE*1000))) # Each memory address point to a byte +N_TEST_HWPE = int(N_TEST_LOG*TEST_RATIO) +N_LOG = N_CORE + N_DMA + N_EXT +N_MASTER = N_LOG + N_HWPE +IW = int(np.ceil(np.log2(N_TEST_LOG*N_LOG + N_TEST_HWPE*N_HWPE))) +CORE_ZERO_FLAG = 0 +EXT_ZERO_FLAG = 0 +DMA_ZERO_FLAG = 0 +HWPE_ZERO_FLAG = 0 + +### CHECKS ### +if (not N_WORDS.is_integer()): + print("ERROR: the number of words is not an integer value") + sys.exit(1) +if (N_MASTER < 1): + print("ERROR: the number of masters must be > 0") + sys.exit(1) +if (len(args.sim_and_hardware_params) != 13): + print("ERROR: Incorrect number of parameters in --sim_and_hardware_params") + print("Expected: 11 parameters") + print("Passed: ", len(args.sim_and_hardware_params), "parameters") + sys.exit(1) +if (len(args.master_log)/7 != N_LOG): + print("ERROR: Incorrect number of parameters in --master_log") + print("Expected: 7*N_LOG = ",7*N_LOG, "parameters") + print("Passed: ", len(args.master_log), "parameters") + sys.exit(1) +if (len(args.master_hwpe)/7 != N_HWPE): + print("ERROR: Incorrect number of parameters in --master_hwpe") + print("Expected: 7*N_HWPE = ",7*N_HWPE, "parameters") + print("Passed: ", len(args.master_hwpe), "parameters") + sys.exit(1) + +### GENERATE RAW TXT FILES ### +if (N_CORE <= 0): + CORE_ZERO_FLAG = 1 + N_CORE = 1 + filepath = os.path.abspath(os.path.join(code_directory, "../../verif/simvectors/stimuli_raw/" + "master_log_0.txt")) + os.makedirs(os.path.dirname(filepath),exist_ok=True) + with open(filepath, 'w', encoding="ascii") as file: + file.write('zero') +if (N_DMA <= 0): + DMA_ZERO_FLAG = 1 + N_DMA = 1 + filepath = os.path.abspath(os.path.join(code_directory, "../../verif/simvectors/stimuli_raw/" + f"master_log_{N_CORE}.txt")) + os.makedirs(os.path.dirname(filepath),exist_ok=True) + with open(filepath, 'w', encoding="ascii") as file: + file.write('zero') +if (N_EXT <= 0): + EXT_ZERO_FLAG = 1 + N_EXT = 1 + filepath = os.path.abspath(os.path.join(code_directory, "../../verif/simvectors/stimuli_raw/" + f"master_log_{N_CORE+N_DMA}.txt")) + os.makedirs(os.path.dirname(filepath),exist_ok=True) + with open(filepath, 'w', encoding="ascii") as file: + file.write('zero') +if (N_HWPE <= 0): + HWPE_ZERO_FLAG = 1 + N_HWPE = 1 + filepath = os.path.abspath(os.path.join(code_directory, "../../verif/simvectors/stimuli_raw/" + "master_hwpe_0.txt")) + os.makedirs(os.path.dirname(filepath),exist_ok=True) + with open(filepath, 'w', encoding="ascii") as file: + file.write('zero') + +N_MASTER = N_CORE + N_DMA + N_EXT + N_HWPE + +next_start_id = 0 +LIST_OF_FORBIDDEN_ADDRESSES_WRITE = [] +LIST_OF_FORBIDDEN_ADDRESSES_READ = [] + +for n in range(N_MASTER): + if n < N_CORE: + if CORE_ZERO_FLAG: + continue + else: + filepath = os.path.abspath(os.path.join(code_directory, "../../verif/simvectors/stimuli_raw/" + f"master_log_{n}.txt")) + master = stimuli_generator(IW,WIDTH_OF_MEMORY,N_BANKS,TOT_MEM_SIZE,DATA_WIDTH,ADD_WIDTH,filepath,N_TEST_LOG,EXACT_OR_MAX_OFFSET,CYCLE_OFFSET_LOG,n) #create the instance "master" from the class "stimuli generator" + config, start_address, stride0, len_d0, stride1, len_d1, stride2 = getattr(args,"master_log")[n*7:n*7+7] + elif n < N_CORE + N_DMA: + if DMA_ZERO_FLAG: + continue + else: + filepath = os.path.abspath(os.path.join(code_directory, "../../verif/simvectors/stimuli_raw/" + f"master_log_{n}.txt")) + master = stimuli_generator(IW,WIDTH_OF_MEMORY,N_BANKS,TOT_MEM_SIZE,DATA_WIDTH,ADD_WIDTH,filepath,N_TEST_LOG,EXACT_OR_MAX_OFFSET,CYCLE_OFFSET_LOG,n) #create the instance "master" from the class "stimuli generator" + config, start_address, stride0, len_d0, stride1, len_d1, stride2 = getattr(args,"master_log")[n*7:n*7+7] + elif n < N_CORE + N_DMA + N_EXT: + if EXT_ZERO_FLAG: + continue + else: + filepath = os.path.abspath(os.path.join(code_directory, "../../verif/simvectors/stimuli_raw/" + f"master_log_{n}.txt")) + master = stimuli_generator(IW,WIDTH_OF_MEMORY,N_BANKS,TOT_MEM_SIZE,DATA_WIDTH,ADD_WIDTH,filepath,N_TEST_LOG,EXACT_OR_MAX_OFFSET,CYCLE_OFFSET_LOG,n) #create the instance "master" from the class "stimuli generator" + config, start_address, stride0, len_d0, stride1, len_d1, stride2 = getattr(args,"master_log")[n*7:n*7+7] + else: + if HWPE_ZERO_FLAG: + continue + else: + filepath = os.path.abspath(os.path.join(code_directory, "../../verif/simvectors/stimuli_raw/" + f"master_hwpe_{n-(N_MASTER-N_HWPE)}.txt")) + master = stimuli_generator(IW,WIDTH_OF_MEMORY,N_BANKS,TOT_MEM_SIZE,HWPE_WIDTH*DATA_WIDTH,ADD_WIDTH,filepath,N_TEST_HWPE,EXACT_OR_MAX_OFFSET,CYCLE_OFFSET_HWPE,n) # wide word for the hwpe + config, start_address, stride0, len_d0, stride1, len_d1, stride2 = getattr(args,"master_hwpe")[(n-(N_MASTER-N_HWPE))*7:(n-(N_MASTER-N_HWPE))*7+7] + stride0 = int(stride0) + len_d0 = int(len_d0) + stride1 = int(stride1) + len_d1 = int(len_d1) + stride2 = int(stride2) + match config: + case '0': + next_start_id = master.random_gen(next_start_id,LIST_OF_FORBIDDEN_ADDRESSES_READ,LIST_OF_FORBIDDEN_ADDRESSES_WRITE) + case '1': + next_start_id = master.linear_gen(stride0,start_address,next_start_id,LIST_OF_FORBIDDEN_ADDRESSES_READ,LIST_OF_FORBIDDEN_ADDRESSES_WRITE) + case '2': + next_start_id = master.gen_2d(stride0,len_d0,stride1,start_address,next_start_id,LIST_OF_FORBIDDEN_ADDRESSES_READ,LIST_OF_FORBIDDEN_ADDRESSES_WRITE) + case '3': + next_start_id = master.gen_3d(stride0,len_d0,stride1,len_d1,stride2,start_address,next_start_id,LIST_OF_FORBIDDEN_ADDRESSES_READ,LIST_OF_FORBIDDEN_ADDRESSES_WRITE) + +print("STEP 0 COMPLETED: create raw txt files") + +### PROCESS RAW TXT FILES ### +simvector_raw_path = os.path.dirname(filepath) +simvector_processed_path = os.path.abspath(os.path.join(simvector_raw_path,"../stimuli_processed")) +process.unfold_raw_txt(simvector_raw_path,simvector_processed_path,IW,DATA_WIDTH,ADD_WIDTH,HWPE_WIDTH) +print("STEP 1 COMPLETED: unfold txt files") + +process.pad_txt_files(simvector_processed_path,IW,DATA_WIDTH,ADD_WIDTH,HWPE_WIDTH) +print("STEP 2 COMPLETED: pad txt files") diff --git a/verif/sv/clock_and_reset/clk_rst_gen_prova.sv b/verif/sv/clock_and_reset/clk_rst_gen_prova.sv new file mode 100644 index 0000000..b4cbb4f --- /dev/null +++ b/verif/sv/clock_and_reset/clk_rst_gen_prova.sv @@ -0,0 +1,31 @@ +module clk_rst_gen_prova #( + parameter time ClkPeriod, + parameter unsigned RstClkCycles +) ( + output logic clk_o, + output logic rst_no +); + + logic clk; + + // Clock Generation + initial begin + clk = 1'b0; + end + always begin + #(ClkPeriod/2); + clk = ~clk; + end + assign clk_o = clk; + + // Reset Generation + rst_gen_prova #( + .RstClkCycles(RstClkCycles) + ) i_rst_gen ( + .clk_i (clk), + .rst_ni(1'b1), + .rst_o (), + .rst_no(rst_no) + ); + +endmodule diff --git a/verif/sv/clock_and_reset/rst_gen_prova.sv b/verif/sv/clock_and_reset/rst_gen_prova.sv new file mode 100644 index 0000000..bed35d6 --- /dev/null +++ b/verif/sv/clock_and_reset/rst_gen_prova.sv @@ -0,0 +1,56 @@ +/** + * Synchronous Reset Generator + * + * Generates reset signals synchronous to a reference clock. The resets are asserted after + * initialization or when the external active-low reset is asserted. Once asserted, the resets + * are deasserted after a configurable number of cycles of the reference clock. + * + * Maintainer: VLSI I Assistants + */ + +module rst_gen_prova #( + parameter integer RstClkCycles +) ( + input logic clk_i, // Reference clock + input logic rst_ni, // External active-low reset + output logic rst_o, // Active-high reset output + output logic rst_no // Active-low reset output +); + + // Define signals. + logic [$clog2(RstClkCycles+1)-1:0] cnt_d, cnt_q; + logic rst_d, rst_q; + + // Increment counter until the configured number of clock cycles is reached. + always_comb begin + cnt_d = cnt_q; + if (cnt_q < RstClkCycles) begin + cnt_d += 1; + end + end + + // Deassert reset after the configured number of clock cycles is reached. + assign rst_d = (cnt_q >= RstClkCycles) ? 1'b0 : 1'b1; + + // Drive reset outputs directly from register + assign rst_o = rst_q; + assign rst_no = ~rst_q; + + // Infer rising-edge-triggered synchronous-(re)set FFs for the counter and reset register. + always @(posedge clk_i) begin + if (~rst_ni) begin + cnt_q <= '0; + rst_q <= 1'b1; + end else begin + cnt_q <= cnt_d; + rst_q <= rst_d; + end + end + + // Define initial values for FFs on the FPGA. + initial begin + cnt_q = '0; + rst_q = 1'b1; + end + +endmodule diff --git a/verif/sv/common/verification_hci_package.sv b/verif/sv/common/verification_hci_package.sv new file mode 100644 index 0000000..c4f3368 --- /dev/null +++ b/verif/sv/common/verification_hci_package.sv @@ -0,0 +1,159 @@ +package verification_hci_package; + + //////////////////////// + //PARAMETERS // + //////////////////////// + + // Timing parameters + localparam time CLK_PERIOD = `ifdef CLK_PERIOD `CLK_PERIOD `else 6 `endif; + localparam time APPL_DELAY = 0; + localparam unsigned RST_CLK_CYCLES = `ifdef RST_CLK_CYCLES `RST_CLK_CYCLES `else 10 `endif; + + // HCI parameters + localparam int unsigned N_HWPE_REAL = `ifdef N_HWPE `N_HWPE `else 1 `endif ; // Number of HWPEs attached to the port + localparam int unsigned N_CORE_REAL = `ifdef N_CORE `N_CORE `else 1 `endif ; // Number of Core ports + localparam int unsigned N_DMA_REAL = `ifdef N_DMA `N_DMA `else 1 `endif ; // Number of DMA ports + localparam int unsigned N_EXT_REAL = `ifdef N_EXT `N_EXT `else 1 `endif ; // Number of External ports + localparam int unsigned N_HWPE = (N_HWPE_REAL == 0) ? 1 : N_HWPE_REAL ; // Number of HWPEs attached to the port + localparam int unsigned N_CORE = (N_CORE_REAL == 0) ? 1 : N_CORE_REAL ; // Number of Core ports + localparam int unsigned N_DMA = (N_DMA_REAL == 0) ? 1 : N_DMA_REAL ; // Number of DMA ports + localparam int unsigned N_EXT = (N_EXT_REAL == 0) ? 1 : N_EXT_REAL ; // Number of External ports + localparam int unsigned N_MASTER = N_HWPE + N_CORE + N_DMA + N_EXT ; // Total number of masters + localparam int unsigned N_MASTER_REAL = N_HWPE_REAL + N_CORE_REAL + N_DMA_REAL + N_EXT_REAL ; // Total number of masters + localparam int unsigned TS_BIT = `ifdef TS_BIT `TS_BIT `else 0 `endif ; // TEST_SET_BIT (for Log Interconnect) + localparam int unsigned IW = $clog2(N_TRANSACTION_LOG*(N_MASTER_REAL-N_HWPE_REAL)+N_TRANSACTION_HWPE*N_HWPE_REAL) ; // ID Width + localparam int unsigned EXPFIFO = `ifdef EXPFIFO `EXPFIFO `else 0 `endif ; // FIFO Depth for HWPE Interconnect + localparam int unsigned SEL_LIC = `ifdef SEL_LIC `SEL_LIC `else 0 `endif ; // Log interconnect type selector + + localparam int unsigned DATA_WIDTH = `ifdef DATA_WIDTH `DATA_WIDTH `else 32 `endif ; // Width of DATA in bits + localparam int unsigned HWPE_WIDTH = `ifdef HWPE_WIDTH `HWPE_WIDTH `else 4 `endif ; // Widht of an HWPE wide-word (as a multiple of DATA_WIDTH) + localparam int unsigned TOT_MEM_SIZE = `ifdef TOT_MEM_SIZE `TOT_MEM_SIZE `else 32 `endif ; // Memory size (kB) + localparam int unsigned ADD_WIDTH = $clog2(TOT_MEM_SIZE*1024) ; // Width of ADDRESS in bits + localparam int unsigned N_BANKS = `ifdef N_BANKS `N_BANKS `else 16 `endif ; // Number of memory banks + localparam int unsigned WIDTH_OF_MEMORY = DATA_WIDTH ; // Width of a memory bank (bits) + localparam int unsigned WIDTH_OF_MEMORY_BYTE = WIDTH_OF_MEMORY/8 ; // Width of a memory bank (bytes) + localparam int unsigned BIT_BANK_INDEX = $clog2(N_BANKS) ; // Bits of the Bank index + localparam int unsigned AddrMemWidth = ADD_WIDTH - BIT_BANK_INDEX ; // Number of address bits per TCDM bank + localparam int unsigned N_WORDS = (TOT_MEM_SIZE*1024/N_BANKS)/WIDTH_OF_MEMORY_BYTE ; // Number of words in a bank + localparam int unsigned FILTER_WRITE_R_VALID = '0; + + localparam int unsigned ARBITER_MODE = (`ifdef PRIORITY_CHECK_MODE_ONE `PRIORITY_CHECK_MODE_ONE `else 0 `endif == 1) ? 1 : 0 ;// Choosen mode for the arbiter + localparam int unsigned INVERT_PRIO = `ifdef INVERT_PRIO `INVERT_PRIO `else 0 `endif; + localparam int unsigned LOW_PRIO_MAX_STALL = `ifdef LOW_PRIO_MAX_STALL `LOW_PRIO_MAX_STALL `else 3 `endif; + // Simulation parameters + localparam int unsigned N_TRANSACTION_LOG = `ifdef N_TRANSACTION_LOG `N_TRANSACTION_LOG `else 10 `endif; + localparam int unsigned TRANSACTION_RATIO = `ifdef TRANSACTION_RATIO `TRANSACTION_RATIO `else 1 `endif; + localparam int unsigned N_TRANSACTION_HWPE = int'(N_TRANSACTION_LOG*TRANSACTION_RATIO); + localparam int unsigned TOT_CHECK = N_TRANSACTION_LOG*(N_CORE_REAL + N_DMA_REAL + N_EXT_REAL)+N_HWPE_REAL*N_TRANSACTION_HWPE*HWPE_WIDTH; + + //////////////////////// + //STRUCT // + //////////////////////// + typedef struct packed { + logic wen; + logic [DATA_WIDTH-1:0] data; + logic [ADD_WIDTH-1:0] add; + } stimuli; + + typedef struct packed { + logic [DATA_WIDTH - 1 : 0] data; + logic [AddrMemWidth - 1 : 0] add; + } out_intc_to_mem; + + //////////////////////// + //TASK // + //////////////////////// + task recreate_address(input logic [AddrMemWidth-1:0] address_before, input int bank, output logic [ADD_WIDTH-1:0] address_after); + begin + logic [BIT_BANK_INDEX-1:0] bank_index; + bank_index = bank; + address_after = {address_before[AddrMemWidth-1:2],bank_index,address_before[1:0]}; //[$clog2(N_BANKS)-1:0] + end + endtask + + task create_address_and_data_hwpe(input logic[ADD_WIDTH-1:0] address_before,input logic [HWPE_WIDTH*DATA_WIDTH-1:0] data_before, input int index, output logic [ADD_WIDTH-1:0] address_after, output logic [DATA_WIDTH-1:0] data_after, input rolls_over_check_before, output rolls_over_check_after); + begin + logic [BIT_BANK_INDEX-1:0] bank_index_before, bank_index_after; + bank_index_before = address_before[BIT_BANK_INDEX-1 + 2 : 2]; + bank_index_after = index + bank_index_before; + rolls_over_check_after = rolls_over_check_before; + if(bank_index_before > bank_index_after) begin //rolls over check + rolls_over_check_after = 1'b1; + end + address_after = {address_before[ADD_WIDTH-1:BIT_BANK_INDEX + 2]+rolls_over_check_after,bank_index_after,address_before[1:0]}; + + data_after = data_before[index*DATA_WIDTH +: DATA_WIDTH]; + end + endtask + + task calculate_bank_index(input logic [ADD_WIDTH-1:0] address, output logic [BIT_BANK_INDEX-1:0] index); + index = address[BIT_BANK_INDEX-1+2:2]; + endtask + + task check_hwpe(input int unsigned index_hwpe_already_checked,input int unsigned index_bank_already_checked,input stimuli queue_stimuli_hwpe[HWPE_WIDTH][$],input out_intc_to_mem queue_out_intc_to_mem_read[N_BANKS][$],output logic skip); + int signed index_hwpe_to_check; + int signed index_bank_to_check; + stimuli recreated_queue; + skip = 0; + for(int i=1; i HWPE_WIDTH-1) begin + index_hwpe_to_check = index_hwpe_to_check - HWPE_WIDTH; + index_bank_to_check = index_bank_to_check -HWPE_WIDTH; + end + if(index_bank_to_check >= int'(N_BANKS)) begin + index_bank_to_check = index_bank_to_check - N_BANKS; + + end + if(index_bank_to_check < 0) begin + index_bank_to_check = index_bank_to_check + N_BANKS; + end + recreate_address(queue_out_intc_to_mem_read[index_bank_to_check][0].add,index_bank_to_check,recreated_queue.add); + recreated_queue.data = queue_out_intc_to_mem_read[index_bank_to_check][0].data; + if(recreated_queue != queue_stimuli_hwpe[index_hwpe_to_check][0] || queue_out_intc_to_mem_read[index_bank_to_check].size()==0) begin + skip = 1; + end + end + endtask + + task calculate_theoretical_throughput(output real troughput_theo); + + real tot_data,band_memory_limit,tot_time; + string line; + if(TRANSACTION_RATIO>=1) begin + tot_time = N_TRANSACTION_HWPE; + end else begin + tot_time = N_TRANSACTION_LOG; + end + + tot_data = ((N_TRANSACTION_LOG * DATA_WIDTH) * (N_MASTER_REAL - N_HWPE_REAL) + (N_TRANSACTION_HWPE * HWPE_WIDTH * DATA_WIDTH) * N_HWPE_REAL); // bit + troughput_theo = tot_data/tot_time; // bit per cycle + band_memory_limit = real'(N_BANKS * DATA_WIDTH); + if (troughput_theo >= band_memory_limit) begin + troughput_theo = band_memory_limit; + end + endtask + + task automatic calculate_average_latency (ref real SUM_LATENCY_PER_TRANSACTION_LOG[N_MASTER-N_HWPE], ref real SUM_LATENCY_PER_TRANSACTION_HWPE[N_HWPE]); + for(int i=0;i= N_BANKS) begin + HWPE_REQ_EACH_MASTER[bank_index_hwpe_int + i - N_BANKS][ii] = 1'b1; //rolls over + end else begin + HWPE_REQ_EACH_MASTER[bank_index_hwpe_int + i][ii] = 1'b1; + end + end + #(CLK_PERIOD/100); + while(1) begin + @(posedge clk); + if(hwpe_intc[ii].gnt) begin + #(CLK_PERIOD/100); + for(int i=0;i= N_BANKS) begin + HWPE_REQ_EACH_MASTER[bank_index_hwpe_int + i - N_BANKS][ii] = 1'b0; //rolls over + end else begin + HWPE_REQ_EACH_MASTER[bank_index_hwpe_int + i][ii] = 1'b0; + end + end + break; + end + end + end + end + end + for(genvar ii=0;ii= TOT_CHECK); + $display("n_checks final = %0d",n_checks); + $display("------ Simulation End ------"); + if(n_correct == TOT_CHECK) begin + $display(" Test ***PASSED*** \n"); + end else begin + $display(" Test ***FAILED*** \n"); + end + $display("\\\\CHECKS\\\\"); + $display("n_correct = %0d out of n_check = %0d",n_correct,n_checks); + $display("expected n_check = %0d",TOT_CHECK); + $display("note: each hwpe transaction consists of HWPE_WIDTH=%0d checks \n",HWPE_WIDTH); + if(WARNING) begin + $display("** WARNING **: Unnecessary spourious writes are occuring when the HWPE's wide word is written to the banks."); + $display("The interconnect still works correctly, but this could be an unintended behaviour.\n"); + end + + calculate_theoretical_throughput(troughput_theo); + wait(troughput_real>=0); + $display("\\\\BANDWIDTH\\\\"); + $display("IDEAL APPLICATION PEAK BANDWIDTH (KERNEL DEPENDENT): %f bit per cycle",troughput_theo); + $display("REAL APPLICATION BANDWITH: %f bit per cycle",troughput_real); + $display("PERFORMANCE RATING %f%%\n", troughput_real/troughput_theo*100); + + wait(tot_latency>=0); + $display("\\\\SIMULATION TIME\\\\"); + $display("TOTAL SIMULATION TIME: %0d cycles", tot_latency); + for(int i=0; i= 0.1); + $display("10%% completed..."); + wait(real'(n_checks)/TOT_CHECK >= 0.2); + $display("20%% completed..."); + wait(real'(n_checks)/TOT_CHECK >= 0.3); + $display("30%% completed..."); + wait(real'(n_checks)/TOT_CHECK >= 0.4); + $display("40%% completed..."); + wait(real'(n_checks)/TOT_CHECK >= 0.5); + $display("50%% completed..."); + wait(real'(n_checks)/TOT_CHECK >= 0.6); + $display("60%% completed..."); + wait(real'(n_checks)/TOT_CHECK >= 0.7); + $display("70%% completed..."); + wait(real'(n_checks)/TOT_CHECK >= 0.8); + $display("80%% completed..."); + wait(real'(n_checks)/TOT_CHECK >= 0.9); + $display("90%% completed..."); + wait(real'(n_checks)/TOT_CHECK == 1); + $display("100%% completed!"); + end + +endmodule \ No newline at end of file diff --git a/verif/sv/other_modules/queues_out.sv b/verif/sv/other_modules/queues_out.sv new file mode 100644 index 0000000..362b4f4 --- /dev/null +++ b/verif/sv/other_modules/queues_out.sv @@ -0,0 +1,46 @@ +module queues_out + import verification_hci_package::out_intc_to_mem; +#( + parameter int unsigned N_MASTER = 1, + parameter int unsigned N_HWPE = 1, + parameter int unsigned N_BANKS = 8, + parameter int unsigned DATA_WIDTH = 32, + parameter int unsigned AddrMemWidth = 32 +) ( + hci_core_intf.target all_except_hwpe [0:N_MASTER-N_HWPE-1], + hci_core_intf.target hwpe_intc [0:N_HWPE-1], + hci_core_intf.target intc_mem_wiring [0:N_BANKS-1], + input logic rst_n, + input logic clk +); + + out_intc_to_mem queue_out_write[N_BANKS][$]; + out_intc_to_mem queue_out_read[N_BANKS][$]; + + // Add transactions received by each BANK to different output queues + generate + for(genvar ii=0;ii + * Antonio Pullini + * Igor Loi + * Francesco Conti + */ + +module tcdm_banks_wrap #( + parameter int unsigned BankSize = 256, // --> OVERRIDE + parameter int unsigned NbBanks = 1, // --> OVERRIDE + parameter int unsigned DataWidth = 32, + parameter int unsigned AddrWidth = 32, + parameter int unsigned BeWidth = DataWidth/8, + parameter int unsigned IdWidth = 1 +) ( + input logic clk_i, + input logic rst_ni, + input logic test_mode_i, + + hci_core_intf.target tcdm_slave[0:NbBanks-1] +); + localparam int unsigned RANDOM_GNT = `ifdef RANDOM_GNT `RANDOM_GNT `else 0 `endif; + + for(genvar i=0; i Don't know if this is needed, but OBI protocol requires it + logic [IdWidth-1:0] resp_id_d, resp_id_q; + assign resp_id_d = tcdm_slave[i].id; + assign tcdm_slave[i].r_id = resp_id_q; + + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_resp_id + if(~rst_ni) begin + resp_id_q <= '0; + end else begin + resp_id_q <= resp_id_d; + end + end + + // gnt + if (RANDOM_GNT == 1) begin + always_ff @(posedge clk_i or negedge rst_ni) begin : gnt_gen + if(~rst_ni) begin + tcdm_slave[i].gnt <= 1'b1; + end else begin + tcdm_slave[i].gnt <= $urandom; + end + end + end else begin + assign tcdm_slave[i].gnt = 1'b1; + end + + //sram + tc_sram #( + .NumWords (BankSize ), // Number of Words in data array + .DataWidth (DataWidth), // Data signal width + .ByteWidth (8 ), // Width of a data byte + .NumPorts (1 ), // Number of read and write ports + .Latency (1 ), // Latency when the read data is available + .SimInit ("ones" ), // Simulation initialization + .PrintSimCfg(0 ) // Print configuration + ) i_bank ( + .clk_i (clk_i ), // Clock + .rst_ni (rst_ni ), // Asynchronous reset active low + + .req_i (tcdm_slave[i].req ), // request + .we_i (~tcdm_slave[i].wen ), // write enable + .addr_i (tcdm_slave[i].add[$clog2(BankSize)+2-1:2]), // request address + .wdata_i(tcdm_slave[i].data ), // write data + .be_i (tcdm_slave[i].be ), // write byte enable + + .rdata_o(tcdm_slave[i].r_data ) // read data + ); + + //r_valid + always_ff @(posedge clk_i or negedge rst_ni) begin : rvalid_gen + if(~rst_ni) begin + tcdm_slave[i].r_valid <= 1'b0; + end else begin + if(tcdm_slave[i].req && tcdm_slave[i].gnt && tcdm_slave[i].wen) begin + tcdm_slave[i].r_valid <= 1'b1; + end else begin + tcdm_slave[i].r_valid <= 1'b0; + end + end + end + end + +endmodule + diff --git a/verif/sv/tb_top.sv b/verif/sv/tb_top.sv new file mode 100644 index 0000000..8ec0379 --- /dev/null +++ b/verif/sv/tb_top.sv @@ -0,0 +1,753 @@ +/* + * tb_top.sv + * + * Luca Codeluppi + * + * + * Copyright (C) 2019-2020 ETH Zurich, 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. + */ + + /** + Top-level module of a comprehensive and exhaustive HCI verification enviroment, including QoS measurement + **/ + +`include "hci_helpers.svh" + +timeunit 1ns; +timeprecision 10ps; + +module hci_tb + import hci_package::*; + import verification_hci_package::*; + (); + + //------------------------------------------------------------------------------------------------------------------------------- + //- HCI - + //------------------------------------------------------------------------------------------------------------------------------- + + logic clk, rst_n; + logic clear_i; + hci_interconnect_ctrl_t ctrl_i; + + assign clear_i = 0; + assign ctrl_i.invert_prio = INVERT_PRIO; + assign ctrl_i.low_prio_max_stall = LOW_PRIO_MAX_STALL; + + //////////////////// + // HCI interfaces // + //////////////////// + localparam hci_package::hci_size_parameter_t `HCI_SIZE_PARAM(cores) = '{ // CORE + DMA + EXT parameters + DW: DEFAULT_DW, + AW: DEFAULT_AW, + BW: DEFAULT_BW, + UW: DEFAULT_UW, + IW: IW, + EW: DEFAULT_EW, + EHW: DEFAULT_EHW + }; + localparam hci_package::hci_size_parameter_t `HCI_SIZE_PARAM(mems) = '{ // Bank parameters + DW: DEFAULT_DW, + AW: AddrMemWidth, + BW: DEFAULT_BW, + UW: DEFAULT_UW, + IW: IW, + EW: DEFAULT_EW, + EHW: DEFAULT_EHW + }; + localparam hci_package::hci_size_parameter_t `HCI_SIZE_PARAM(hwpe) = '{ // HWPE parameters + DW: HWPE_WIDTH*DATA_WIDTH, + AW: DEFAULT_AW, + BW: DEFAULT_BW, + UW: DEFAULT_UW, + IW: IW, + EW: DEFAULT_EW, + EHW: DEFAULT_EHW + }; + + hci_core_intf #( + .DW(HCI_SIZE_hwpe.DW), + .AW(HCI_SIZE_hwpe.AW), + .BW(HCI_SIZE_hwpe.BW), + .UW(HCI_SIZE_hwpe.UW), + .IW(HCI_SIZE_hwpe.IW), + .EW(HCI_SIZE_hwpe.EW), + .EHW(HCI_SIZE_hwpe.EHW) + ) hwpe_intc [0:N_HWPE-1] ( + .clk(clk) + ); + hci_core_intf #( + .DW(HCI_SIZE_cores.DW), + .AW(HCI_SIZE_cores.AW), + .BW(HCI_SIZE_cores.BW), + .UW(HCI_SIZE_cores.UW), + .IW(HCI_SIZE_cores.IW), + .EW(HCI_SIZE_cores.EW), + .EHW(HCI_SIZE_cores.EHW) + ) all_except_hwpe [0:N_MASTER-N_HWPE-1] ( + .clk(clk) + ); + hci_core_intf #( + .DW(HCI_SIZE_mems.DW), + .AW(HCI_SIZE_mems.AW), + .BW(HCI_SIZE_mems.BW), + .UW(HCI_SIZE_mems.UW), + .IW(HCI_SIZE_mems.IW), + .EW(HCI_SIZE_mems.EW), + .EHW(HCI_SIZE_mems.EHW), + .WAIVE_RQ3_ASSERT(1'b1), + .WAIVE_RQ4_ASSERT(1'b1), + .WAIVE_RSP3_ASSERT(1'b1), + .WAIVE_RSP5_ASSERT(1'b1) + ) intc_mem_wiring [0:N_BANKS-1] ( + .clk(clk) + ); + + ////////////////// + // HCI instance // + ////////////////// + hci_interconnect #( + .N_HWPE(N_HWPE), // Number of HWPEs attached to the port + .N_CORE(N_CORE), // Number of Core ports + .N_DMA(N_DMA), // Number of DMA ports + .N_EXT(N_EXT), // Number of External ports + .N_MEM(N_BANKS), // Number of Memory banks + .TS_BIT(TS_BIT), // TEST_SET_BIT (for Log Interconnect) + .IW(IW), // ID Width + .EXPFIFO(EXPFIFO), // FIFO Depth for HWPE Interconnect + .SEL_LIC(SEL_LIC), // Log interconnect type selector + .ARBITER_MODE(ARBITER_MODE), // Chosen mode for the arbiter + .HCI_SIZE_cores(HCI_SIZE_cores), + .HCI_SIZE_mems(HCI_SIZE_mems), + .HCI_SIZE_hwpe(HCI_SIZE_hwpe), + .WAIVE_RQ3_ASSERT(1'b1), + .WAIVE_RQ4_ASSERT(1'b1), + .WAIVE_RSP3_ASSERT(1'b1), + .WAIVE_RSP5_ASSERT(1'b1) + ) i_hci_interconnect ( + .clk_i(clk), + .rst_ni(rst_n), + .clear_i(clear_i), + .ctrl_i(ctrl_i), + .cores(all_except_hwpe[0:N_CORE-1]), + .dma(all_except_hwpe[N_CORE:N_CORE+N_DMA-1]), + .ext(all_except_hwpe[N_CORE+N_DMA:N_CORE+N_DMA+N_EXT-1]), + .mems(intc_mem_wiring), + .hwpe(hwpe_intc) + ); + + //------------------------------------------------------------------------------------------------------------------------------- + //- TCDM - + //------------------------------------------------------------------------------------------------------------------------------- + + tcdm_banks_wrap #( + .BankSize(N_WORDS), + .NbBanks(N_BANKS), + .DataWidth(DATA_WIDTH), + .AddrWidth(ADD_WIDTH), + .BeWidth(DATA_WIDTH/8), + .IdWidth(IW) + ) memory ( + .clk_i(clk), + .rst_ni(rst_n), + .test_mode_i(/*unconnected*/), + .tcdm_slave(intc_mem_wiring) + ); + + //------------------------------------------------------------------------------------------------------------------------------- + //- APPLICATION DRIVERS - + //------------------------------------------------------------------------------------------------------------------------------- + logic [0:N_MASTER-1] END_STIMULI = '0; + logic [0:N_MASTER-1] END_LATENCY = '0; + + /////////////////////// + // Driver interfaces // + /////////////////////// + hci_core_intf #( + .DW(HCI_SIZE_hwpe.DW), + .AW(HCI_SIZE_hwpe.AW), + .BW(HCI_SIZE_hwpe.BW), + .UW(HCI_SIZE_hwpe.UW), + .IW(HCI_SIZE_hwpe.IW), + .EW(HCI_SIZE_hwpe.EW), + .EHW(HCI_SIZE_hwpe.EHW) + ) drivers_hwpe [0:N_HWPE-1] ( + .clk(clk) + ); + + hci_core_intf #( + .DW(HCI_SIZE_cores.DW), + .AW(HCI_SIZE_cores.AW), + .BW(HCI_SIZE_cores.BW), + .UW(HCI_SIZE_cores.UW), + .IW(HCI_SIZE_cores.IW), + .EW(HCI_SIZE_cores.EW), + .EHW(HCI_SIZE_cores.EHW) + ) drivers_log [0:N_MASTER-N_HWPE-1] ( + .clk(clk) + ); + + ////////////////////// + // CORE + DMA + EXT // + ////////////////////// + generate + for(genvar ii=0; ii < N_MASTER - N_HWPE ; ii++) begin: app_driver_log + application_driver#( + .MASTER_NUMBER(ii), + .IS_HWPE(0), + .DATA_WIDTH(DATA_WIDTH), + .ADD_WIDTH(ADD_WIDTH), + .APPL_DELAY(APPL_DELAY), //delay on the input signals + .IW(IW) + ) app_driver ( + .master(drivers_log[ii]), + .rst_ni(rst_n), + .clear_i(clear_i), + .clk(clk), + .end_stimuli(END_STIMULI[ii]), + .end_latency(END_LATENCY[ii]) + ); + end + endgenerate + + ////////// + // HWPE // + ////////// + generate + for(genvar ii=0; ii < N_HWPE ; ii++) begin: app_driver_hwpe + application_driver#( + .MASTER_NUMBER(ii), + .IS_HWPE(1), + .DATA_WIDTH(HWPE_WIDTH*DATA_WIDTH), + .ADD_WIDTH(ADD_WIDTH), + .APPL_DELAY(APPL_DELAY), //delay on the input signals + .IW(IW) + ) app_driver_hwpe ( + .master(drivers_hwpe[ii]), + .rst_ni(rst_n), + .clear_i(clear_i), + .clk(clk), + .end_stimuli(END_STIMULI[N_MASTER-N_HWPE+ii]), + .end_latency(END_LATENCY[N_MASTER-N_HWPE+ii]) + ); + end + endgenerate + + //------------------------------------------------------------------------------------------------------------------------------- + //- INITIATORS-HCI BOUNDING - + //------------------------------------------------------------------------------------------------------------------------------- + + generate + for(genvar ii=0; ii < N_MASTER - N_HWPE ; ii++) begin: bounding_log_hci + assign_drivers_to_logbranch #( + .DRIVER_ID(ii) + ) i_assign_drivers_to_logbranch ( + .driver_target(drivers_log[ii]), + .hci_initiator(all_except_hwpe[ii]) + ); + end + endgenerate + + generate + for(genvar ii=0; ii < N_HWPE ; ii++) begin: bounding_hwpe_hci + assign_drivers_to_hwpebranch #( + .DRIVER_ID(ii+N_MASTER-N_HWPE), + .HWPE_WIDTH(HWPE_WIDTH), + .DATA_WIDTH_CORE(DATA_WIDTH) + ) i_assign_drivers_to_hwpebranch ( + .driver_target(drivers_hwpe[ii]), + .hci_initiator(hwpe_intc[ii]) + ); + end + endgenerate + + //------------------------------------------------------------------------------------------------------------------------------- + //- QUEUES - + //------------------------------------------------------------------------------------------------------------------------------- + + static int unsigned n_checks = 0; + static int unsigned n_correct = 0; + static int unsigned hwpe_check[N_HWPE] = '{default: 0}; + static int unsigned check_hwpe_read[N_HWPE] = '{default: 0}; + static int unsigned check_hwpe_read_add[N_HWPE] = '{default: 0}; + logic [N_BANKS-1:0] HIDE_HWPE; + logic [N_BANKS-1:0] HIDE_LOG; + + real SUM_LATENCY_PER_TRANSACTION_LOG[N_MASTER-N_HWPE]; + real SUM_LATENCY_PER_TRANSACTION_HWPE[N_HWPE]; + + //////////////////// + // STIMULI QUEUES // + //////////////////// + queues_stimuli #( + .N_MASTER(N_MASTER), + .N_HWPE(N_HWPE), + .HWPE_WIDTH(HWPE_WIDTH), + .DATA_WIDTH(DATA_WIDTH), + .ADD_WIDTH(ADD_WIDTH) + ) i_queues_stimuli ( + .all_except_hwpe(all_except_hwpe), + .hwpe_intc(hwpe_intc), + .rst_n(rst_n), + .clk(clk) + ); + + logic EMPTY_queue_out_read [0:N_BANKS-1]; + generate + for(genvar ii=0;ii Date: Fri, 29 Aug 2025 11:31:36 +0200 Subject: [PATCH 2/2] Update verif/sv/tb_top.sv Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- verif/sv/tb_top.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/verif/sv/tb_top.sv b/verif/sv/tb_top.sv index 8ec0379..449ee61 100644 --- a/verif/sv/tb_top.sv +++ b/verif/sv/tb_top.sv @@ -16,7 +16,7 @@ */ /** - Top-level module of a comprehensive and exhaustive HCI verification enviroment, including QoS measurement + Top-level module of a comprehensive and exhaustive HCI verification environment, including QoS measurement **/ `include "hci_helpers.svh"