From 4852e307b7f6112ea763da2b072a64099b82d994 Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Fri, 27 Nov 2020 08:26:02 +0000 Subject: [PATCH] Update lowrisc_ip to lowRISC/opentitan@e619fc60 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This updates the vendored code from OpenTitan and fixes up patches as we go. The biggest change is that the support files that were in dv/data have moved to dv/tools/dvsim (with a couple of other internal renames). The icache test code also needs the corresponding path change and to rename its regression from "sanity" to "smoke" (the new name for the default regression). Update code from upstream repository https://github.com/lowRISC/opentitan to revision e619fc60c6b9c755043eba65a41dc47815612834 * [dv] Remove duplicated keys from common_sim_cfg.hjson (Rupert Swarbrick) * [dv] two small fix in dv (Cindy Chen) * [dv] Comment out example build modes from common_sim_cfg.hjson (Rupert Swarbrick) * [dv/keymgr] Cleanup some warnings in xcelium (Weicai Yang) * [lc_ctrl] Reuse an instance of the RISC-V dmi_jtag as the LC TAP (Michael Schaffner) * [otp_ctrl] Update LC types within OTP (Michael Schaffner) * [lc_ctrl] Add first cut implementation (Michael Schaffner) * [flash_ctrl] update prim flash interface (Timothy Chen) * [flash_ctrl] Add support for isolated flash partition (Timothy Chen) * [dv/common] update naming from sanity to smoke (Cindy Chen) * [prim] update naming from sanity to smoke (Cindy Chen) * [dv/base] add get_reg_by_name support in dv_base_reg_block (Cindy Chen) * [cov methodology] Functional coverage prototype (Srikrishna Iyer) * [dv] Fix tpyo (Weicai Yang) * [dv common] Wave dumping improvements / fix (Srikrishna Iyer) * [dv] Fix for `--run-only` switch (Srikrishna Iyer) * [prim_present] Add support for iterative full-round PRESENT (Michael Schaffner) * [dv] Fix VCS compile error (Weicai Yang) * [sparse-fsm-encode] Switch to Safe Rust Encoding (Sam Elliott) * [sparse-fsm-encode] Disallow Complementary Encodings (Sam Elliott) * [prim/util] Fix parameter type when using prefixes (Pirmin Vogel) * [keymgr/prim_lfsr] Correct minor errors in core files (Michael Schaffner) * [design checklist] avoid using word sanity (Cindy Chen) * [prim_lc_sync] Add two stage sync for life cycle control signals (Michael Schaffner) * [flash] update flash program to support ack / done / last (Timothy Chen) * [prim] update prim flash to have ack / done support (Timothy Chen) * Fix typo in testplan template (Rupert Swarbrick) * [dv] Fix license header for some cfg files (Weicai Yang) * [dv] Only check scoreboard from pre_abort if we were in run phase (Rupert Swarbrick) * [doc] Add lint requirements to V1 checklist (Cindy Chen) * [dv common] Minor enhancements to dv_reg_block (Srikrishna Iyer) * [dv] Fix library paths for dsim (Srikrishna Iyer) * [keymgr/dv] Update testbench (Weicai Yang) * [dv/common] Add DV_ALERT_IF_CONNECT macro (Weicai Yang) * [dv, common] Promote VCS warning to error (Srikrishna Iyer) * [prim] update clock_mux prim to avoid using BUFG (Timothy Chen) * [clkmgr] Add divider bypass during test mode (Timothy Chen) * [opt_ctrl] Change state_q assignment to ease debugging (Michael Schaffner) * [doc] Update D2 checklist and propagate updates to IPs (Michael Schaffner) * [dv/dvsim] Fix -c option compile error (Cindy Chen) * [dv] Tidy up use of get_normalized_addr (Rupert Swarbrick) * [fpv] Fix fusesoc dependecy issue (Cindy Chen) * [lint] Fix lint warning (Cindy Chen) * [dv/lint] Add new DV TB to lint batch script (Cindy Chen) * [fpv] Add lint checking to FPV tb (Cindy Chen) * [dvsim] Remove process_exports() from the code (Srikrishna Iyer) * [dvsim] Fix HJson bugs (Srikrishna Iyer) * [fpv] alert_rx/tx updates (Cindy Chen) * [prim] slicer lint fix (Eunchan Kim) * [prim] Packer to remove unused parameter. (Eunchan Kim) * [prim_lfsr] Update prim_lfsr and testbench to use correct perm width (Michael Schaffner) * [prim_lfsr] Add script to generate seed and perm constants (Michael Schaffner) * [dv/common] Upgrade some VCS warnings to errors (Weicai Yang) * [dvsim] Document and slightly improve subst_wildcards in utils.py (Rupert Swarbrick) * [csrng/dv] Initial dv environment (Steve Nelson) * [sparse-fsm-encode] Update template to prevent JG compile error (Michael Schaffner) * Gracefully shut down Verilator when software test fails (Philipp Wagner) * [otp] fix FPV compile error (Cindy Chen) * [dvsim] Kill subprocesses more gracefully (Rupert Swarbrick) * [prim] Fix Verilator lint warnings (Pirmin Vogel) * [memutil] Allocate the right number of bytes in StagedMem::GetFlat() (Rupert Swarbrick) * [memutil] Load ELF files via a staging area (Rupert Swarbrick) * [memutil] Add iterator and merging insertion interfaces to RangedMap (Rupert Swarbrick) * [memutil] Factor out "ranged map" implementation from dpi_memutil (Rupert Swarbrick) * [alert_handler] update alert hander ports (Timothy Chen) * [otp_ctrl] Update OTP output data mapping (Michael Schaffner) * [otp_ctrl] Split partition metadata into separate package (Michael Schaffner) * [prim_otp] Add TL-UL regfile for testing (sim only) (Michael Schaffner) * [memutil] Split out the non-verilator part of verilator_memutil (Rupert Swarbrick) * [dv/common] Update DV_CHECK_* macros (Weicai Yang) * [dv/common] Fix testplan path (Weicai Yang) * [prim_assert] Fixed non-UVM part of `ASSERT_ERROR (Srikrishna Iyer) * [otp_ctrl] Simplify and consolidate OTP error codes (Michael Schaffner) * [kmac] Fix critical syntax errors. (Eunchan Kim) * [dv/common] Move testplan from tools directory to data (Weicai Yang) * [dvsim] Rename verbosity wildcards to something more informative (Rupert Swarbrick) * [dv/lfsr] Update prim_lfsr_sim_cfg.hjson and add coverage (Udi Jonnalagadda) * [dv common] Added string check macros (Srikrishna Iyer) * [rtl] Use platform-agnostic log macros prim_assert (Srikrishna Iyer) * [dv] Minor fixups to dv_Utils_pkg (Srikrishna Iyer) * [dv] Fix platform-agnostic log macros (Srikrishna Iyer) * [checklist] Upgrade wording for D1 milestone (Scott Johnson) * [entropy_src/rtl] fix for dv sanity test (Mark Branstad) * [lint] Add option to bail out on first invalid Tcl cmd (Michael Schaffner) * [sram_ctrl] Add first cut implementation (Michael Schaffner) * [prim] Fix AscentLint waiver that made the tool crash (Michael Schaffner) * [checklists] Clean up and align HW and SW checklists (Michael Schaffner) * [prim] Update signal name in lint waiver rule (Pirmin Vogel) * [flash_ctrl] Switch to new keyschedule in PRINCE (Michael Schaffner) * [lint] fix the waiver format (Eunchan Kim) * [dv] Waive lint warnings in dv_macros.svh (Srikrishna Iyer) * [dv common] Add platform-agnostic log macros (Srikrishna Iyer) * [util] Add Rust Enum Support to sparse-fsm-encode.py (Sam Elliott) * [util] Add C Enum Support to sparse-fsm-encode.py (Sam Elliott) * [sparse-fsm-encode] Expand error and help messages (Michael Schaffner) * [dv/common] TLUL agent function coverage (Weicai Yang) * [dv/shadow_reg] support alert handshake checking (Cindy Chen) * [prim_present/otp_ctrl] Add round index state IOs to primitive (Michael Schaffner) * [dv] Fix 2 regression failures (Weicai Yang) * [prim_multibit_sync] Add multibit synchronizer with consistency check (Michael Schaffner) * [prim] Fix Lint warning for prim_slicer (Eunchan Kim) * [prim_generic_otp] Add TL-UL test interface stub for DV (Michael Schaffner) * [doc] Improve documentation for common_ifs (Rupert Swarbrick) * [doc] Improve pins_if block diagram (Rupert Swarbrick) * [prim_prince/present] Remove TODOs (Michael Schaffner) * [dv/common] Change TL item content when it's not accepted (Weicai Yang) * [dv/uvmgen] update has_alerts (Cindy Chen) * [dv/common] Add run opt plusarg to enable file path in the log (Weicai Yang) * [prim] Add clock buffer primitive for Xilinx FPGAs (Pirmin Vogel) * [otp_ctrl] Provision power sequencing signals (Michael Schaffner) * [dv/common] Clean up old makefile flow (Weicai Yang) * [entropy_src/rtl] review round2 changes (Mark Branstad) * [otp_ctrl] Update all FSMs to use prim_flop for the state (Michael Schaffner) * [prim_xilinx_flop] Add a Xilinx version with keep attribute (Michael Schaffner) * [prim/util] Update sparse-fsm-encode and include FSM template (Michael Schaffner) * [DV macros] minor enhancement to `DV_SPINWAIT (Srikrishna Iyer) * [DV common] Add DV_ASSERT_CTRL macro (Srikrishna Iyer) * [DV common] Enhance `DV_CHECK_MEMBER_RANDOMIZE_*` (Srikrishna Iyer) * [otbn] Use relative scope names for OTBN scopes (Rupert Swarbrick) * [verilator simutil] Add support for relative scope names to SVScoped (Rupert Swarbrick) * [fpv/prim_packer] remove assumption (Cindy Chen) * [fpv/csr_assert] support all modules for CSR assert (Cindy Chen) * [memutil] Teach verilator_memutil to load multi-segment ELF files (Rupert Swarbrick) * [memutil] Simplify how we read ELF files in verilator_memutil.cc (Rupert Swarbrick) * [memutil] Add a "verbose" flag to detail memory loads (Rupert Swarbrick) * [memutil] Parse all arguments before loading anything (Rupert Swarbrick) * [memutil] Use override keyword, not virtual for overridden method (Rupert Swarbrick) * [memutil] Use exceptions to simplify error handling (Rupert Swarbrick) * [memutil] Store the width of memory areas in bytes, not bits (Rupert Swarbrick) * [memutil] Allow memory locations to have associated LMAs (Rupert Swarbrick) * [memutil] Improve type of ElfFileToBinary in verilator_memutil.cc (Rupert Swarbrick) * [verilator simutil] Move SVScoped class into dv/verilator/cpp (Rupert Swarbrick) * [memutil] Move static functions out of VerilatorMemUtil class (Rupert Swarbrick) * [memutil] Run clang-format on verilator_memutil.* (Rupert Swarbrick) * [dv:entropy_src] Initial rng_agent and integrated into entropy_src env (Steve Nelson) * [prim_ram_adv/fpv] fix assertion (Cindy Chen) * [prim_ram_1p_scr] Simplify nonce input and align to multiples of 64b (Michael Schaffner) * [fpv/csr_assert] add csr support for regwen (Cindy Chen) * [prim*] Various lint fixes in the prims (Michael Schaffner) * [prim] remove FPV related assertions (Eunchan Kim) * [prim_lfsr] Add option to supply custom output permutation (Michael Schaffner) * [dv/common] calculate addr map size in RAL (Weicai Yang) * [flash_ctrl] Add ECC to program / erase datapaths (Timothy Chen) * [otp_ctrl] First cut implementation of the OTP controller (Michael Schaffner) * Fix invalid read in verilator_memutil (Rupert Swarbrick) * [doc] Don't strip markdown headings from HW checklist (Philipp Wagner) * [site] Set lint title (Tobias Wölfel) * [dv/prim] add basic PRINCE testbench (Udi Jonnalagadda) * [flash_ctrl] Support the notion of a 'program-repair'. (Timothy Chen) * [prim/tlul] Various small lint fixes (Michael Schaffner) * [dv/uvmdvgen] update dvsim and remove Makefile (Cindy Chen) * [util] Add script for generating sparse FSM encodings (Michael Schaffner) * [prim] Add option to register output for interrupts (Timothy Chen) * [prim_otp] First cut implementation of FPGA emulation (Michael Schaffner) * [prim_ram_1p_adv] Add 16bit ECC mode (Michael Schaffner) * [chip dv] Fix for failing GPIO test (Srikrishna Iyer) * [RTl] Generic pad wrapper default behavior fix (Srikrishna Iyer) * [slicer] Select partial from bitstream (Eunchan Kim) * [util] Don't hack __repr__ in FlowCfg (Rupert Swarbrick) * [util] Fix lint in dvsim.py (Rupert Swarbrick) * [fpv/prim_packer] Add a FPV TB (Cindy Chen) * [Keccak] Keccak_f implementation (Eunchan Kim) * [dv/csr] add common task for csr_or_field_rd_check (Cindy Chen) * [keccak] Add valid signal to random value (Eunchan Kim) * [prim] Add primitive clock divider (Timothy Chen) * [dv/shadow_reg] update sequence for storage error (Cindy Chen) * [dv/lib] clear csr_outstanding_access after reset (Cindy Chen) * [sw] Ensure Headers are Correctly Ordered (Sam Elliott) * [dv] Fix csr_rd check during reset (Weicai Yang) * Adding the first update to coverage methodology (Rasmus Madsen) * [dv] TL agent supports no clock reset (Weicai Yang) * [tlul/dv] Update test plan for tl errors (Weicai Yang) * [fpv/alert] update namings for FPV tb (Cindy Chen) * [keccak] Masked/Unmasked Keccak single round (Eunchan Kim) * [lint/prim*] Waive STAR_PORT_CONN_USE errors in generated prims (Michael Schaffner) * [prim_usb_diff_rx] Carry over wrapper for USB diff receiver (Michael Schaffner) Signed-off-by: Rupert Swarbrick --- dv/uvm/icache/dv/Makefile | 2 +- dv/uvm/icache/dv/ibex_icache_sim_cfg.hjson | 4 +- vendor/lowrisc_ip.lock.hjson | 2 +- vendor/lowrisc_ip.vendor.hjson | 19 +- vendor/lowrisc_ip/dv/sv/common_ifs/index.md | 115 +-- vendor/lowrisc_ip/dv/sv/common_ifs/pins_if.sv | 33 +- .../lowrisc_ip/dv/sv/common_ifs/pins_if.svg | 97 ++- vendor/lowrisc_ip/dv/sv/csr_utils/README.md | 2 +- .../lowrisc_ip/dv/sv/csr_utils/csr_seq_lib.sv | 60 +- .../dv/sv/csr_utils/csr_utils_pkg.sv | 173 +++-- .../dv/sv/dv_base_reg/dv_base_reg.sv | 50 +- .../dv/sv/dv_base_reg/dv_base_reg_block.sv | 131 +++- .../dv/sv/dv_base_reg/dv_base_reg_pkg.sv | 9 + vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_env.sv | 11 - .../dv/sv/dv_lib/dv_base_env_cfg.sv | 46 +- .../dv/sv/dv_lib/dv_base_env_cov.sv | 14 +- .../dv/sv/dv_lib/dv_base_scoreboard.sv | 19 +- .../lowrisc_ip/dv/sv/dv_lib/dv_base_vseq.sv | 26 +- .../lowrisc_ip/dv/sv/dv_utils/dv_macros.core | 17 + .../lowrisc_ip/dv/sv/dv_utils/dv_macros.svh | 234 +++++- .../dv/sv/dv_utils/dv_report_server.sv | 5 +- .../lowrisc_ip/dv/sv/dv_utils/dv_utils.core | 3 +- .../lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv | 42 +- .../lowrisc_ip/dv/sv/dv_utils/dv_vif_wrap.sv | 96 +++ vendor/lowrisc_ip/dv/tools/Makefile | 96 --- vendor/lowrisc_ip/dv/tools/README.md | 227 +----- vendor/lowrisc_ip/dv/tools/common.tcl | 61 ++ vendor/lowrisc_ip/dv/tools/common_tests.mk | 66 -- .../{data => tools/dvsim}/common_modes.hjson | 0 .../dvsim}/common_sim_cfg.hjson | 85 +-- .../dv/{data/dsim => tools/dvsim}/dsim.hjson | 59 +- .../dv/{data => tools/dvsim}/fusesoc.hjson | 0 .../riviera => tools/dvsim}/riviera.hjson | 11 +- .../dv/{data => tools/dvsim}/sim.mk | 25 +- .../{ => dvsim}/testplans/csr_testplan.hjson | 0 .../testplans/enable_reg_testplan.hjson | 0 .../testplans/fpv_csr_testplan.hjson | 0 .../testplans/intr_test_testplan.hjson | 0 .../{ => dvsim}/testplans/mem_testplan.hjson | 0 .../shadow_reg_errors_testplan.hjson | 0 .../stress_all_with_reset_testplan.hjson | 0 .../tl_device_access_types_testplan.hjson | 57 ++ .../dvsim}/tests/csr_tests.hjson | 2 +- .../dvsim}/tests/intr_test.hjson | 0 .../dvsim}/tests/mem_tests.hjson | 0 .../tests/shadow_reg_errors_tests.hjson | 0 .../dvsim}/tests/stress_tests.hjson | 0 .../dvsim}/tests/tl_access_tests.hjson | 0 .../dv/{data/vcs => tools/dvsim}/vcs.hjson | 72 +- .../xcelium => tools/dvsim}/xcelium.hjson | 36 +- vendor/lowrisc_ip/dv/tools/fail_patterns | 3 - vendor/lowrisc_ip/dv/tools/fusesoc.mk | 16 - vendor/lowrisc_ip/dv/tools/modes.mk | 58 -- vendor/lowrisc_ip/dv/tools/pass_fail | 34 - vendor/lowrisc_ip/dv/tools/pass_patterns | 1 - .../dv/{data => tools}/riviera/riviera_run.do | 0 vendor/lowrisc_ip/dv/tools/rules.mk | 97 --- vendor/lowrisc_ip/dv/tools/run_dir_limiter | 28 - vendor/lowrisc_ip/dv/tools/sim.tcl | 21 + .../tl_device_access_types_testplan.hjson | 40 -- vendor/lowrisc_ip/dv/tools/vcs/vcs.mk | 117 --- vendor/lowrisc_ip/dv/tools/vcs/vcs.tcl | 26 - vendor/lowrisc_ip/dv/tools/vcs/xprop.cfg | 4 + vendor/lowrisc_ip/dv/tools/waves.tcl | 179 ++++- vendor/lowrisc_ip/dv/tools/xcelium/xcelium.mk | 53 -- .../lowrisc_ip/dv/tools/xcelium/xcelium.tcl | 26 - .../dv/verilator/cpp/dpi_memutil.cc | 666 ++++++++++++++++++ .../lowrisc_ip/dv/verilator/cpp/dpi_memutil.h | 166 +++++ .../lowrisc_ip/dv/verilator/cpp/ranged_map.h | 181 +++++ .../lowrisc_ip/dv/verilator/cpp/sv_scoped.cc | 95 +++ .../lowrisc_ip/dv/verilator/cpp/sv_scoped.h | 51 ++ .../dv/verilator/cpp/verilator_memutil.cc | 508 +++---------- .../dv/verilator/cpp/verilator_memutil.h | 125 +--- .../lowrisc_ip/dv/verilator/memutil_dpi.core | 21 + .../dv/verilator/memutil_verilator.core | 1 + .../cpp/verilator_sim_ctrl.cc | 12 + .../ip/prim/doc/prim_packer_fifo.md | 67 ++ vendor/lowrisc_ip/ip/prim/doc/prim_present.md | 42 +- .../dv/prim_lfsr/data/prim_lfsr_cov_excl.el | 48 ++ .../dv/prim_lfsr/data/prim_lfsr_cover.cfg | 12 + .../prim_lfsr/data/prim_lfsr_cover_assert.cfg | 9 + .../ip/prim/dv/prim_lfsr/prim_lfsr_sim.core | 5 +- .../prim/dv/prim_lfsr/prim_lfsr_sim_cfg.hjson | 31 +- .../dv/prim_lfsr/prim_lfsr_testplan.hjson | 16 - .../ip/prim/dv/prim_lfsr/tb/prim_lfsr_tb.sv | 80 ++- .../prim_present/data/prim_present_cover.cfg | 4 + .../data/prim_present_testplan.hjson | 4 +- .../dv/prim_present/prim_present_sim.core | 5 +- .../prim_present/prim_present_sim_cfg.hjson | 8 +- .../dv/prim_present/tb/prim_present_tb.sv | 41 +- .../crypto_dpi_prince/crypto_dpi_prince.c | 33 + .../crypto_dpi_prince/crypto_dpi_prince.core | 17 + .../crypto_dpi_prince_pkg.sv | 64 ++ .../crypto_dpi_prince/prince_ref.h | 344 +++++++++ .../dv/prim_prince/data/prim_prince_cover.cfg | 11 + .../prim/dv/prim_prince/prim_prince_sim.core | 31 + .../dv/prim_prince/prim_prince_sim_cfg.hjson | 57 ++ .../prim/dv/prim_prince/tb/prim_prince_tb.sv | 297 ++++++++ .../prim/fpv/prim_alert_rxtx_async_fpv.core | 3 + .../ip/prim/fpv/prim_alert_rxtx_fpv.core | 3 + .../ip/prim/fpv/prim_arbiter_fixed_fpv.core | 3 + .../ip/prim/fpv/prim_arbiter_ppc_fpv.core | 3 + .../ip/prim/fpv/prim_arbiter_tree_fpv.core | 3 + .../ip/prim/fpv/prim_esc_rxtx_fpv.core | 3 + .../ip/prim/fpv/prim_fifo_sync_fpv.core | 3 + .../ip/prim/fpv/prim_keccak_fpv.core | 5 +- .../lowrisc_ip/ip/prim/fpv/prim_lfsr_fpv.core | 3 + .../ip/prim/fpv/prim_packer_fpv.core | 30 + .../fpv/tb/prim_alert_rxtx_async_bind_fpv.sv | 5 +- .../prim/fpv/tb/prim_alert_rxtx_async_fpv.sv | 14 +- .../prim/fpv/tb/prim_alert_rxtx_bind_fpv.sv | 5 +- .../ip/prim/fpv/tb/prim_alert_rxtx_fpv.sv | 14 +- .../ip/prim/fpv/tb/prim_esc_rxtx_bind_fpv.sv | 4 +- .../ip/prim/fpv/tb/prim_esc_rxtx_fpv.sv | 8 +- .../ip/prim/fpv/tb/prim_packer_fpv.sv | 63 ++ .../fpv/vip/prim_alert_rxtx_assert_fpv.sv | 41 +- .../vip/prim_alert_rxtx_async_assert_fpv.sv | 43 +- .../prim/fpv/vip/prim_esc_rxtx_assert_fpv.sv | 20 +- vendor/lowrisc_ip/ip/prim/lint/prim.waiver | 8 + .../ip/prim/lint/prim_clock_buf.waiver | 8 + .../ip/prim/lint/prim_clock_div.waiver | 5 + .../ip/prim/lint/prim_clock_gating.waiver | 8 + .../ip/prim/lint/prim_clock_inv.waiver | 8 + .../ip/prim/lint/prim_clock_mux2.waiver | 8 + .../lowrisc_ip/ip/prim/lint/prim_flash.waiver | 8 + .../lowrisc_ip/ip/prim/lint/prim_flop.waiver | 8 + .../ip/prim/lint/prim_flop_2sync.waiver | 8 + .../lowrisc_ip/ip/prim/lint/prim_otp.waiver | 8 + .../ip/prim/lint/prim_pad_wrapper.waiver | 8 + .../ip/prim/lint/prim_ram_1p.waiver | 8 + .../ip/prim/lint/prim_ram_1p_adv.waiver | 8 + .../ip/prim/lint/prim_ram_2p.waiver | 8 + .../lowrisc_ip/ip/prim/lint/prim_rom.waiver | 8 + .../ip/prim/lint/prim_usb_diff_rx.waiver | 8 + .../cpp/prim_sync_reqack_tb.cc | 2 +- vendor/lowrisc_ip/ip/prim/prim.core | 3 +- vendor/lowrisc_ip/ip/prim/prim_clock_buf.core | 25 + vendor/lowrisc_ip/ip/prim/prim_clock_div.core | 22 + .../lowrisc_ip/ip/prim/prim_clock_gating.core | 25 + vendor/lowrisc_ip/ip/prim/prim_clock_inv.core | 25 + .../lowrisc_ip/ip/prim/prim_clock_mux2.core | 25 + vendor/lowrisc_ip/ip/prim/prim_flash.core | 25 + vendor/lowrisc_ip/ip/prim/prim_flop.core | 24 + .../lowrisc_ip/ip/prim/prim_flop_2sync.core | 26 + vendor/lowrisc_ip/ip/prim/prim_lc_sync.core | 61 ++ vendor/lowrisc_ip/ip/prim/prim_lfsr.core | 41 +- .../ip/prim/prim_multibit_sync.core | 20 + vendor/lowrisc_ip/ip/prim/prim_otp.core | 25 + .../lowrisc_ip/ip/prim/prim_pad_wrapper.core | 25 + vendor/lowrisc_ip/ip/prim/prim_ram_1p.core | 25 + .../lowrisc_ip/ip/prim/prim_ram_1p_adv.core | 25 +- vendor/lowrisc_ip/ip/prim/prim_ram_2p.core | 25 + vendor/lowrisc_ip/ip/prim/prim_rom.core | 25 + vendor/lowrisc_ip/ip/prim/prim_secded.core | 2 + .../lowrisc_ip/ip/prim/prim_usb_diff_rx.core | 50 ++ .../ip/prim/rtl/prim_alert_sender.sv | 74 +- .../ip/prim/rtl/prim_arbiter_fixed.sv | 7 +- .../ip/prim/rtl/prim_arbiter_tree.sv | 16 +- vendor/lowrisc_ip/ip/prim/rtl/prim_assert.sv | 24 +- .../prim/rtl/prim_assert_standard_macros.svh | 45 +- .../lowrisc_ip/ip/prim/rtl/prim_cipher_pkg.sv | 36 +- .../lowrisc_ip/ip/prim/rtl/prim_clock_div.sv | 84 +++ .../ip/prim/rtl/prim_dom_and_2share.sv | 51 +- .../lowrisc_ip/ip/prim/rtl/prim_fifo_async.sv | 4 +- .../lowrisc_ip/ip/prim/rtl/prim_fifo_sync.sv | 4 +- vendor/lowrisc_ip/ip/prim/rtl/prim_intr_hw.sv | 30 +- vendor/lowrisc_ip/ip/prim/rtl/prim_keccak.sv | 2 +- vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sync.sv | 58 ++ vendor/lowrisc_ip/ip/prim/rtl/prim_lfsr.sv | 32 +- .../ip/prim/rtl/prim_multibit_sync.sv | 103 +++ vendor/lowrisc_ip/ip/prim/rtl/prim_packer.sv | 10 +- .../ip/prim/rtl/prim_packer_fifo.sv | 165 +++++ vendor/lowrisc_ip/ip/prim/rtl/prim_present.sv | 68 +- vendor/lowrisc_ip/ip/prim/rtl/prim_prince.sv | 32 +- .../lowrisc_ip/ip/prim/rtl/prim_ram_1p_adv.sv | 20 +- .../lowrisc_ip/ip/prim/rtl/prim_ram_1p_scr.sv | 65 +- .../ip/prim/rtl/prim_ram_2p_async_adv.sv | 7 +- .../ip/prim/rtl/prim_secded_22_16_dec.sv | 48 ++ .../ip/prim/rtl/prim_secded_22_16_enc.sv | 35 + .../ip/prim/rtl/prim_secded_72_64_dec.sv | 44 +- .../ip/prim/rtl/prim_secded_72_64_enc.sv | 16 +- vendor/lowrisc_ip/ip/prim/rtl/prim_slicer.sv | 32 + .../lowrisc_ip/ip/prim/rtl/prim_subst_perm.sv | 4 +- .../ip/prim/rtl/prim_util_memload.svh | 16 +- .../lowrisc_ip/ip/prim/util/gen-lfsr-seed.py | 142 ++++ vendor/lowrisc_ip/ip/prim/util/primgen.py | 1 + .../ip/prim/util/primgen/abstract_prim.sv.tpl | 10 + .../ip/prim/util/sparse-fsm-encode.py | 333 +++++++++ .../lint/prim_generic_clock_mux2.waiver | 3 + .../prim_generic/lint/prim_generic_otp.waiver | 3 + .../lint/prim_generic_ram_1p.waiver | 2 - .../prim_generic/lint/prim_generic_ram_2p.vlt | 5 + .../lint/prim_generic_ram_2p.waiver | 2 +- .../ip/prim_generic/prim_generic_flash.core | 1 + .../ip/prim_generic/prim_generic_otp.core | 2 + .../prim_generic_usb_diff_rx.core | 42 ++ .../rtl/prim_generic_clock_gating.sv | 4 +- .../rtl/prim_generic_clock_mux2.sv | 4 +- .../ip/prim_generic/rtl/prim_generic_flash.sv | 390 ++-------- .../rtl/prim_generic_flash_bank.sv | 415 +++++++++++ .../ip/prim_generic/rtl/prim_generic_otp.sv | 392 ++++++++--- .../rtl/prim_generic_pad_wrapper.sv | 3 +- .../rtl/prim_generic_usb_diff_rx.sv | 32 + .../lint/prim_xilinx_clock_buf.vlt | 4 + .../lint/prim_xilinx_clock_buf.waiver | 4 + .../lint/prim_xilinx_pad_wrapper.waiver | 8 +- .../ip/prim_xilinx/prim_xilinx_clock_buf.core | 42 ++ .../ip/prim_xilinx/prim_xilinx_flop.core | 40 ++ .../prim_xilinx/rtl/prim_xilinx_clock_buf.sv | 15 + .../rtl/prim_xilinx_clock_gating.sv | 20 +- .../prim_xilinx/rtl/prim_xilinx_clock_mux2.sv | 26 +- .../ip/prim_xilinx/rtl/prim_xilinx_flop.sv | 27 + vendor/lowrisc_ip/lint/doc/README.md | 8 + .../tools/ascentlint/parse-lint-report.py | 4 +- .../{data => tools/dvsim}/ascentlint.hjson | 0 .../dvsim}/common_lint_cfg.hjson | 4 +- .../lint/{data => tools/dvsim}/lint.mk | 0 .../{data => tools/dvsim}/veriblelint.hjson | 0 .../{data => tools/dvsim}/verilator.hjson | 0 vendor/lowrisc_ip/util/dvsim/Deploy.py | 61 +- vendor/lowrisc_ip/util/dvsim/FlowCfg.py | 24 +- vendor/lowrisc_ip/util/dvsim/Makefile | 7 + vendor/lowrisc_ip/util/dvsim/OneShotCfg.py | 2 - vendor/lowrisc_ip/util/dvsim/SimCfg.py | 112 +-- vendor/lowrisc_ip/util/dvsim/dvsim.py | 43 +- .../util/dvsim/testplanner/README.md | 8 +- .../examples/foo_regr_results.hjson | 2 +- .../testplanner/examples/foo_testplan.hjson | 12 +- vendor/lowrisc_ip/util/dvsim/utils.py | 271 +++++-- vendor/lowrisc_ip/util/dvsim/utils_test.py | 77 ++ vendor/lowrisc_ip/util/uvmdvgen/Makefile.tpl | 46 -- vendor/lowrisc_ip/util/uvmdvgen/README.md | 20 +- .../lowrisc_ip/util/uvmdvgen/agent_pkg.sv.tpl | 2 +- .../lowrisc_ip/util/uvmdvgen/checklist.md.tpl | 324 ++++----- vendor/lowrisc_ip/util/uvmdvgen/driver.sv.tpl | 3 +- vendor/lowrisc_ip/util/uvmdvgen/env.core.tpl | 2 +- .../lowrisc_ip/util/uvmdvgen/env_cfg.sv.tpl | 9 +- .../lowrisc_ip/util/uvmdvgen/env_pkg.sv.tpl | 7 +- vendor/lowrisc_ip/util/uvmdvgen/gen_env.py | 24 +- vendor/lowrisc_ip/util/uvmdvgen/index.md.tpl | 7 +- .../util/uvmdvgen/scoreboard.sv.tpl | 2 +- vendor/lowrisc_ip/util/uvmdvgen/sim.core.tpl | 6 +- .../util/uvmdvgen/sim_cfg.hjson.tpl | 28 +- .../{sanity_vseq.sv.tpl => smoke_vseq.sv.tpl} | 8 +- vendor/lowrisc_ip/util/uvmdvgen/sva.core.tpl | 12 +- vendor/lowrisc_ip/util/uvmdvgen/tb.sv.tpl | 33 +- .../util/uvmdvgen/testplan.hjson.tpl | 14 +- vendor/lowrisc_ip/util/uvmdvgen/uvmdvgen.py | 24 +- .../lowrisc_ip/util/uvmdvgen/vseq_list.sv.tpl | 2 +- .../0001-common-sim-cfg.patch | 22 +- .../dv_utils/0001-use-ibex-bus-params.patch | 6 +- 251 files changed, 7926 insertions(+), 3103 deletions(-) create mode 100644 vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.core create mode 100644 vendor/lowrisc_ip/dv/sv/dv_utils/dv_vif_wrap.sv delete mode 100644 vendor/lowrisc_ip/dv/tools/Makefile create mode 100644 vendor/lowrisc_ip/dv/tools/common.tcl delete mode 100644 vendor/lowrisc_ip/dv/tools/common_tests.mk rename vendor/lowrisc_ip/dv/{data => tools/dvsim}/common_modes.hjson (100%) rename vendor/lowrisc_ip/dv/{data => tools/dvsim}/common_sim_cfg.hjson (71%) rename vendor/lowrisc_ip/dv/{data/dsim => tools/dvsim}/dsim.hjson (78%) rename vendor/lowrisc_ip/dv/{data => tools/dvsim}/fusesoc.hjson (100%) rename vendor/lowrisc_ip/dv/{data/riviera => tools/dvsim}/riviera.hjson (88%) rename vendor/lowrisc_ip/dv/{data => tools/dvsim}/sim.mk (79%) rename vendor/lowrisc_ip/dv/tools/{ => dvsim}/testplans/csr_testplan.hjson (100%) rename vendor/lowrisc_ip/dv/tools/{ => dvsim}/testplans/enable_reg_testplan.hjson (100%) rename vendor/lowrisc_ip/dv/tools/{ => dvsim}/testplans/fpv_csr_testplan.hjson (100%) rename vendor/lowrisc_ip/dv/tools/{ => dvsim}/testplans/intr_test_testplan.hjson (100%) rename vendor/lowrisc_ip/dv/tools/{ => dvsim}/testplans/mem_testplan.hjson (100%) rename vendor/lowrisc_ip/dv/tools/{ => dvsim}/testplans/shadow_reg_errors_testplan.hjson (100%) rename vendor/lowrisc_ip/dv/tools/{ => dvsim}/testplans/stress_all_with_reset_testplan.hjson (100%) create mode 100644 vendor/lowrisc_ip/dv/tools/dvsim/testplans/tl_device_access_types_testplan.hjson rename vendor/lowrisc_ip/dv/{data => tools/dvsim}/tests/csr_tests.hjson (98%) rename vendor/lowrisc_ip/dv/{data => tools/dvsim}/tests/intr_test.hjson (100%) rename vendor/lowrisc_ip/dv/{data => tools/dvsim}/tests/mem_tests.hjson (100%) rename vendor/lowrisc_ip/dv/{data => tools/dvsim}/tests/shadow_reg_errors_tests.hjson (100%) rename vendor/lowrisc_ip/dv/{data => tools/dvsim}/tests/stress_tests.hjson (100%) rename vendor/lowrisc_ip/dv/{data => tools/dvsim}/tests/tl_access_tests.hjson (100%) rename vendor/lowrisc_ip/dv/{data/vcs => tools/dvsim}/vcs.hjson (70%) rename vendor/lowrisc_ip/dv/{data/xcelium => tools/dvsim}/xcelium.hjson (80%) delete mode 100644 vendor/lowrisc_ip/dv/tools/fail_patterns delete mode 100644 vendor/lowrisc_ip/dv/tools/fusesoc.mk delete mode 100644 vendor/lowrisc_ip/dv/tools/modes.mk delete mode 100644 vendor/lowrisc_ip/dv/tools/pass_fail delete mode 100644 vendor/lowrisc_ip/dv/tools/pass_patterns rename vendor/lowrisc_ip/dv/{data => tools}/riviera/riviera_run.do (100%) delete mode 100644 vendor/lowrisc_ip/dv/tools/rules.mk delete mode 100755 vendor/lowrisc_ip/dv/tools/run_dir_limiter create mode 100644 vendor/lowrisc_ip/dv/tools/sim.tcl delete mode 100644 vendor/lowrisc_ip/dv/tools/testplans/tl_device_access_types_testplan.hjson delete mode 100644 vendor/lowrisc_ip/dv/tools/vcs/vcs.mk delete mode 100644 vendor/lowrisc_ip/dv/tools/vcs/vcs.tcl delete mode 100644 vendor/lowrisc_ip/dv/tools/xcelium/xcelium.mk delete mode 100644 vendor/lowrisc_ip/dv/tools/xcelium/xcelium.tcl create mode 100644 vendor/lowrisc_ip/dv/verilator/cpp/dpi_memutil.cc create mode 100644 vendor/lowrisc_ip/dv/verilator/cpp/dpi_memutil.h create mode 100644 vendor/lowrisc_ip/dv/verilator/cpp/ranged_map.h create mode 100644 vendor/lowrisc_ip/dv/verilator/cpp/sv_scoped.cc create mode 100644 vendor/lowrisc_ip/dv/verilator/cpp/sv_scoped.h create mode 100644 vendor/lowrisc_ip/dv/verilator/memutil_dpi.core create mode 100644 vendor/lowrisc_ip/ip/prim/doc/prim_packer_fifo.md create mode 100644 vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/data/prim_lfsr_cov_excl.el create mode 100644 vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/data/prim_lfsr_cover.cfg create mode 100644 vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/data/prim_lfsr_cover_assert.cfg delete mode 100644 vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_testplan.hjson create mode 100644 vendor/lowrisc_ip/ip/prim/dv/prim_prince/crypto_dpi_prince/crypto_dpi_prince.c create mode 100644 vendor/lowrisc_ip/ip/prim/dv/prim_prince/crypto_dpi_prince/crypto_dpi_prince.core create mode 100644 vendor/lowrisc_ip/ip/prim/dv/prim_prince/crypto_dpi_prince/crypto_dpi_prince_pkg.sv create mode 100644 vendor/lowrisc_ip/ip/prim/dv/prim_prince/crypto_dpi_prince/prince_ref.h create mode 100644 vendor/lowrisc_ip/ip/prim/dv/prim_prince/data/prim_prince_cover.cfg create mode 100644 vendor/lowrisc_ip/ip/prim/dv/prim_prince/prim_prince_sim.core create mode 100644 vendor/lowrisc_ip/ip/prim/dv/prim_prince/prim_prince_sim_cfg.hjson create mode 100644 vendor/lowrisc_ip/ip/prim/dv/prim_prince/tb/prim_prince_tb.sv create mode 100644 vendor/lowrisc_ip/ip/prim/fpv/prim_packer_fpv.core create mode 100644 vendor/lowrisc_ip/ip/prim/fpv/tb/prim_packer_fpv.sv create mode 100644 vendor/lowrisc_ip/ip/prim/lint/prim_clock_buf.waiver create mode 100644 vendor/lowrisc_ip/ip/prim/lint/prim_clock_div.waiver create mode 100644 vendor/lowrisc_ip/ip/prim/lint/prim_clock_gating.waiver create mode 100644 vendor/lowrisc_ip/ip/prim/lint/prim_clock_inv.waiver create mode 100644 vendor/lowrisc_ip/ip/prim/lint/prim_clock_mux2.waiver create mode 100644 vendor/lowrisc_ip/ip/prim/lint/prim_flash.waiver create mode 100644 vendor/lowrisc_ip/ip/prim/lint/prim_flop.waiver create mode 100644 vendor/lowrisc_ip/ip/prim/lint/prim_flop_2sync.waiver create mode 100644 vendor/lowrisc_ip/ip/prim/lint/prim_otp.waiver create mode 100644 vendor/lowrisc_ip/ip/prim/lint/prim_pad_wrapper.waiver create mode 100644 vendor/lowrisc_ip/ip/prim/lint/prim_ram_1p.waiver create mode 100644 vendor/lowrisc_ip/ip/prim/lint/prim_ram_1p_adv.waiver create mode 100644 vendor/lowrisc_ip/ip/prim/lint/prim_ram_2p.waiver create mode 100644 vendor/lowrisc_ip/ip/prim/lint/prim_rom.waiver create mode 100644 vendor/lowrisc_ip/ip/prim/lint/prim_usb_diff_rx.waiver create mode 100644 vendor/lowrisc_ip/ip/prim/prim_clock_div.core create mode 100644 vendor/lowrisc_ip/ip/prim/prim_lc_sync.core create mode 100644 vendor/lowrisc_ip/ip/prim/prim_multibit_sync.core create mode 100644 vendor/lowrisc_ip/ip/prim/prim_usb_diff_rx.core create mode 100644 vendor/lowrisc_ip/ip/prim/rtl/prim_clock_div.sv create mode 100644 vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sync.sv create mode 100644 vendor/lowrisc_ip/ip/prim/rtl/prim_multibit_sync.sv create mode 100755 vendor/lowrisc_ip/ip/prim/rtl/prim_packer_fifo.sv create mode 100644 vendor/lowrisc_ip/ip/prim/rtl/prim_secded_22_16_dec.sv create mode 100644 vendor/lowrisc_ip/ip/prim/rtl/prim_secded_22_16_enc.sv create mode 100644 vendor/lowrisc_ip/ip/prim/rtl/prim_slicer.sv create mode 100755 vendor/lowrisc_ip/ip/prim/util/gen-lfsr-seed.py create mode 100755 vendor/lowrisc_ip/ip/prim/util/sparse-fsm-encode.py create mode 100644 vendor/lowrisc_ip/ip/prim_generic/prim_generic_usb_diff_rx.core create mode 100644 vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash_bank.sv create mode 100644 vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_usb_diff_rx.sv create mode 100644 vendor/lowrisc_ip/ip/prim_xilinx/lint/prim_xilinx_clock_buf.vlt create mode 100644 vendor/lowrisc_ip/ip/prim_xilinx/lint/prim_xilinx_clock_buf.waiver create mode 100644 vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_clock_buf.core create mode 100644 vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_flop.core create mode 100644 vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_clock_buf.sv create mode 100644 vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_flop.sv rename vendor/lowrisc_ip/lint/{data => tools/dvsim}/ascentlint.hjson (100%) rename vendor/lowrisc_ip/lint/{data => tools/dvsim}/common_lint_cfg.hjson (89%) rename vendor/lowrisc_ip/lint/{data => tools/dvsim}/lint.mk (100%) rename vendor/lowrisc_ip/lint/{data => tools/dvsim}/veriblelint.hjson (100%) rename vendor/lowrisc_ip/lint/{data => tools/dvsim}/verilator.hjson (100%) create mode 100644 vendor/lowrisc_ip/util/dvsim/Makefile create mode 100644 vendor/lowrisc_ip/util/dvsim/utils_test.py delete mode 100644 vendor/lowrisc_ip/util/uvmdvgen/Makefile.tpl rename vendor/lowrisc_ip/util/uvmdvgen/{sanity_vseq.sv.tpl => smoke_vseq.sv.tpl} (60%) rename vendor/patches/lowrisc_ip/{dv_data => dv_tools}/0001-common-sim-cfg.patch (64%) diff --git a/dv/uvm/icache/dv/Makefile b/dv/uvm/icache/dv/Makefile index 008a9c9fb9..2ec0f1e3c9 100644 --- a/dv/uvm/icache/dv/Makefile +++ b/dv/uvm/icache/dv/Makefile @@ -25,7 +25,7 @@ default-seed := 123 SEED=$(if $(filter 1,$(RESEED)),$(default-seed),) # Specify which tests to run. Defaults to the empty string, which -# means dvsim will run its default (the "sanity" suite). +# means dvsim will run its default (the "smoke" suite of tests). TESTS= ibex-top := ../../../.. diff --git a/dv/uvm/icache/dv/ibex_icache_sim_cfg.hjson b/dv/uvm/icache/dv/ibex_icache_sim_cfg.hjson index 737eac4b13..dbc7920e56 100644 --- a/dv/uvm/icache/dv/ibex_icache_sim_cfg.hjson +++ b/dv/uvm/icache/dv/ibex_icache_sim_cfg.hjson @@ -23,7 +23,7 @@ // Import additional common sim cfg files. import_cfgs: [ // Project wide common sim cfg file - "{proj_root}/vendor/lowrisc_ip/dv/data/common_sim_cfg.hjson" + "{proj_root}/vendor/lowrisc_ip/dv/tools/dvsim/common_sim_cfg.hjson" ] build_modes: [ @@ -111,7 +111,7 @@ // List of regressions. regressions: [ { - name: sanity + name: smoke tests: ["ibex_icache_sanity", "ibex_icache_passthru", "ibex_icache_caching", diff --git a/vendor/lowrisc_ip.lock.hjson b/vendor/lowrisc_ip.lock.hjson index 9498185ddb..6a129b9de2 100644 --- a/vendor/lowrisc_ip.lock.hjson +++ b/vendor/lowrisc_ip.lock.hjson @@ -9,6 +9,6 @@ upstream: { url: https://github.com/lowRISC/opentitan - rev: 92e9242424c72c59008e267dd3779e2af5ec8e83 + rev: e619fc60c6b9c755043eba65a41dc47815612834 } } diff --git a/vendor/lowrisc_ip.vendor.hjson b/vendor/lowrisc_ip.vendor.hjson index 786dc7c54d..3e744b542e 100644 --- a/vendor/lowrisc_ip.vendor.hjson +++ b/vendor/lowrisc_ip.vendor.hjson @@ -11,20 +11,10 @@ } mapping: [ - // We have to apply a patch to the vendored files from hw/dv/data, - // because they contain an OpenTitan specific path. - { - from: "hw/dv/data", - to: "dv/data", - patch_dir: "dv_data" - }, - {from: "hw/dv/sv/common_ifs", to: "dv/sv/common_ifs"}, {from: "hw/dv/sv/csr_utils", to: "dv/sv/csr_utils"}, {from: "hw/dv/sv/dv_base_reg", to: "dv/sv/dv_base_reg"}, {from: "hw/dv/sv/mem_model", to: "dv/sv/mem_model"}, - {from: "hw/dv/tools", to: "dv/tools"}, - {from: "hw/dv/verilator", to: "dv/verilator"}, // We apply a patch to fix the bus_params_pkg core file name when // vendoring in dv_lib and dv_utils. This allows us to have an @@ -39,6 +29,15 @@ to: "dv/sv/dv_utils", patch_dir: "dv_utils", }, + // We have to apply a patch to the vendored files from hw/dv/tools + // because they contain OpenTitan specific paths. + { + from: "hw/dv/tools", + to: "dv/tools", + patch_dir: "dv_tools" + }, + + {from: "hw/dv/verilator", to: "dv/verilator"}, {from: "hw/ip/prim", to: "ip/prim"}, {from: "hw/ip/prim_generic", to: "ip/prim_generic"}, diff --git a/vendor/lowrisc_ip/dv/sv/common_ifs/index.md b/vendor/lowrisc_ip/dv/sv/common_ifs/index.md index d54a46cb6a..f28e41bb07 100644 --- a/vendor/lowrisc_ip/dv/sv/common_ifs/index.md +++ b/vendor/lowrisc_ip/dv/sv/common_ifs/index.md @@ -8,43 +8,55 @@ connecting dut signals. They are described in detail below. ### `clk_if` This is a passive clock interface that is used to wait for clock events in -testbenches. -This interface has two clocking blocks: `cb` and `cbn` for synchronizing to -positive and negative clock edges. This interface consists of following tasks: +testbenches. This interface has two clocking blocks, `cb` and `cbn`, for +synchronizing to positive and negative clock edges, respectively. The interface +also has the following tasks: * `wait_clks`: waits for specified number of positive clock edges * `wait_n_clks`: waits for specified number of negative clock edges ### `clk_rst_if` -This interface provides the ability to drive / sample clock and reset signal. -It provides various methods related to clock and reset generation. These -methods can be categorized into `setup methods` and `drive / sample` methods. -Following are `setup methods` of `pins_if`: -* `set_freq_mhz`: set the clk frequency in mhz and calclate period in ns -* `set_duty_cycle`: set the duty cycle (1-99) -* `set_active`: enables `clk` and `rst_n` generation - typically, called at t=0 (from tb top) -* `set_period_ns`: set the clk period in ns and calculate frequency in mhz -* `set_jitter_chance_pc`: set jitter chance in percentage (0 - 100) - * 0: do not add any jitter - * 100: add jitter on every clock edge -* `set_max_jitter_ps`: set maximum jitter in ps -Following are `drive / sample` methods of `pins_if`: -* `wait_for_reset`: wait for rst_n to assert and then deassert -* `apply_reset`: apply reset with specified scheme out of following: - * fullly synchronous reset - * async assert, sync dessert - * async assert, async dessert - * clk gated when reset asserted -* `add_jitter`: add jitter to `clk_hi` and `clk_lo` half periods based on - `jitter_chance_pc` -* `start_clk`: start / ungate clock + +Unlike `clk_if`, this interface can generate a clock and a reset signal. These +are connected as `inout` signals and the interface observes them passively +unless the `set_active` function is called. + +Just like `clk_if`, this interface has clocking blocks `cb` and `cbn`, together +with `wait_clks` and `wait_n_clks` utility tasks. It also has +* `wait_for_reset`: wait for a reset signalled on `rst_n` + +To generate a clock signal, call `set_active` at the start of the simulation. +This is typically called from an `initial` block in the testbench. To configure +the frequency and duty cycle of the generated clock, use the following +functions: +* `set_freq_mhz` / `set_freq_khz`: set the clock frequency in MHz / KHz. This + is 50MHz by default. +* `set_period_ns`: set the clock period in nanoseconds. This is 20ns by default + (giving a clock period of 50MHz). +* `set_duty_cycle`: set the duty cycle (as a percentage: 1 - 99). This is 50 by + default. + +The clock can also have jitter added. This is generated as an offset in +picoseconds added to randomly selected clock half-periods. It can be enabled +and configured with: +* `set_jitter_chance_pc`: set the percentage probability of adding a jitter to + a given half-period. By default, this is 0 and the clock has no jitter. +* `set_max_jitter_ps`: set the maximum jitter to add to each clock half-period + in picoseconds. This is 1000ps (1 ns) by default. + +To start and stop the clock or apply a reset, use the following tasks. These +will have no effect if `set_active` has not been called. +* `start_clk`: start the clock. The clock is started by default, so this + task is only needed after a call to `stop_clk`. * `stop_clk`: stop / gate the clk -* `wait_clks`: waits for specified number of positive clock edges -* `wait_n_clks`: waits for specified number of negative clock edges +* `apply_reset`: signal a reset on `rst_n`. The length of this reset and + whether it is synchronous or not can be configured with arguments to the + function. ### `pins_if` -This paramterized interface provides the ability to drive / sample any signal + +This parameterized interface provides the ability to drive or sample any signal in the DUT. + ```systemverilog interface pins_if #( parameter int Width = 1 @@ -52,30 +64,23 @@ interface pins_if #( inout [Width-1:0] pins ); ``` -The member `pins` is inout type and it can be connected to any of input or -output port within of dut to drive or sample them. `pins` can be driven either -internally using `pins_o` and `pins_oe` signals, that constitute a tri-state -buffer implementation. This provide an ability to disconnects `pins` by driving -them to high impedance state. `pins` may also be driven through an external -driver that it gets connected to. This interface also provides capability -to drive weak pull-up or pull-down on `pins` in case of no internal or external -drivers. The members `pins_pu` and `pins_pd` control weak pull-up or pull-down -functionality. Following diagram explains working of `pins_if`: - -## `pins_if` block diagram -![Block diagram](pins_if.svg) -Some of the commonly used methods of `pins_if` are as follows: -* `drive_en_pin`: Drive specified value `val` on specified index `idx` of - `pins_oe` signal -* `drive_en`: Drive `pins_oe` signal to specified value `val` -* `drive_pin`: Drive specified index `idx` of pins_oe signal to 1, and the same - index of `pins_o` to specified value `val` - value -* `drive`: Drive `pins_oe` to all 1's and specified value `val` on `pins_o` -* `sample_pin`: Sample and return value of `pins[idx]` for specified index `idx` -* `sample`: Sample and return value of `pins` -* `set_pullup_en`: Implement pull-up on specific bits of `pins` based on - specified value `val` -* `set_pulldown_en`: Implement pull-down on specifc bits of `pins` based on - specified value `val` +By default, it behaves as a passive interface. The values of the pins can be +read with the following functions: +* `sample`: sample and return all the pin values +* `sample_pin`: sample just the given pin + +The interface can also be configured to drive, pull up, or pull down its +outputs. To do this, call +* `drive` / `drive_pin`: Drive the output to the given value. +* `drive_en` / `drive_en_pin`: Configure output enable; when enabled, this + drives value previously stored by a call to `drive` or `drive_pin`. +* `set_pullup_en` / `set_pullup_en_pin`: Configure pull-up setting. If true and + output enable is false, drives the output to `1`. +* `set_pulldown_en` / `set_pulldown_en_pin`: Configure pull-down setting. If + true and both output_enable and pull-up are false, drives the output to `0`. + +The diagram below gives a schematic view of `pins_if`. The driver shown is +replicated for each bit. + +![Block diagram](pins_if.svg) diff --git a/vendor/lowrisc_ip/dv/sv/common_ifs/pins_if.sv b/vendor/lowrisc_ip/dv/sv/common_ifs/pins_if.sv index 2a419ed78e..636af6fcf3 100644 --- a/vendor/lowrisc_ip/dv/sv/common_ifs/pins_if.sv +++ b/vendor/lowrisc_ip/dv/sv/common_ifs/pins_if.sv @@ -15,7 +15,6 @@ interface pins_if #( logic [Width-1:0] pins_o; // value to be driven out - wire [Width-1:0] pins_int; // value of pin using internal pull-up / pull-down bit [Width-1:0] pins_oe = '0; // output enable bit [Width-1:0] pins_pd = '0; // pull down enable bit [Width-1:0] pins_pu = '0; // pull up enable @@ -73,24 +72,26 @@ interface pins_if #( endfunction // make connections - generate - for (genvar i = 0; i < Width; i++) begin : each_pin - assign pins_int[i] = pins_pd[i] ? 1'b0 : - pins_pu[i] ? 1'b1 : 1'bz; - // If output enable is 1, strong driver assigns pin to 'value to be driven out'; - // the external strong driver can still affect pin, if exists. - // Else if output enable is 0, weak pullup or pulldown is applied to pin. - // By doing this, we make sure that weak pullup or pulldown does not override - // any 'x' value on pin, that may result due to conflicting values - // between 'value to be driven out' and the external driver's value. - assign pins[i] = pins_oe[i] ? pins_o[i] : 1'bz; + for (genvar i = 0; i < Width; i++) begin : each_pin `ifdef VERILATOR - assign pins[i] = ~pins_oe[i] ? pins_int[i] : 1'bz; + assign pins[i] = pins_oe[i] ? pins_o[i] : + pins_pu[i] ? 1'b1 : + pins_pd[i] ? 1'b0 : 1'bz; `else - assign (pull0, pull1) pins[i] = ~pins_oe[i] ? pins_int[i] : 1'bz; + // Drive the pin with pull strength based on whether pullup / pulldown is enabled. + assign (pull0, pull1) pins[i] = ~pins_oe[i] ? (pins_pu[i] ? 1'b1 : + pins_pd[i] ? 1'b0 : 1'bz) : 1'bz; + + + // If output enable is 1, strong driver assigns pin to 'value to be driven out'; + // the external strong driver can still affect pin, if exists. + // Else if output enable is 0, weak pullup or pulldown is applied to pin. + // By doing this, we make sure that weak pullup or pulldown does not override + // any 'x' value on pin, that may result due to conflicting values + // between 'value to be driven out' and the external driver's value. + assign pins[i] = pins_oe[i] ? pins_o[i] : 1'bz; `endif - end - endgenerate + end endinterface `endif diff --git a/vendor/lowrisc_ip/dv/sv/common_ifs/pins_if.svg b/vendor/lowrisc_ip/dv/sv/common_ifs/pins_if.svg index 8d9d5d00a3..0d624ff36e 100644 --- a/vendor/lowrisc_ip/dv/sv/common_ifs/pins_if.svg +++ b/vendor/lowrisc_ip/dv/sv/common_ifs/pins_if.svg @@ -1 +1,96 @@ - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pins_if + + 00 + 01 + 10 + 11 + + + + + + + + + + z + 1 + 0 + 0 + 0 + 1 + + + + + pins_int + + + pu + pd + + + + + + + + + + + pins_oe + + pins_o + + + + + + + + (strong0, strong1) + (pull0, pull1) + + external driver + pins + + diff --git a/vendor/lowrisc_ip/dv/sv/csr_utils/README.md b/vendor/lowrisc_ip/dv/sv/csr_utils/README.md index b2833014a5..e82ff6983b 100644 --- a/vendor/lowrisc_ip/dv/sv/csr_utils/README.md +++ b/vendor/lowrisc_ip/dv/sv/csr_utils/README.md @@ -123,7 +123,7 @@ Supported CSR test sequences are: the read results with the expected values ### CSR exclusion methodology -The CSR test sequences listed above intend to perform a sanity check to CSR +The CSR test sequences listed above intend to perform a basic check to CSR read/write accesses, but do not intend to check specific DUT functionalities. Thus the sequences might need to exclude reading or writing certain CSRs depending on the specific testbench. diff --git a/vendor/lowrisc_ip/dv/sv/csr_utils/csr_seq_lib.sv b/vendor/lowrisc_ip/dv/sv/csr_utils/csr_seq_lib.sv index 71d076cf56..73436751d2 100644 --- a/vendor/lowrisc_ip/dv/sv/csr_utils/csr_seq_lib.sv +++ b/vendor/lowrisc_ip/dv/sv/csr_utils/csr_seq_lib.sv @@ -219,14 +219,6 @@ class csr_rw_seq extends csr_base_seq; `uvm_object_new - rand bit do_csr_rd_check; - rand bit do_csr_field_rd_check; - - constraint csr_or_field_rd_check_c { - // at least one of them should be set - do_csr_rd_check || do_csr_field_rd_check; - } - virtual task body(); foreach (test_csrs[i]) begin uvm_reg_data_t wdata; @@ -243,7 +235,6 @@ class csr_rw_seq extends csr_base_seq; `uvm_info(`gtn, $sformatf("Verifying register read/write for %0s", test_csrs[i].get_full_name()), UVM_MEDIUM) - `DV_CHECK_FATAL(randomize(do_csr_rd_check, do_csr_field_rd_check)) `DV_CHECK_STD_RANDOMIZE_FATAL(wdata) wdata &= get_mask_excl_fields(test_csrs[i], CsrExclWrite, CsrRwTest, m_csr_excl_item); @@ -254,33 +245,14 @@ class csr_rw_seq extends csr_base_seq; // register is getting the updated access information. csr_wr(.csr(test_csrs[i]), .value(wdata), .blocking(0), .predict(!external_checker)); - // check if parent block or register is excluded from read-check - if (m_csr_excl_item.is_excl(test_csrs[i], CsrExclWriteCheck, CsrRwTest)) begin - `uvm_info(`gtn, $sformatf("Skipping register %0s due to CsrExclWriteCheck exclusion", - test_csrs[i].get_full_name()), UVM_MEDIUM) - continue; - end + do_check_csr_or_field_rd(.csr(test_csrs[i]), + .blocking(0), + .compare(!external_checker), + .compare_vs_ral(1), + .csr_excl_type(CsrExclWriteCheck), + .csr_test_type(CsrRwTest), + .csr_excl_item(m_csr_excl_item)); - compare_mask = get_mask_excl_fields(test_csrs[i], CsrExclWriteCheck, CsrRwTest, - m_csr_excl_item); - if (do_csr_rd_check) begin - csr_rd_check(.ptr (test_csrs[i]), - .blocking (0), - .compare (!external_checker), - .compare_vs_ral(1'b1), - .compare_mask (compare_mask)); - end - if (do_csr_field_rd_check) begin - test_csrs[i].get_fields(test_fields); - test_fields.shuffle(); - foreach (test_fields[j]) begin - bit compare = !m_csr_excl_item.is_excl(test_fields[j], CsrExclWriteCheck, CsrRwTest); - csr_rd_check(.ptr (test_fields[j]), - .blocking (0), - .compare (!external_checker && compare), - .compare_vs_ral(1'b1)); - end - end wait_if_max_outstanding_accesses_reached(); end endtask @@ -392,14 +364,7 @@ class csr_bit_bash_seq extends csr_base_seq; val = rg.get(); val[k] = ~val[k]; err_msg = $sformatf("Wrote %0s[%0d]: %0b", rg.get_full_name(), k, val[k]); - csr_wr(.csr(rg), .value(val), .blocking(1)); - - // if external checker is not enabled and writes are made non-blocking, then we need to - // pre-predict so that the mirrored value will be updated. if we dont, then csr_rd_check task - // might pick up stale mirrored value - if (!external_checker) begin - void'(rg.predict(.value(val), .kind(UVM_PREDICT_WRITE))); - end + csr_wr(.csr(rg), .value(val), .blocking(1), .predict(!external_checker)); // TODO, outstanding access to same reg isn't supported in uvm_reg. Need to add another seq // uvm_reg waits until transaction is completed, before start another read/write in same reg @@ -442,14 +407,7 @@ class csr_aliasing_seq extends csr_base_seq; `DV_CHECK_STD_RANDOMIZE_FATAL(wdata) wdata &= get_mask_excl_fields(test_csrs[i], CsrExclWrite, CsrAliasingTest, m_csr_excl_item); - csr_wr(.csr(test_csrs[i]), .value(wdata), .blocking(0)); - - // if external checker is not enabled and writes are made non-blocking, then we need to - // pre-predict so that the mirrored value will be updated. if we dont, then csr_rd_check task - // might pick up stale mirrored value - if (!external_checker) begin - void'(test_csrs[i].predict(.value(wdata), .kind(UVM_PREDICT_WRITE))); - end + csr_wr(.csr(test_csrs[i]), .value(wdata), .blocking(0), .predict(!external_checker)); all_csrs.shuffle(); foreach (all_csrs[j]) begin diff --git a/vendor/lowrisc_ip/dv/sv/csr_utils/csr_utils_pkg.sv b/vendor/lowrisc_ip/dv/sv/csr_utils/csr_utils_pkg.sv index 19b2b8e8be..ae913d73b5 100644 --- a/vendor/lowrisc_ip/dv/sv/csr_utils/csr_utils_pkg.sv +++ b/vendor/lowrisc_ip/dv/sv/csr_utils/csr_utils_pkg.sv @@ -13,13 +13,14 @@ package csr_utils_pkg; `include "dv_macros.svh" // local types and variables - uint outstanding_accesses = 0; - uint default_timeout_ns = 1_000_000; // 1ms - uint default_spinwait_timeout_ns = 10_000_000; // 10ms - string msg_id = "csr_utils"; - bit default_csr_blocking = 1; - bit under_reset = 0; - int max_outstanding_accesses = 100; + uint outstanding_accesses = 0; + uint default_timeout_ns = 1_000_000; // 1ms + uint default_spinwait_timeout_ns = 10_000_000; // 10ms + string msg_id = "csr_utils"; + bit default_csr_blocking = 1; + uvm_check_e default_csr_check = UVM_CHECK; + bit under_reset = 0; + int max_outstanding_accesses = 100; // csr field struct - hold field specific params typedef struct { @@ -174,7 +175,7 @@ package csr_utils_pkg; endtask task automatic csr_update(input uvm_reg csr, - input uvm_check_e check = UVM_CHECK, + input uvm_check_e check = default_csr_check, input uvm_path_e path = UVM_DEFAULT_PATH, input bit blocking = default_csr_blocking, input uint timeout_ns = default_timeout_ns, @@ -193,7 +194,7 @@ package csr_utils_pkg; // subroutine of csr_update, don't use it directly task automatic csr_update_sub(input uvm_reg csr, - input uvm_check_e check = UVM_CHECK, + input uvm_check_e check = default_csr_check, input uvm_path_e path = UVM_DEFAULT_PATH, input uint timeout_ns = default_timeout_ns, input uvm_reg_map map = null, @@ -209,7 +210,9 @@ package csr_utils_pkg; csr_pre_write_sub(csr, en_shadow_wr); csr.update(.status(status), .path(path), .map(map), .prior(100)); csr_post_write_sub(csr, en_shadow_wr); - if (check == UVM_CHECK) begin + // when reset occurs, all items will be dropped immediately. This may end up getting + // d_error = 1 from previous item on the bus. Skip checking it during reset + if (check == UVM_CHECK && !under_reset) begin `DV_CHECK_EQ(status, UVM_IS_OK, "", error, msg_id) end decrement_outstanding_access(); @@ -227,7 +230,7 @@ package csr_utils_pkg; task automatic csr_wr(input uvm_reg csr, input uvm_reg_data_t value, - input uvm_check_e check = UVM_CHECK, + input uvm_check_e check = default_csr_check, input uvm_path_e path = UVM_DEFAULT_PATH, input bit blocking = default_csr_blocking, input bit backdoor = 0, @@ -238,15 +241,11 @@ package csr_utils_pkg; if (backdoor) begin csr_poke(csr, value, check, predict); end else if (blocking) begin - csr_wr_sub(csr, value, check, path, timeout_ns, map, en_shadow_wr); - if (predict) void'(csr.predict(.value(value), .kind(UVM_PREDICT_WRITE))); + csr_wr_sub(csr, value, check, path, timeout_ns, predict, map, en_shadow_wr); end else begin fork begin - csr_wr_sub(csr, value, check, path, timeout_ns, map, en_shadow_wr); - // predict after csr_wr_sub, to ensure predict after enable register overwrite the locked - // registers' access information - if (predict) void'(csr.predict(.value(value), .kind(UVM_PREDICT_WRITE))); + csr_wr_sub(csr, value, check, path, timeout_ns, predict, map, en_shadow_wr); end join_none // Add #0 to ensure that this thread starts executing before any subsequent call @@ -257,9 +256,10 @@ package csr_utils_pkg; // subroutine of csr_wr, don't use it directly task automatic csr_wr_sub(input uvm_reg csr, input uvm_reg_data_t value, - input uvm_check_e check = UVM_CHECK, + input uvm_check_e check = default_csr_check, input uvm_path_e path = UVM_DEFAULT_PATH, input uint timeout_ns = default_timeout_ns, + input bit predict = 0, input uvm_reg_map map = null, input bit en_shadow_wr = 1); fork @@ -273,9 +273,14 @@ package csr_utils_pkg; csr_pre_write_sub(csr, en_shadow_wr); csr.write(.status(status), .value(value), .path(path), .map(map), .prior(100)); csr_post_write_sub(csr, en_shadow_wr); - if (check == UVM_CHECK) begin + if (check == UVM_CHECK && !under_reset) begin `DV_CHECK_EQ(status, UVM_IS_OK, "", error, msg_id) end + // Only update the predicted value if status is ok (otherwise the write isn't completed + // successfully and the design shouldn't have accepted the written value) + if (status == UVM_IS_OK && predict) begin + void'(csr.predict(.value(value), .kind(UVM_PREDICT_WRITE))); + end decrement_outstanding_access(); end begin @@ -314,15 +319,16 @@ package csr_utils_pkg; endtask // backdoor write csr - task automatic csr_poke(input uvm_reg csr, - input uvm_reg_data_t value, - input uvm_check_e check = UVM_CHECK, - input bit predict = 0); + task automatic csr_poke(input uvm_reg csr, + input uvm_reg_data_t value, + input uvm_check_e check = default_csr_check, + input bit predict = 0, + input bkdr_reg_path_e kind = BkdrRegPathRtl); uvm_status_e status; string msg_id = {csr_utils_pkg::msg_id, "::csr_poke"}; uvm_reg_data_t old_mirrored_val = csr.get_mirrored_value(); - csr.poke(.status(status), .value(value)); + csr.poke(.status(status), .value(value), .kind(kind.name)); if (check == UVM_CHECK && status != UVM_IS_OK) begin string str; uvm_hdl_path_concat paths[$]; @@ -332,26 +338,28 @@ package csr_utils_pkg; csr.get_full_name(), str)) end // poke always updates predict value, if predict == 0, revert back to old mirrored value - if (!predict) begin + if (!predict || kind == BkdrRegPathRtlShadow) begin void'(csr.predict(.value(old_mirrored_val), .kind(UVM_PREDICT_DIRECT))); end endtask task automatic csr_rd(input uvm_object ptr, // accept reg or field output uvm_reg_data_t value, - input uvm_check_e check = UVM_CHECK, + input uvm_check_e check = default_csr_check, input uvm_path_e path = UVM_DEFAULT_PATH, input bit blocking = default_csr_blocking, input bit backdoor = 0, input uint timeout_ns = default_timeout_ns, input uvm_reg_map map = null); - if (backdoor) begin - csr_peek(ptr, value, check); - end else if (blocking) begin - csr_rd_sub(ptr, value, check, path, timeout_ns, map); + uvm_status_e status; + if (blocking) begin + csr_rd_sub(.ptr(ptr), .value(value), .status(status), .check(check), .path(path), + .backdoor(backdoor), .timeout_ns(timeout_ns), .map(map)); end else begin + `DV_CHECK_EQ(backdoor, 0, "Don't enable backdoor with blocking = 0", error, msg_id) fork - csr_rd_sub(ptr, value, check, path, timeout_ns, map); + csr_rd_sub(.ptr(ptr), .value(value), .status(status), .check(check), .path(path), + .backdoor(backdoor), .timeout_ns(timeout_ns), .map(map)); join_none // Add #0 to ensure that this thread starts executing before any subsequent call #0; @@ -361,14 +369,20 @@ package csr_utils_pkg; // subroutine of csr_rd, don't use it directly task automatic csr_rd_sub(input uvm_object ptr, // accept reg or field output uvm_reg_data_t value, - input uvm_check_e check = UVM_CHECK, + output uvm_status_e status, + input bit backdoor = 0, + input uvm_check_e check = default_csr_check, input uvm_path_e path = UVM_DEFAULT_PATH, input uint timeout_ns = default_timeout_ns, input uvm_reg_map map = null); + if (backdoor) begin + csr_peek(ptr, value, check); + status = UVM_IS_OK; + return; + end fork begin : isolation_fork csr_field_t csr_or_fld; - uvm_status_e status; string msg_id = {csr_utils_pkg::msg_id, "::csr_rd"}; fork @@ -382,7 +396,7 @@ package csr_utils_pkg; csr_or_fld.csr.read(.status(status), .value(value), .path(path), .map(map), .prior(100)); end - if (check == UVM_CHECK) begin + if (check == UVM_CHECK && !under_reset) begin `DV_CHECK_EQ(status, UVM_IS_OK, "", error, msg_id) end decrement_outstanding_access(); @@ -402,15 +416,16 @@ package csr_utils_pkg; // uvm_reg::peek() returns a 2-state value, directly get data from hdl path task automatic csr_peek(input uvm_object ptr, output uvm_reg_data_t value, - input uvm_check_e check = UVM_CHECK); + input uvm_check_e check = default_csr_check, + input bkdr_reg_path_e kind = BkdrRegPathRtl); string msg_id = {csr_utils_pkg::msg_id, "::csr_peek"}; csr_field_t csr_or_fld = decode_csr_or_field(ptr); uvm_reg csr = csr_or_fld.csr; - if (csr.has_hdl_path()) begin + if (csr.has_hdl_path(kind.name)) begin uvm_hdl_path_concat paths[$]; - csr.get_full_hdl_path(paths); + csr.get_full_hdl_path(paths, kind.name); foreach (paths[0].slices[i]) begin uvm_reg_data_t field_val; if (uvm_hdl_read(paths[0].slices[i].path, field_val)) begin @@ -421,7 +436,8 @@ package csr_utils_pkg; end end end else begin - `uvm_fatal(msg_id, $sformatf("No backdoor defined for %0s", csr.get_full_name())) + `uvm_fatal(msg_id, $sformatf("No backdoor defined for %0s path's %0s", + csr.get_full_name(), kind.name)) end // if it's field, only return field value @@ -429,7 +445,7 @@ package csr_utils_pkg; endtask task automatic csr_rd_check(input uvm_object ptr, - input uvm_check_e check = UVM_CHECK, + input uvm_check_e check = default_csr_check, input uvm_path_e path = UVM_DEFAULT_PATH, input bit blocking = default_csr_blocking, input bit backdoor = 0, @@ -452,8 +468,8 @@ package csr_utils_pkg; csr_or_fld = decode_csr_or_field(ptr); - csr_rd(.ptr(ptr), .value(obs), .check(check), .path(path), .backdoor(backdoor), - .blocking(1), .timeout_ns(timeout_ns), .map(map)); + csr_rd_sub(.ptr(ptr), .value(obs), .status(status), .check(check), .path(path), + .backdoor(backdoor), .timeout_ns(timeout_ns), .map(map)); // get mirrored value after read to make sure the read reg access is updated if (csr_or_fld.field != null) begin @@ -461,7 +477,7 @@ package csr_utils_pkg; end else begin exp = csr_or_fld.csr.get_mirrored_value(); end - if (compare && !under_reset) begin + if (compare && status == UVM_IS_OK && !under_reset) begin obs = obs & compare_mask; exp = (compare_vs_ral ? exp : compare_value) & compare_mask; `DV_CHECK_EQ(obs, exp, {"Regname: ", ptr.get_full_name(), " ", err_msg}, @@ -485,10 +501,55 @@ package csr_utils_pkg; foreach (ral_csrs[i]) csr_rd_check(.ptr(ral_csrs[i]), .compare_vs_ral(1)); endtask + // Checks the csr value against predicted value by reading the whole CSR or individual CSR + // fields. + // This task will skip read check if the CSR field is excluded. + task automatic do_check_csr_or_field_rd(input uvm_reg csr, + input bit do_csr_field_rd_check = $urandom(), + input bit blocking = 0, + input bit compare = 1, + input bit compare_vs_ral = 1, + input csr_excl_type_e csr_excl_type = CsrNoExcl, + input csr_test_type_e csr_test_type = CsrRwTest, + input csr_excl_item csr_excl_item = null); + uvm_reg_data_t compare_mask; + + // Check if parent block or register is excluded from read-check + if (csr_excl_item != null && csr_excl_item.is_excl(csr, csr_excl_type, csr_test_type)) begin + `uvm_info(msg_id, $sformatf("Skipping register %0s due to CsrExclWriteCheck exclusion", + csr.get_full_name()), UVM_MEDIUM) + return; + end + + compare_mask = get_mask_excl_fields(csr, csr_excl_type, csr_test_type, csr_excl_item); + + if (!do_csr_field_rd_check) begin + csr_rd_check(.ptr (csr), + .blocking (blocking), + .compare (compare), + .compare_vs_ral(compare_vs_ral), + .compare_mask (compare_mask)); + end else begin + uvm_reg_field test_fields[$]; + csr.get_fields(test_fields); + test_fields.shuffle(); + foreach (test_fields[i]) begin + bit field_compare = 1; + if (csr_excl_item != null) begin + field_compare = !csr_excl_item.is_excl(test_fields[i], csr_excl_type, csr_test_type); + end + csr_rd_check(.ptr (test_fields[i]), + .blocking (blocking), + .compare (field_compare && compare), + .compare_vs_ral(compare_vs_ral)); + end + end + endtask + // poll a csr or csr field continuously until it reads the expected value. task automatic csr_spinwait(input uvm_object ptr, input uvm_reg_data_t exp_data, - input uvm_check_e check = UVM_CHECK, + input uvm_check_e check = default_csr_check, input uvm_path_e path = UVM_DEFAULT_PATH, input uvm_reg_map map = null, input uint spinwait_delay_ns = 0, @@ -538,7 +599,7 @@ package csr_utils_pkg; task automatic mem_rd(input uvm_mem ptr, input int offset, output bit[31:0] data, - input uvm_check_e check = UVM_CHECK, + input uvm_check_e check = default_csr_check, input bit blocking = default_csr_blocking, input uint timeout_ns = default_timeout_ns, input uvm_reg_map map = null); @@ -556,7 +617,7 @@ package csr_utils_pkg; task automatic mem_rd_sub(input uvm_mem ptr, input int offset, output bit[31:0] data, - input uvm_check_e check = UVM_CHECK, + input uvm_check_e check = default_csr_check, input uint timeout_ns = default_timeout_ns, input uvm_reg_map map = null); fork @@ -568,7 +629,7 @@ package csr_utils_pkg; begin increment_outstanding_access(); ptr.read(.status(status), .offset(offset), .value(data), .map(map), .prior(100)); - if (check == UVM_CHECK) begin + if (check == UVM_CHECK && !under_reset) begin `DV_CHECK_EQ(status, UVM_IS_OK, "", error, msg_id) end decrement_outstanding_access(); @@ -589,7 +650,7 @@ package csr_utils_pkg; input bit[31:0] data, input bit blocking = default_csr_blocking, input uint timeout_ns = default_timeout_ns, - input uvm_check_e check = UVM_CHECK, + input uvm_check_e check = default_csr_check, input uvm_reg_map map = null); if (blocking) begin mem_wr_sub(ptr, offset, data, timeout_ns, check, map); @@ -606,7 +667,7 @@ package csr_utils_pkg; input int offset, input bit[31:0] data, input uint timeout_ns = default_timeout_ns, - input uvm_check_e check = UVM_CHECK, + input uvm_check_e check = default_csr_check, input uvm_reg_map map = null); fork begin : isolation_fork @@ -617,7 +678,7 @@ package csr_utils_pkg; begin increment_outstanding_access(); ptr.write(.status(status), .offset(offset), .value(data), .map(map), .prior(100)); - if (check == UVM_CHECK) begin + if (check == UVM_CHECK && !under_reset) begin `DV_CHECK_EQ(status, UVM_IS_OK, "", error, msg_id) end decrement_outstanding_access(); @@ -641,12 +702,14 @@ package csr_utils_pkg; uvm_reg_field flds[$]; csr.get_fields(flds); get_mask_excl_fields = '1; - foreach (flds[i]) begin - if (m_csr_excl_item.is_excl(flds[i], csr_excl_type, csr_test_type)) begin - csr_field_t fld_params = decode_csr_or_field(flds[i]); - `uvm_info(msg_id, $sformatf("Skipping field %0s due to %0s exclusion", - flds[i].get_full_name(), csr_excl_type.name()), UVM_MEDIUM) - get_mask_excl_fields &= ~(fld_params.mask << fld_params.shift); + if (m_csr_excl_item != null) begin + foreach (flds[i]) begin + if (m_csr_excl_item.is_excl(flds[i], csr_excl_type, csr_test_type)) begin + csr_field_t fld_params = decode_csr_or_field(flds[i]); + `uvm_info(msg_id, $sformatf("Skipping field %0s due to %0s exclusion", + flds[i].get_full_name(), csr_excl_type.name()), UVM_MEDIUM) + get_mask_excl_fields &= ~(fld_params.mask << fld_params.shift); + end end end endfunction diff --git a/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg.sv b/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg.sv index e0c58908cf..fd1cf9e727 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg.sv @@ -9,7 +9,7 @@ class dv_base_reg extends uvm_reg; local bit is_ext_reg; local dv_base_reg locked_regs[$]; - local uvm_reg_data_t staged_shadow_val; + local uvm_reg_data_t staged_shadow_val, committed_val, shadowed_val; local bit is_shadowed; local bit shadow_wr_staged; // stage the first shadow reg write local bit shadow_update_err; @@ -111,6 +111,15 @@ class dv_base_reg extends uvm_reg; return shadow_update_err; endfunction + function bit get_shadow_storage_err(); + uvm_reg_data_t mask = (1'b1 << (get_msb_pos() + 1)) - 1; + uvm_reg_data_t shadowed_val_temp = (~shadowed_val) & mask; + uvm_reg_data_t committed_val_temp = committed_val & mask; + `uvm_info(`gfn, $sformatf("shadow_val %0h, commmit_val %0h", shadowed_val_temp, + committed_val_temp), UVM_DEBUG) + return shadowed_val_temp != committed_val_temp; + endfunction + virtual function void clear_shadow_update_err(); shadow_update_err = 0; endfunction @@ -123,6 +132,10 @@ class dv_base_reg extends uvm_reg; virtual task post_write(uvm_reg_item rw); dv_base_reg_field fields[$]; string field_access; + + // no need to update shadow value or access type if access is not OK, as access is aborted + if (rw.status != UVM_IS_OK) return; + if (is_shadowed) begin // first write if (!shadow_wr_staged) begin @@ -136,6 +149,8 @@ class dv_base_reg extends uvm_reg; shadow_update_err = 1; return; end + committed_val = staged_shadow_val; + shadowed_val = ~committed_val; end end if (is_enable_reg()) begin @@ -197,11 +212,44 @@ class dv_base_reg extends uvm_reg; super.do_predict(rw, kind, be); endfunction + virtual task poke (output uvm_status_e status, + input uvm_reg_data_t value, + input string kind = "BkdrRegPathRtl", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (kind == "BkdrRegPathRtlShadow") shadowed_val = value; + else if (kind == "BkdrRegPathRtlCommitted") committed_val = value; + super.poke(status, value, kind, parent, extension, fname, lineno); + endtask + + // callback function to update shadowed values according to specific design + // should only be called after post-write + virtual function void update_shadowed_val(uvm_reg_data_t val, bit do_predict = 1); + if (shadow_wr_staged) begin + // update value after first write + staged_shadow_val = val; + end else begin + // update value after second write + if (staged_shadow_val != val) begin + shadow_update_err = 1; + end else begin + shadow_update_err = 0; + committed_val = staged_shadow_val; + shadowed_val = ~committed_val; + end + end + if (do_predict) void'(predict(val)); + endfunction + virtual function void reset(string kind = "HARD"); super.reset(kind); if (is_shadowed) begin shadow_update_err = 0; shadow_wr_staged = 0; + committed_val = get_mirrored_value(); + shadowed_val = ~committed_val; // in case reset is issued during shadowed writes void'(atomic_shadow_wr.try_get(1)); void'(atomic_en_shadow_wr.try_get(1)); diff --git a/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_block.sv b/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_block.sv index c0bbcc62c8..a3e4521dcd 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_block.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_block.sv @@ -8,6 +8,14 @@ class dv_base_reg_block extends uvm_reg_block; csr_excl_item csr_excl; + // The address mask for the register block specific to a map. This will be (1 << K) - 1 for some + // K. All relative offsets in the register block have addresses less than (1 << K), so an address + // decoder that starts by discarding all higher bits will work correctly so long as the chosen + // base address of the register block has no bits in common with this mask. + // + // This is set by compute_addr_mask(), which must run after locking the model. + protected uvm_reg_addr_t addr_mask[uvm_reg_map]; + function new (string name = "", int has_coverage = UVM_NO_COVERAGE); super.new(name, has_coverage); endfunction @@ -30,9 +38,18 @@ class dv_base_reg_block extends uvm_reg_block; foreach (ral_regs[i]) `downcast(dv_regs[i], ral_regs[i]) endfunction + function dv_base_reg get_dv_base_reg_by_name(string csr_name, bit check_csr_exist = 1'b1); + uvm_reg csr = get_reg_by_name(csr_name); + `downcast(get_dv_base_reg_by_name, csr) + if (check_csr_exist) begin + `DV_CHECK_NE_FATAL(get_dv_base_reg_by_name, null, + $sformatf("%0s does not exist in block %0s",csr_name, get_name())) + end + endfunction + function void get_enable_regs(ref dv_base_reg enable_regs[$]); dv_base_reg_block blks[$]; - this.get_dv_base_reg_blocks(blks); + get_dv_base_reg_blocks(blks); if (blks.size() == 0) begin dv_base_reg all_regs[$]; this.get_dv_base_regs(all_regs); @@ -49,9 +66,121 @@ class dv_base_reg_block extends uvm_reg_block; // when reset issued - the locked registers' access will be reset to original access virtual function void reset(string kind = "HARD"); dv_base_reg enable_regs[$]; + `uvm_info(`gfn, "Resetting RAL reg block", UVM_MEDIUM) super.reset(kind); get_enable_regs(enable_regs); foreach (enable_regs[i]) enable_regs[i].set_locked_regs_access(); endfunction + // Internal function, used to compute the address mask for this register block. + // + // This is quite an expensive computation, so we memoize the results in addr_mask[map]. + // Use below to get the addr map size #3317 + // max2(biggest_reg_offset+reg_size, biggest_mem_offset+mem_size) and then round up to 2**N + protected function void compute_addr_mask(uvm_reg_map map); + uvm_reg_addr_t max_addr, max_offset; + uvm_reg_block blocks[$]; + uvm_reg regs[$]; + uvm_mem mems[$]; + int unsigned alignment; + + // TODO: assume IP only contains 1 reg block, find a better way to handle chip-level and IP + // with multiple reg blocks + get_blocks(blocks); + if (blocks.size > 0) begin + addr_mask[map] = '1; + return; + end + + get_registers(regs); + get_memories(mems); + `DV_CHECK_GT_FATAL(regs.size() + mems.size(), 0) + + // Walk the known registers and memories, calculating the largest byte address visible. Note + // that the get_offset() calls will return absolute addresses, including any base address in the + // default register map. + max_addr = 0; + foreach (regs[i]) begin + max_addr = max2(regs[i].get_offset(map) + regs[i].get_n_bytes() - 1, max_addr); + end + + foreach (mems[i]) begin + uvm_reg_addr_t mem_size; + mem_size = mems[i].get_offset(.map(map)) + mems[i].get_size() * mems[i].get_n_bytes() - 1; + max_addr = max2(mem_size, max_addr); + end + + // Subtract the base address in the default register map to get the maximum relative offset. + max_offset = max_addr - map.get_base_addr(); + + // Set alignment to be ceil(log2(biggest_offset)) + alignment = 0; + while (max_offset > 0) begin + alignment++; + max_offset = max_offset >> 1; + end + + // Note that we know alignment > 0 (because we've already checked that we have at least one + // register or memory). + `DV_CHECK_GT_FATAL(alignment, 0) + + // Finally, extract a mask corresponding to the alignment + addr_mask[map] = (1 << alignment) - 1; + + // Computed mask must be non-zero. + `DV_CHECK_FATAL(addr_mask[map]) + endfunction + + // Get the address mask. This should only be called after locking the model (because it depends on + // the layout of registers and memories in the block). + function uvm_reg_addr_t get_addr_mask(uvm_reg_map map = null); + `DV_CHECK_FATAL(is_locked()) + if (map == null) map = get_default_map(); + if (!addr_mask.exists(map)) compute_addr_mask(map); + return addr_mask[map]; + endfunction + + // Set the base address for the given register map + // + // Check that base_addr is aligned as required by the register block. If the supplied base_addr is + // the "magic" address '1, randomly pick an appropriately aligned base address and set it for the + // specified map. + function void set_base_addr(uvm_reg_addr_t base_addr = '1, uvm_reg_map map = null); + uvm_reg_addr_t mask; + + if (map == null) map = get_default_map(); + mask = get_addr_mask(map); + + // If base_addr is '1, randomly pick an aligned base address + if (base_addr == '1) begin + `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(base_addr, (base_addr & mask) == '0;) + end + + // Check base addr alignment (which should be guaranteed if we just picked it, but needs + // checking if not). + `DV_CHECK_FATAL((base_addr & mask) == '0) + `uvm_info(`gfn, $sformatf("Setting register base address to 0x%0h", base_addr), UVM_HIGH) + map.set_base_addr(base_addr); + endfunction + + // Round the given address down to the start of the containing word. For example, if the address + // is 'h123, it will be rounded down to 'h120. + // + // This is useful if you have a possibly misaligned address and you want to know whether it hits a + // register (since get_reg_by_offset needs the aligned address for the start of the register). + function uvm_reg_addr_t get_word_aligned_addr(uvm_reg_addr_t byte_addr); + uvm_reg_addr_t shift = $clog2(`UVM_REG_BYTENABLE_WIDTH); + return (byte_addr >> shift) << shift; + endfunction + + // Get the absolute address (in the default register map) for the given offset. For example, if + // the base address is 'h100 and offset is 'h13, this will return 'h113 ('h110 if word_aligned is + // set). + function uvm_reg_addr_t get_addr_from_offset(uvm_reg_addr_t byte_offset, + bit word_aligned = 1'b1, + uvm_reg_map map = null); + if (map == null) map = get_default_map(); + return (word_aligned ? get_word_aligned_addr(byte_offset) : byte_offset) + map.get_base_addr(); + endfunction + endclass diff --git a/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_pkg.sv b/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_pkg.sv index a5018ce300..b411f82975 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_pkg.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_pkg.sv @@ -37,6 +37,15 @@ package dv_base_reg_pkg; CsrAllTests = 4'hf // all tests } csr_test_type_e; + typedef enum bit[2:0] { + BkdrRegPathRtl, // backdoor path for reg's val in RTL + BkdrRegPathRtlCommitted, // backdoor path for shadow reg's committed val in RTL + BkdrRegPathRtlShadow, // backdoor path for shadow reg's shadow val in RTL + BkdrRegPathGls, // backdoor path for reg's val in GLS + BkdrRegPathGlsCommitted, // backdoor path for shadow reg's committed val in GLS + BkdrRegPathGlsShdow // backdoor path for shadow reg's shadow val in GLS + } bkdr_reg_path_e; + // package sources // base ral `include "csr_excl_item.sv" diff --git a/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_env.sv b/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_env.sv index f616446bee..4e293bb886 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_env.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_env.sv @@ -46,15 +46,4 @@ class dv_base_env #(type CFG_T = dv_base_env_cfg, scoreboard.cov = cov; endfunction - virtual function void end_of_elaboration_phase(uvm_phase phase); - super.end_of_elaboration_phase(phase); - if (cfg.has_ral) begin - // Lock the ral model - cfg.ral.lock_model(); - // Get list of valid csr addresses (useful in seq to randomize addr as well as in scb checks) - get_csr_addrs(cfg.ral, cfg.csr_addrs); - get_mem_addr_ranges(cfg.ral, cfg.mem_ranges); - end - endfunction : end_of_elaboration_phase - endclass diff --git a/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_env_cfg.sv b/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_env_cfg.sv index cdb3f78fa1..233937e8cd 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_env_cfg.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_env_cfg.sv @@ -26,11 +26,6 @@ class dv_base_env_cfg #(type RAL_T = dv_base_reg_block) extends uvm_object; bit [bus_params_pkg::BUS_AW-1:0] csr_addrs[$]; addr_range_t mem_ranges[$]; - // ral base address and size - bit [bus_params_pkg::BUS_AW-1:0] csr_base_addr; // base address where csr map begins - bit [bus_params_pkg::BUS_AW:0] csr_addr_map_size; // csr addr region allocated to the ip, - // max: 1 << bus_params_pkg::BUS_AW - // clk_rst_if & freq virtual clk_rst_if clk_rst_vif; rand clk_freq_mhz_e clk_freq_mhz; @@ -40,44 +35,36 @@ class dv_base_env_cfg #(type RAL_T = dv_base_reg_block) extends uvm_object; `uvm_field_int (en_scb, UVM_DEFAULT) `uvm_field_int (en_cov, UVM_DEFAULT) `uvm_field_int (zero_delays, UVM_DEFAULT) - `uvm_field_int (csr_base_addr, UVM_DEFAULT) - `uvm_field_int (csr_addr_map_size, UVM_DEFAULT) `uvm_field_enum (clk_freq_mhz_e, clk_freq_mhz, UVM_DEFAULT) `uvm_object_utils_end `uvm_object_new virtual function void initialize(bit [bus_params_pkg::BUS_AW-1:0] csr_base_addr = '1); - initialize_csr_addr_map_size(); - `DV_CHECK_NE_FATAL(csr_addr_map_size, 0, "csr_addr_map_size can't be 0") - // use locally randomized csr base address, unless provided as arg to this function - if (csr_base_addr != '1) begin - bit is_aligned; - this.csr_base_addr = csr_base_addr; - // check alignment - is_aligned = ~|(this.csr_base_addr & (this.csr_addr_map_size - 1)); - `DV_CHECK_EQ_FATAL(is_aligned, 1'b1) - end else begin - // base address needs to be aligned to csr_addr_map_size - `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(csr_base_addr, - ~|(csr_base_addr & (csr_addr_map_size - 1));) - this.csr_base_addr = csr_base_addr; - end // build the ral model if (has_ral) begin + uvm_reg_addr_t base_addr; + ral = RAL_T::type_id::create("ral"); - ral.build(this.csr_base_addr, null); + + // Build the register block with an arbitrary base address (we choose 0). We'll change it + // later. + ral.build(.base_addr(0), .csr_excl(null)); apply_ral_fixes(); + ral.lock_model(); + + // Now the model is locked, we know its layout. Set the base address for the register block. + // The function internally picks a random one if we pass '1 to it, and performs an integrity + // check on the set address. + ral.set_base_addr(csr_base_addr); + + // Get list of valid csr addresses (useful in seq to randomize addr as well as in scb checks) + get_csr_addrs(ral, csr_addrs); + get_mem_addr_ranges(ral, mem_ranges); ral_models.push_back(ral); end endfunction - // This function must be implemented in extended class to - // initialize value of csr_addr_map_size member - virtual function void initialize_csr_addr_map_size(); - `uvm_fatal(`gfn, "This task must be implemented in the extended class!") - endfunction : initialize_csr_addr_map_size - // ral flow is limited in terms of setting correct field access policies and reset values // We apply those fixes here - please note these fixes need to be reflected in the scoreboard protected virtual function void apply_ral_fixes(); @@ -93,4 +80,5 @@ class dv_base_env_cfg #(type RAL_T = dv_base_reg_block) extends uvm_object; this.under_reset = 0; csr_utils_pkg::reset_deasserted(); endfunction + endclass diff --git a/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_env_cov.sv b/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_env_cov.sv index d593462804..663de0d0cd 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_env_cov.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_env_cov.sv @@ -5,13 +5,15 @@ // TODO - We are enclosing generic covergroups inside class so that we can // take avoid tool limitation of not allowing arrays of covergroup // Refer to Issue#375 for more details -class dv_base_generic_cov_obj; +class bit_toggle_cg_wrap; // Covergroup: bit_toggle_cg // Generic covergroup definition - covergroup bit_toggle_cg(string name, bit toggle_cov_en = 1) with function sample(bit value); + covergroup bit_toggle_cg(string name, string path = "", bit toggle_cov_en = 1) with function + sample(bit value); option.per_instance = 1; - option.name = name; + option.name = (path == "") ? name : {path, "::", name}; + cp_value: coverpoint value; cp_transitions: coverpoint value { option.weight = toggle_cov_en; @@ -21,8 +23,8 @@ class dv_base_generic_cov_obj; endgroup : bit_toggle_cg // Function: new - function new(string name = "dv_base_generic_cov_obj", bit toggle_cov_en = 1); - bit_toggle_cg = new(name, toggle_cov_en); + function new(string name = "bit_toggle_cg_wrap", string path = "", bit toggle_cov_en = 1); + bit_toggle_cg = new(name, path, toggle_cov_en); endfunction : new // Function: sample @@ -30,7 +32,7 @@ class dv_base_generic_cov_obj; bit_toggle_cg.sample(value); endfunction : sample -endclass : dv_base_generic_cov_obj +endclass : bit_toggle_cg_wrap class dv_base_env_cov #(type CFG_T = dv_base_env_cfg) extends uvm_component; `uvm_component_param_utils(dv_base_env_cov #(CFG_T)) diff --git a/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_scoreboard.sv b/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_scoreboard.sv index 6c080947ef..f2e57cf9ea 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_scoreboard.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_scoreboard.sv @@ -52,12 +52,19 @@ class dv_base_scoreboard #(type RAL_T = dv_base_reg_block, virtual function void pre_abort(); super.pre_abort(); - // use under_pre_abort flag to prevent deadloop described below: - // when fatal_err occurred, it will skip check_phase. We add the additional check_phase call - // here to help debugging. But if inside the check_phase there are UVM_ERRORs, and the err cnt - // is larger than max_err_cnt, then check_phase will call pre_abort again. This will end up - // creating a deadloop. - if (has_uvm_fatal_occurred() && !under_pre_abort) begin + + // In UVM, a fatal error normally aborts the test completely and skips the check phase. However, + // it's sometimes helpful to run that phase on the scoreboard anyway (it might make it easier to + // debug whatever went wrong), so we do that here. + // + // We only run the check phase if we were in the run phase: if something went wrong in the build + // or connect phase, there's not much point in "checking the run" further. We also have to be + // careful to avoid an infinite loop, so we set a flag to avoid doing this a second time if we + // have errors in the check phase. + if (has_uvm_fatal_occurred() && + !under_pre_abort && + m_current_phase.is(uvm_run_phase::get())) begin + under_pre_abort = 1; check_phase(m_current_phase); under_pre_abort = 0; diff --git a/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_vseq.sv b/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_vseq.sv index 9fb02df3da..6e0d44798e 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_vseq.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_vseq.sv @@ -88,6 +88,7 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block, if (kind == "HARD") begin csr_utils_pkg::reset_asserted(); cfg.clk_rst_vif.apply_reset(); + csr_utils_pkg::clear_outstanding_access(); csr_utils_pkg::reset_deasserted(); end if (cfg.has_ral) begin @@ -186,13 +187,19 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block, string reset_type = "HARD"; csr_write_seq m_csr_write_seq; + // Writing random values to CSRs might trigger assertion errors. So we disable in the entire + // DUT hierarchy and re-enable after resetting the DUT. See DV_ASSERT_CTRL macro defined in + // hw/dv/sv/dv_utils/dv_macros.svh for more details. + if (!enable_asserts_in_hw_reset_rand_wr) begin + `DV_ASSERT_CTRL_REQ("dut_assert_en", 1'b0) + end + // run write-only sequence to randomize the csr values m_csr_write_seq = csr_write_seq::type_id::create("m_csr_write_seq"); m_csr_write_seq.models = cfg.ral_models; - m_csr_write_seq.set_csr_excl_item(csr_excl); m_csr_write_seq.external_checker = cfg.en_scb; - m_csr_write_seq.en_rand_backdoor_write = 1; - if (!enable_asserts_in_hw_reset_rand_wr) $assertoff; + m_csr_write_seq.en_rand_backdoor_write = 1'b1; + m_csr_write_seq.set_csr_excl_item(csr_excl); m_csr_write_seq.start(null); // run dut_shutdown before asserting reset @@ -200,16 +207,23 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block, // issue reset void'($value$plusargs("do_reset=%0s", reset_type)); dut_init(reset_type); - if (!enable_asserts_in_hw_reset_rand_wr) $asserton; + if (!enable_asserts_in_hw_reset_rand_wr) begin + `DV_ASSERT_CTRL_REQ("dut_assert_en", 1'b1) + end end // create base csr seq and pass our ral m_csr_seq = csr_base_seq::type_id::create("m_csr_seq"); - m_csr_seq.num_test_csrs = num_test_csrs; m_csr_seq.models = cfg.ral_models; - m_csr_seq.set_csr_excl_item(csr_excl); m_csr_seq.external_checker = cfg.en_scb; + m_csr_seq.num_test_csrs = num_test_csrs; + m_csr_seq.set_csr_excl_item(csr_excl); m_csr_seq.start(null); endtask + // enable/disable csr_assert + virtual function void set_csr_assert_en(bit enable, string path = "*"); + uvm_config_db#(bit)::set(null, path, "csr_assert_en", enable); + endfunction + endclass diff --git a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.core b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.core new file mode 100644 index 0000000000..5f2fb800bd --- /dev/null +++ b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.core @@ -0,0 +1,17 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:dv:dv_macros" +description: "A collection of macros used in DV." + +filesets: + files_dv: + files: + - dv_macros.svh: {is_include_file: true} + file_type: systemVerilogSource + +targets: + default: &default_target + filesets: + - files_dv diff --git a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh index 56d8f26381..e9413f847c 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh +++ b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh @@ -2,26 +2,38 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 +`ifndef __DV_MACROS_SVH__ +`define __DV_MACROS_SVH__ + +`ifdef UVM + `include "uvm_macros.svh" +`endif + // UVM speficic macros `ifndef gfn + // verilog_lint: waive macro-name-style `define gfn get_full_name() `endif `ifndef gtn + // verilog_lint: waive macro-name-style `define gtn get_type_name() `endif `ifndef gn + // verilog_lint: waive macro-name-style `define gn get_name() `endif `ifndef gmv + // verilog_lint: waive macro-name-style `define gmv(csr) csr.get_mirrored_value() `endif // cast base class obj holding extended class handle to extended class handle; // throw error if cast fails `ifndef downcast + // verilog_lint: waive macro-name-style `define downcast(EXT_, BASE_, MSG_="", SEV_=fatal, ID_=`gfn) \ begin \ if (!$cast(EXT_, BASE_)) begin \ @@ -57,6 +69,11 @@ _inst_name_ = _type_name_::type_id::create(`"_inst_name_`", this); `endif +// Convert arbitrary text / expression to string. +`ifndef DV_STRINGIFY + `define DV_STRINGIFY(I_) `"I_`" +`endif + // Common check macros used by DV_CHECK error and fatal macros. // Note: Should not be called by user code `ifndef DV_CHECK @@ -71,7 +88,7 @@ `ifndef DV_CHECK_EQ `define DV_CHECK_EQ(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ begin \ - if (!(ACT_ == EXP_)) begin \ + if (!((ACT_) == (EXP_))) begin \ `uvm_``SEV_(ID_, $sformatf("Check failed %s == %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \ `"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_)) \ end \ @@ -81,7 +98,7 @@ `ifndef DV_CHECK_NE `define DV_CHECK_NE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ begin \ - if (!(ACT_ != EXP_)) begin \ + if (!((ACT_) != (EXP_))) begin \ `uvm_``SEV_(ID_, $sformatf("Check failed %s != %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \ `"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_)) \ end \ @@ -91,7 +108,7 @@ `ifndef DV_CHECK_CASE_EQ `define DV_CHECK_CASE_EQ(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ begin \ - if (!(ACT_ === EXP_)) begin \ + if (!((ACT_) === (EXP_))) begin \ `uvm_``SEV_(ID_, $sformatf("Check failed %s === %s (0x%0h [%0b] vs 0x%0h [%0b]) %s", \ `"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_)) \ end \ @@ -101,7 +118,7 @@ `ifndef DV_CHECK_CASE_NE `define DV_CHECK_CASE_NE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ begin \ - if (!(ACT_ !== EXP_)) begin \ + if (!((ACT_) !== (EXP_))) begin \ `uvm_``SEV_(ID_, $sformatf("Check failed %s !== %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \ `"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_)) \ end \ @@ -111,7 +128,7 @@ `ifndef DV_CHECK_LT `define DV_CHECK_LT(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ begin \ - if (!(ACT_ < EXP_)) begin \ + if (!((ACT_) < (EXP_))) begin \ `uvm_``SEV_(ID_, $sformatf("Check failed %s < %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \ `"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_)) \ end \ @@ -121,7 +138,7 @@ `ifndef DV_CHECK_GT `define DV_CHECK_GT(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ begin \ - if (!(ACT_ > EXP_)) begin \ + if (!((ACT_) > (EXP_))) begin \ `uvm_``SEV_(ID_, $sformatf("Check failed %s > %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \ `"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_)) \ end \ @@ -131,7 +148,7 @@ `ifndef DV_CHECK_LE `define DV_CHECK_LE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ begin \ - if (!(ACT_ <= EXP_)) begin \ + if (!((ACT_) <= (EXP_))) begin \ `uvm_``SEV_(ID_, $sformatf("Check failed %s <= %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \ `"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_)) \ end \ @@ -141,13 +158,27 @@ `ifndef DV_CHECK_GE `define DV_CHECK_GE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ begin \ - if (!(ACT_ >= EXP_)) begin \ + if (!((ACT_) >= (EXP_))) begin \ `uvm_``SEV_(ID_, $sformatf("Check failed %s >= %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \ `"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_)) \ end \ end `endif +`ifndef DV_CHECK_STREQ + `define DV_CHECK_STREQ(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ + if (!((ACT_) == (EXP_))) begin \ + `uvm_``SEV_(ID_, $sformatf("Check failed \"%s\" == \"%s\" %s", ACT_, EXP_, MSG_)); \ + end +`endif + +`ifndef DV_CHECK_STRNE + `define DV_CHECK_STRNE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ + if (!((ACT_) != (EXP_))) begin \ + `uvm_``SEV_(ID_, $sformatf("Check failed \"%s\" != \"%s\" %s", ACT_, EXP_, MSG_)); \ + end +`endif + // Fatal version of the checks `ifndef DV_CHECK_FATAL `define DV_CHECK_FATAL(T_, MSG_="", ID_=`gfn) \ @@ -184,6 +215,16 @@ `DV_CHECK_GE(ACT_, EXP_, MSG_, fatal, ID_) `endif +`ifndef DV_CHECK_STREQ_FATAL + `define DV_CHECK_STREQ_FATAL(ACT_, EXP_, MSG_="", ID_=`gfn) \ + `DV_CHECK_STREQ(ACT_, EXP_, MSG_, fatal, ID_) +`endif + +`ifndef DV_CHECK_STRNE_FATAL + `define DV_CHECK_STRNE_FATAL(ACT_, EXP_, MSG_="", ID_=`gfn) \ + `DV_CHECK_STRNE(ACT_, EXP_, MSG_, fatal, ID_) +`endif + // Shorthand for common foo.randomize() + fatal check `ifndef DV_CHECK_RANDOMIZE_FATAL `define DV_CHECK_RANDOMIZE_FATAL(VAR_, MSG_="Randomization failed!", ID_=`gfn) \ @@ -208,16 +249,18 @@ `DV_CHECK_FATAL(std::randomize(VAR_) with {WITH_C_}, MSG_, ID_) `endif -// Shorthand for common this.randomize(foo) + fatal check +// Shorthand for common cls_inst.randomize(member) + fatal check +// Randomizes a specific member of a class instance. `ifndef DV_CHECK_MEMBER_RANDOMIZE_FATAL - `define DV_CHECK_MEMBER_RANDOMIZE_FATAL(VAR_, MSG_="Randomization failed!", ID_=`gfn) \ - `DV_CHECK_FATAL(this.randomize(VAR_), MSG_, ID_) + `define DV_CHECK_MEMBER_RANDOMIZE_FATAL(VAR_, CLS_INST_=this, MSG_="Randomization failed!", ID_=`gfn) \ + `DV_CHECK_FATAL(CLS_INST_.randomize(VAR_), MSG_, ID_) `endif -// Shorthand for common this.randomize(foo) with { } + fatal check +// Shorthand for common cls_inst.randomize(member) with { } + fatal check +// Randomizes a specific member of a class instance with inline constraints. `ifndef DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL - `define DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(VAR_, C_, MSG_="Randomization failed!", ID_=`gfn) \ - `DV_CHECK_FATAL(this.randomize(VAR_) with {C_}, MSG_, ID_) + `define DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(VAR_, C_, CLS_INST_=this, MSG_="Randomization failed!", ID_=`gfn) \ + `DV_CHECK_FATAL(CLS_INST_.randomize(VAR_) with {C_}, MSG_, ID_) `endif // print static/dynamic 1d array or queue @@ -297,15 +340,16 @@ `define GET_PARITY(val, odd=0) (^val ^ odd) `endif -// wait a task or statement with timer watchdog +// Wait a task or statement with exit condition +// Kill the thread when either the wait statement is completed or exit condition occurs // input WAIT_ need to be a statement. Here are some examples // `DV_SPINWAIT(wait(...);, "Wait for ...") // `DV_SPINWAIT( // while (1) begin // ... // end) -`ifndef DV_SPINWAIT -`define DV_SPINWAIT(WAIT_, MSG_ = "timeout occurred!", TIMEOUT_NS_ = default_spinwait_timeout_ns, ID_ =`gfn) \ +`ifndef DV_SPINWAIT_EXIT +`define DV_SPINWAIT_EXIT(WAIT_, EXIT_, MSG_ = "exit condition occurred!", ID_ =`gfn) \ begin \ fork begin \ fork \ @@ -313,10 +357,164 @@ WAIT_ \ end \ begin \ - wait_timeout(TIMEOUT_NS_, ID_, MSG_); \ + EXIT_ \ + if (MSG_ != "") begin \ + `uvm_info(ID_, MSG_, UVM_HIGH) \ + end \ end \ join_any \ disable fork; \ end join \ end `endif + +// wait a task or statement with timer watchdog +`ifndef DV_SPINWAIT +`define DV_SPINWAIT(WAIT_, MSG_ = "timeout occurred!", TIMEOUT_NS_ = default_spinwait_timeout_ns, ID_ =`gfn) \ + `DV_SPINWAIT_EXIT(WAIT_, wait_timeout(TIMEOUT_NS_, ID_, MSG_);, "", ID_) +`endif + +// Control assertions in the DUT. +// +// This macro is invoked in top level testbench that instantiates the DUT. It spawns off an initial +// block that forever waits for a resource of type bit named by the string arg ~LABEL_~ that +// can be set by any entity in the testbench. Based on the value set, it enables or disables the +// assertions at the hierarchy of the provided path. The entity setting the resource value invokes +// uvm_config_db#(bit)::set(...) and this macro calls the corresponding get. +// +// LABEL_ : Name of the assertion control resource bit (string). +// HIER_ : Path to the module within which the assertion is controlled. +// LEVELS_: Number of levels within the module to control the assertions. +// SCOPE_ : Hierarchical string path to the testbench where this macro is invoked, example: %m. +// ID_ : Identifier string used for UVM logs. +`ifndef DV_ASSERT_CTRL +`define DV_ASSERT_CTRL(LABEL_, HIER_, LEVELS_ = 0, SCOPE_ = "", ID_ = "%m") \ + initial begin \ + bit assert_en; \ + forever begin \ + uvm_config_db#(bit)::wait_modified(null, SCOPE_, LABEL_); \ + if (!uvm_config_db#(bit)::get(null, SCOPE_, LABEL_, assert_en)) begin \ + `uvm_fatal(ID_, $sformatf("Failed to get \"%0s\" from uvm_config_db", LABEL_)) \ + end \ + if (assert_en) begin \ + `uvm_info(ID_, $sformatf("Enabling assertions: %0s", `DV_STRINGIFY(HIER_)), UVM_LOW) \ + $asserton(LEVELS_, HIER_); \ + end else begin \ + `uvm_info(ID_, $sformatf("Disabling assertions: %0s", `DV_STRINGIFY(HIER_)), UVM_LOW) \ + $assertoff(LEVELS_, HIER_); \ + end \ + end \ + end +`endif + +// Enable / disable assertions at a module hierarchy identified by LABEL_. +// +// This goes in conjunction with `DV_ASSERT_CTRL() macro above, but is invoked in the entity that is +// sending the req to turn on / off the assertions. Note that that piece of code invoking this macro +// does not have the information on the actual hierarchical path to the module or the levels - this +// is 'wrapped' into the LABEL_ instead. DV user needs to uniquify the label sufficienly enough to +// reflect it. +// +// LABEL_ : Name of the assertion control resource bit (string). +// VALUE_ : Value of the control bit - 1 - enable assertions, 0 - disable assertions. +// SCOPE_ : Hierarchical string path to the testbench where this macro is invoked, example: %m. +`ifndef DV_ASSERT_CTRL_REQ +`define DV_ASSERT_CTRL_REQ(LABEL_, VALUE_, SCOPE_="") \ + begin \ + uvm_config_db#(bit)::set(null, SCOPE_, LABEL_, VALUE_); \ + end +`endif + +// Macros for logging (info, warning, error and fatal severities). +// +// These are meant to be invoked in modules and interfaces that are shared between DV and Verilator +// testbenches. +`ifdef UVM +`ifndef DV_INFO + `define DV_INFO(MSG_, VERBOSITY_ = UVM_LOW, ID_ = $sformatf("%m")) \ + `uvm_info(ID_, MSG_, VERBOSITY_) +`endif + +`ifndef DV_WARNING + `define DV_WARNING(MSG_, ID_ = $sformatf("%m")) \ + `uvm_warning(ID_, MSG_) +`endif + +`ifndef DV_ERROR + `define DV_ERROR(MSG_, ID_ = $sformatf("%m")) \ + `uvm_error(ID_, MSG_) +`endif + +`ifndef DV_FATAL + `define DV_FATAL(MSG_, ID_ = $sformatf("%m")) \ + `uvm_fatal(ID_, MSG_) +`endif + +`else // UVM + +`ifndef DV_INFO + `define DV_INFO(MSG_, VERBOSITY = DUMMY_, ID_ = $sformatf("%m")) \ + $display("%0t: (%0s:%0d) [%0s] %0s", $time, `__FILE__, `__LINE__, ID_, MSG_); +`endif + +`ifndef DV_WARNING + `define DV_WARNING(MSG_, ID_ = $sformatf("%m")) \ + $warning("%0t: (%0s:%0d) [%0s] %0s", $time, `__FILE__, `__LINE__, ID_, MSG_); +`endif + +`ifndef DV_ERROR + `define DV_ERROR(MSG_, ID_ = $sformatf("%m")) \ + $error("%0t: (%0s:%0d) [%0s] %0s", $time, `__FILE__, `__LINE__, ID_, MSG_); +`endif + +`ifndef DV_FATAL + `define DV_FATAL(MSG_, ID_ = $sformatf("%m")) \ + $fatal("%0t: (%0s:%0d) [%0s] %0s", $time, `__FILE__, `__LINE__, ID_, MSG_); +`endif + +`endif // UVM + +// Declare array of alert interface, using parameter NUM_ALERTS and LIST_OF_ALERTS, and connect to +// arrays of wires (alert_tx and alert_rx). User need to manually connect these wires to DUT +// Also set each alert_if to uvm_config_db to use in env +`ifndef DV_ALERT_IF_CONNECT +`define DV_ALERT_IF_CONNECT \ + alert_esc_if alert_if[NUM_ALERTS](.clk(clk), .rst_n(rst_n)); \ + prim_alert_pkg::alert_rx_t [NUM_ALERTS-1:0] alert_rx; \ + prim_alert_pkg::alert_tx_t [NUM_ALERTS-1:0] alert_tx; \ + for (genvar k = 0; k < NUM_ALERTS; k++) begin : connect_alerts_pins \ + assign alert_rx[k] = alert_if[k].alert_rx; \ + assign alert_if[k].alert_tx = alert_tx[k]; \ + initial begin \ + uvm_config_db#(virtual alert_esc_if)::set(null, $sformatf("*.env.m_alert_agent_%0s", \ + LIST_OF_ALERTS[k]), "vif", alert_if[k]); \ + end \ + end +`endif + +// Instantiates a covergroup in an interface or module. +// +// This macro assumes that a covergroup of the same name as the __CG_NAME arg is defined in the +// interface or module. It just adds some extra signals and logic to control the creation of the +// covergroup instance with ~bit en_~. This defaults to 0. It is ORed with the external +// __COND signal. The testbench can modify it at t = 0 based on the test being run. +// NOTE: This is not meant to be invoked inside a class. +// +// __CG_NAME : Name of the covergroup. +// __COND : External condition / expr that controls the creation of the covergroup. +// __CG_ARGS : Arguments to covergroup instance, if any. Args MUST BE wrapped in (..). +`ifndef DV_INSTANTIATE_CG +`define DV_INSTANTIATE_CG(__CG_NAME, __COND = 1'b1, __CG_ARGS = ()) \ + bit en_``__CG_NAME = 1'b0; \ + __CG_NAME __CG_NAME``_inst; \ + initial begin \ + /* The #1 delay below allows any part of the tb to control the conditions first at t = 0. */ \ + #1; \ + if ((en_``__CG_NAME) || (__COND)) begin \ + `DV_INFO({"Creating covergroup ", `"__CG_NAME`"}, UVM_MEDIUM) \ + __CG_NAME``_inst = new``__CG_ARGS; \ + end \ + end +`endif + +`endif // __DV_MACROS_SVH__ diff --git a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_report_server.sv b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_report_server.sv index a29342e647..be40391b37 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_report_server.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_report_server.sv @@ -6,12 +6,15 @@ class dv_report_server extends uvm_default_report_server; bit show_file_line = 1'b1; + // if enabled, show the relative path of the file. By default only show file name + bit show_file_path = 1'b0; bit use_default_uvm_report_message_format = 1'b0; function new (string name = ""); super.new(name); // provide ability to override these knobs over cli void'($value$plusargs("show_file_line=%0b", show_file_line)); + void'($value$plusargs("show_file_path=%0b", show_file_path)); void'($value$plusargs("use_default_uvm_report_message_format=%0b", use_default_uvm_report_message_format)); endfunction @@ -66,7 +69,7 @@ class dv_report_server extends uvm_default_report_server; string file_line; if (show_file_line && filename != "") begin - filename = get_no_hier_filename(filename); + if (!show_file_path) filename = get_no_hier_filename(filename); file_line = $sformatf("(%0s:%0d) ", filename, line); end obj_name = {obj_name, ((obj_name != "") ? " " : "")}; diff --git a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils.core b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils.core index 3bcf5f7249..1412d31b83 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils.core +++ b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils.core @@ -8,13 +8,14 @@ description: "DV utilities" filesets: files_dv: depend: + - lowrisc:dv:dv_macros - lowrisc:dv:common_ifs - lowrisc:prim:assert:0.1 - lowrisc:ibex:bus_params_pkg files: - dv_utils_pkg.sv - - dv_macros.svh: {is_include_file: true} - dv_report_server.sv: {is_include_file: true} + - dv_vif_wrap.sv: {is_include_file: true} file_type: systemVerilogSource targets: diff --git a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv index 3b47bfe0ca..2c99462e74 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv @@ -85,6 +85,17 @@ package dv_utils_pkg; return (a > b) ? a : b; endfunction + // get absolute value of the input. Usage: absolute(val) or absolute(a - b) + function automatic uint absolute(int val); + return val >= 0 ? val : -val; + endfunction + + // endian swap + function automatic logic [31:0] endian_swap(logic [31:0] data); + return {<<8{data}}; + endfunction + +`ifdef UVM // Simple function to set max errors before quitting sim function automatic void set_max_quit_count(int n); uvm_report_server report_server = uvm_report_server::get_server(); @@ -121,16 +132,6 @@ package dv_utils_pkg; end endfunction - // get absolute value of the input. Usage: absolute(val) or absolute(a - b) - function automatic uint absolute(int val); - return val >= 0 ? val : -val; - endfunction - - // endian swap - function automatic logic [31:0] endian_swap(logic [31:0] data); - return {<<8{data}}; - endfunction - // create a sequence by name and return the handle of uvm_sequence function automatic uvm_sequence create_seq_by_name(string seq_name); uvm_object obj; @@ -149,8 +150,29 @@ package dv_utils_pkg; end return seq; endfunction +`endif + + // Returns the hierarchical path to the interface / module N levels up. + // + // Meant to be invoked inside a module or interface. + // hier: String input of the interface / module, typically $sformatf("%m"). + // n_levels_up: Integer number of levels up the hierarchy to omit. + // Example: if (hier = tb.dut.foo.bar, n_levels_up = 2), then return tb.dut + function automatic string get_parent_hier(string hier, int n_levels_up = 1); + int idx; + int level; + if (n_levels_up <= 0) return hier; + for (idx = hier.len() - 1; idx >= 0; idx--) begin + if (hier[idx] == ".") level++; + if (level == n_levels_up) break; + end + return (hier.substr(0, idx - 1)); + endfunction // sources +`ifdef UVM `include "dv_report_server.sv" + `include "dv_vif_wrap.sv" +`endif endpackage diff --git a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_vif_wrap.sv b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_vif_wrap.sv new file mode 100644 index 0000000000..61d99479e7 --- /dev/null +++ b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_vif_wrap.sv @@ -0,0 +1,96 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Abstract class meant to hold arbitrary virtual interface handles. +// +// Written primarily for an interface which implements functional coverage, this could be used +// for other purposes as well. This abstract class provides utilities & macros to retrieve +// virtual interface handles that are bound to a DUT's sub-modules. These sub-module interfaces must +// self-register using the `DV_VIF_WRAP_SET_VIF()` macro (see details below). The extended class +// then implements the `get_vifs()` method using the `DV_VIF_WRAP_GET_VIF*` macros below to retrieve +// the sub-module interface handles it maintains. +virtual class dv_vif_wrap; + string hier; // Represents the hierarchy of the parent module or interface. + string name; // Name of the class instance. + + function new(string hier, string name = ""); + this.hier = hier; + this.name = name; + endfunction + + // Abstract method implemented by the extended class. It is recommended to invoke the helper + // macros below rather than manually define it. + pure virtual task get_vifs(); + +endclass + +// Helper macros. +// +// These are defined in the file itself since they are tightly coupled to the class definition +// above. These are scoped globally so that extended classes can invoke them. + +// Enable an interface to register itself (set its handle into the config db). +// +// Meant to be invoked from an interface. The macros invocation causes the interface to register +// itself into the uvm_resource_db pool. The derived class of dv_vif_wrap retrieves the handle to +// that interface handle from the uvm_resource db pool. +// +// SV LRM does not yet allow referencing the instance of an interface within itself as one +// would in case of a class using the ~this~ keyword. However, most major simulators actually +// support this in their own custom way. On VCS, a reference to self within the interface can be set +// using `interface::self()` construct. On Xcelium, this is achieved by simply referencing the +// interface name. +// +// _IF: The SV interface +// _VIF: The corresponding virtual interface handle name +// _LEVEL: # of hierarchical levels the module to which the SV interface is bound, starting at the +// top level DUT instance. +`define DV_VIF_WRAP_SET_VIF(_IF, _VIF, _LEVEL = 0) \ + import uvm_pkg::*; \ + function automatic void self_register(); \ + string path; \ + virtual _IF vif; \ + /* Initial block adds another level in the path hierarchy which needs to be split out. */ \ + /* Add one more to go one level up the interface instance. */ \ + /* Example: tb.dut.core.u_foo_if.self_register -> tb.dut.core. */ \ + path = dv_utils_pkg::get_parent_hier(.hier($sformatf("%m")), .n_levels_up(2 + _LEVEL)); \ +`ifdef VCS \ + vif = interface::self(); \ +`elsif XCELIUM \ + vif = _IF; \ +`else \ + vif = _IF; \ +`endif \ + uvm_pkg::uvm_resource_db#(virtual _IF)::set(path, `"_VIF`", vif); \ + endfunction \ + initial self_register(); + +// Enables the retrieval of individual vifs. +// +// The three macros below go together to define the _get_vifs() task in the extended class. +`define DV_VIF_WRAP_GET_VIFS_BEGIN \ + task get_vifs(); \ + fork \ + +// To avoid race condition between the instant when an interface handle is set into the config db +// and the instant when it is retrieved (in the same time step, at t = 0), the macro below invokes +// uvm_config_db#(..)::wait_modified() to ensure that the retrieval is done only after the set. +`define DV_VIF_WRAP_GET_VIF(_IF, _VIF) \ + begin \ + bit vif_found; \ + /* At most 2 retries. */ \ + repeat (2) begin \ + /* Force the evaluation at the end of the time step. */ \ + #0; \ + if (uvm_pkg::uvm_resource_db#(virtual _IF)::read_by_name(hier, `"_VIF`", _VIF)) begin \ + vif_found = 1'b1; \ + break; \ + end \ + end \ + `DV_CHECK_FATAL(vif_found, {`"_VIF`", " not found in the resource db"}, hier) \ + end + +`define DV_VIF_WRAP_GET_VIFS_END \ + join \ + endtask diff --git a/vendor/lowrisc_ip/dv/tools/Makefile b/vendor/lowrisc_ip/dv/tools/Makefile deleted file mode 100644 index 5815adcd70..0000000000 --- a/vendor/lowrisc_ip/dv/tools/Makefile +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright lowRISC contributors. -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 -# directory paths -# _ROOT are paths indicating a 'starting point' -# _PATH paths are intermediate paths leading to a _DIR -# _LOC are directory names without the hierarchy -# _DIR paths are final paths used in make rules -# All these variables can be overridden from the command line -# Test Makefile needs to set DV_DIR, DUT_TOP, TB_TOP, FUSESOC_CORE, COMPILE_KEY and TEST_NAME -# at minimum - -export SHELL := /bin/bash -TIMESTAMP ?= $(shell date +%m.%d.%y_%H.%M.%S) -MAKE_ROOT := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) -export PROJ_ROOT := ${MAKE_ROOT}/../../.. -export PRJ_DIR := ${PROJ_ROOT} -export CURR_DIR := $(shell pwd) -SCRATCH_ROOT ?= ${DV_DIR}/scratch - -SCRATCH_LOC ?= ${DUT_TOP} -BUILD_LOC ?= ${COMPILE_KEY} -RUN_LOC ?= ${TIMESTAMP} - -SCRATCH_PATH ?= ${SCRATCH_ROOT}/${SCRATCH_LOC} -BUILD_DIR := ${SCRATCH_PATH}/${BUILD_LOC} -RUN_PATH ?= ${SCRATCH_PATH}/${TEST_NAME} -RUN_DIR := ${RUN_PATH}/${RUN_LOC} -COV_REPORT_DIR ?= ${SCRATCH_PATH}/cov_report -SW_BUILD_DIR ?= ${RUN_DIR}/sw_build -SW_ROOT_DIR := ${PRJ_DIR}/sw -SW_BUILD_DEVICE ?= fpga_nexysvideo - -JOB_OPTS ?= -BUILD_JOB_OPTS ?= $(JOB_OPTS) -RUN_JOB_OPTS ?= $(JOB_OPTS) - -# limit run directories upto a limit specified below -RUN_DIR_LIMIT ?= 5 - -# global simulation specific variables (but simulator independent) -SEED ?= $(shell od -vAn -N4 -tu < /dev/random | xargs) -BUILD_LOG ?= ${BUILD_DIR}/build.log -RUN_LOG ?= ${RUN_DIR}/run.log -UVM_VERBOSITY ?= UVM_LOW - -TOPS ?= ${TB_TOP} ${DUT_TOP}_bind - -# Options for SV build / C build / simulation run -# CL_ prefix represents command line versions of these options - they should be empty and only -# be set on the command line - -# BUILD_OPTS are passed to the simulator during the SV testbench compile step -CL_BUILD_OPTS += -BUILD_OPTS += $(addprefix -top , $(TOPS)) - -# RUN_OPTS are passed to the simulation executable that is invoked to run the simulation -CL_RUN_OPTS += -RUN_OPTS += +UVM_NO_RELNOTES - -# SW_OPTS are options for SW apps that come with their own Makefile (example coremark) -CL_SW_OPTS += -SW_OPTS += ${CL_SW_OPTS} - -# SW_FLAGS are compiler flags / directives that we can pass for each test using our own Makefiles -CL_SW_FLAGS += -SW_FLAGS += ${CL_SW_FLAGS} - -# default project-wide bus widths -TL_AW ?= 32 -TL_DW ?= 32 -TL_DBW ?= 4 - -# add auxiliary / helper mk files -# set simulator to vcs by default -SIMULATOR ?= vcs - -# common tests/seqs -include ${MAKE_ROOT}/common_tests.mk - -# tool to generate file list -include ${MAKE_ROOT}/fusesoc.mk - -# modes / switches (option groups) that can be turned on easily -include ${MAKE_ROOT}/modes.mk - -# add tool specific mk file -ifeq (${SIMULATOR},vcs) - include ${MAKE_ROOT}/vcs/vcs.mk -else ifeq (${SIMULATOR},xcelium) - include ${MAKE_ROOT}/xcelium/xcelium.mk -# else add other tool specific mk files -endif - -# generic rules to sequence build and run flows -include ${MAKE_ROOT}/rules.mk diff --git a/vendor/lowrisc_ip/dv/tools/README.md b/vendor/lowrisc_ip/dv/tools/README.md index c1b9688048..499372ef2b 100644 --- a/vendor/lowrisc_ip/dv/tools/README.md +++ b/vendor/lowrisc_ip/dv/tools/README.md @@ -1,225 +1,2 @@ -# DV build and run flow -The Makefile system implemented here is a standardized solution for building and -running DV sims for all ip/block/top level testbenches. This is only a stop -gap solution until a proper build and run tool is developed and implemented. The -way the Makefiles are structured will hopefully make the eventual transition -easier. - -## Makefile Organization -``` -- hw/ip//dv/Makefile OR - hw/top_earlgrey/dv/Makefile - - hw/dv/tools/Makefile - - ral_gen.mk - - fusesoc.mk - - modes.mk - - rules.mk - - vcs/vcs.mk # if SIMULATOR=vcs - - xcelium/xcelium.mk # if SIMULATOR=xcelium -``` - -### Test Makefile -The test Makefile that serves as the entry point into the DV build and run -flow is placed in individual 'dv' directories of each testbench. For example: -```hw/ip/uart/dv/Makefile``` -This includes the top level Makefile, some mandatory variables that are to be -set and exported and the actual tests. - -### Top level Makefile -This includes the top level Makefile which contains generic set of variable -names (most of which can be overridden) to indicate where, what and how to build -and run tests, some option groups and generic set of rules. This is located at -hw/dv/tools/Makefile - -### Generic Tool-independent Make variables -The following is a list of Make variables that are used for specifying options -to run simulations in a tool-independent way. Some variables are overridable in -the Test Makefile (or command line) and some are appended to group / add options -together. Please see following table for more details: - -Make variable | Description | Overridable (O) or Appendable (A) | ---------------|-------------|-----------------------------------| -DV_DIR | This is the top level DV directory for the IP containing the Test Makefile. | | -DUT_TOP | This is the top level dut module under test. | | -TB_TOP | This is the top level tb module under test. This is used by the `.tcl` file when dumping waves. | | -FUSESOC_CORE | This is the testbench fusesoc .core name that contains the simulation target. This .core file is typically placed in the same directory as the test Makefile. | | -COMPILE_KEY | Users need to define COMPILE_KEY sets for building Test Makefile, CL with a unique sets of compile time options. This is to be done in the Test Makefile in this way:
`ifeq ($(COMPILE_KEY),foo)`
 `BUILD_OPTS += +define+FOO`
`endif`
There is a 'default' compile key already added which implies no additional compile time options are required. Within each test specification, the COMPILE_KEY can be overridden to use the specific compile key.
`ifeq ($(TEST_NAME),foo_test)`
 `COMPILE_KEY = foo`
 `# other test opts`
`endif` | O (Within tests, & command line) | -UVM_TEST | SV UVM test class to create in the test. This is set to the 'base_test' by default and is overridden in the test specifications if needed. | O (Test Makefile) | -UVM_TEST_SEQ | SV UVM test sequence to create in the test. This is set to the 'base_test' by default and is overridden in the test specifications if needed. | O (Test Makefile) | -TEST_NAME | Name of the test to run. These are specified in the test Makefile. By default, it is set to run the sanity test (simply calling 'make' will run this test). | O (command line only) | -SIMULATOR | What simulator to use. Currently only 'vcs' is supported and is set by default. | O | -BUILD_OPTS | Options to pass for build. | A (Test Makefile :: COMPILE_KEY specifications only) | -CL_BUILD_OPTS | Pass additional build options on the command line. | A (command line only) | -RUN_OPTS | Options to pass for run. | A (Test Makefile :: test specifications only) | -CL_RUN_OPTS | Pass additional run options on the command line. | A (command line only) | -WAVES | Enable wave dumps (fsdb). Set to 0 by default; override with WAVES=1. | O | -SIMPROFILE | Turn on sim profiling (time option by default). Set to 0 by default; override with SIMPROFILE=1. | O | -COV | Turn on coverage collection. Set to 0 by default; override with COV=1. | O | -UVM_VERBOSITY | Verbosity level for UVM. Set to UVM_LOW by default; override with UVM_VERBOSITY=UVM_NONE / UVM_LOW / UVM_HIGH / UVM_DEBUG. | O | -BUILD_LOC | Build directory name in the scratch area. This defaults to the COMPILE_KEY used by the corresponding test. You can override it to use a different directory name. This is helpful when there is a test / regression already running and you made some fixes and want to rerun some failing test from another terminal without affecting the existing running sims. | O | -RUN_LOC | Run directory name in the scratch area. This defaults to a 'timestamp' value. You can override this to a specific name. Everytime a test is run, it creates a new directory with the current timestamp for the name. By overriding this with a specific name and rerunning the same test with the same directory name, you won't have to reopen waves - you can just reload. This is useful during test debug. | O | -SCRATCH_ROOT | This is the path to the root scratch area for bulding and running tests. If SCRATCH_ROOT is not already set, it will create a `scratch` directory in `pwd` which typically is the same as `DV_DIR`. | O (command line only) | -RUN_DIR_LIMIT | When you run tests, The flow creates a new `RUN_LOC` directory with the current timestamp (unless it is overridden). In course of debug, you may run the same test multiple times, which will eventually result in a large number of old timestamp directories in the scratch space. Without periodic cleanup, you may run out of scratch space. By default, this variable is set to 5, which means before running the test, it will prune the test area to contain no more than RUN_DIR_LIMIT number of most recent directories (including the newly created one). On the flipside, if you want to run the same test with a large number of iterations, you will need to override this variable to be set to that many iterations to prevent the flow from deleting actively running simulations. | O (command line only) | -SEED | This is a run time parameter passed to the sim executable. It uses `od` command to generate a 32-bit random number to run the sim with a unique seed. You can override this variable on the command line to run the test with a specific seed for debug. | O (command line only) | -XPROP | This is a compile time parameter to enable / disable X-Propagation. Set to 1 by default. | O (command line only) | - -This is not an exhaustive list of Make variables. Please see `./Makefile` and -`./*.mk` for more such variables in use. - -### ral_gen.mk -#### RAL generation tool specific mk file -This lists tools and options to generate the ral model by simply running the -command `make ral` from the same directory as the Test Makefile. For generating -the UVM REG based RAL model, we use the same [in-house tool]({{< relref "doc/rm/register_tool" >}}) for autogenerating -RTL with mako template. - -### fusesoc.mk -#### RTL/TB filelist generation tool specific mk file -This lists tools and options to generate the flattened filelist to supply to the -simulator during the build step. - -### modes.mk -#### Modes or option groups that can be turned on easily -This lists common modes (which are groups of compile time and / or run time options) -passed to the simulator for turning on a specific function. Modes listed in this -file are meant to be common across all environments and simulator tools. Modes added -in this file are `WAVES`, `COV`, `SIMPROFILE` and `UVM_TRACE`. These are truly -global and can be turned on easily on the command line by setting them to 1: `COV=1` -switch on the command line will turn on coverage. These modes may require options -that are specific to the simulator tool, so the make variable `SIMULATOR` can be used -to set tool specific options. - -### rules.mk -#### List of Make targets and recipes -This is the only file in the make flow that contains targets and recipes that -are completely agnostic to the tools used. It sequences the build and run set -of targets. - -### Simulator mk ({vcs, xcelium}.mk) -#### Simulator tool specific options -The top level Makefile uses `SIMULATOR` variable (which is set to `vcs` by -default) to enable tool specific options. If support for new tools need to be -added, then those tool specific mk files need to be supplied. It sets the -following mandatory variables - `SIMCC` & `SIMX`. It also exports additional -tool specific variables to the sub shell when the recipes are executed. This -file has been placed in the respective tool directory. - -### Simulation targets -* **build**: Compile and elaborate the testbench -* **gen_sv_flist**: Generate the full file list which will be used by the - simulator to build the simulation executable -* **run**: Run the test (the simulation executable needs to be built already) -* **env/\_reg_block.sv**: Generate the RAL model only -* **sw_build**: Only compile the C SW test - -### Building and running tests -All of the below command examples are to be run from the 'dv' directory -containing the Test Makefile. - -##### Run the following command to build and run tests: -```console -$ make TEST_NAME=[test-name] [overrides] -``` - -##### To only buld the simv: -```console -$ make build TEST_NAME=[test-name] [overrides] -``` - -##### To run the sim after build is complete: -```console -$ make run TEST_NAME=[test-name] [overrides] -``` - -##### To build and run the sanity test: -```console -$ make -``` -This will work provided user has specified a set a 'default' value to the -`TEST_NAME` Make variable. - -##### Below are some examples - -###### Build and run a test: -This builds the 'default' compile key and runs the 'uart_sanity' test -```console -$ make TEST_NAME=uart_sanity -``` - -###### Run with specific seed: -```console -$ make TEST_NAME= SEED=123423334 -``` - -###### Dump waves: -```console -$ make TEST_NAME= SEED=123423334 WAVES=1 -``` - -###### Run with coverage option enabled: -```console -$ make TEST_NAME= COV=1 -``` - -The options.mk file lists several tool options passed to the build and run steps -for enabling coverage collection. One of the options is adding a hier file (with -a `-cm_hier` switch). By default, it looks for a file called `cover.cfg` in the -'dv' directory set using the `CM_HIER` Make variable - if it exists, it adds the -switch automatically when coverage is enabled. If another hier file is desired - (or with another name), it can be placed anywhere as the user desires and user can - add the following line to the Test Makefile: - -```gnumake -CM_HIER := SIMPROFILE=1 -``` - -###### Override UVM verbosity: -```console -$ make TEST_NAME= WAVES=1 UVM_VERBOSITY=UVM_DEBUG -``` - -###### Build only (This will build the 'default' compile key): -```console -$ make build -``` - -###### Build 'foo' compile key instead: -```console -$ make build COMPILE_KEY=foo -``` - -###### Build with 'FOO' preprocessor flag: -```console -$ make build CL_BUILD_OPTS+=+define+FOO -``` - -###### Run with 'FOO' runtime plusarg: -```console -$ make TEST_NAME= CL_RUN_OPTS+=+FOO -``` - -###### Run test with Xcelium: -``` -$ make TEST_NAME= SIMULATOR=xcelium -``` - -###### Run test with Xcelium and dump WAVES in fsdb: -```console -$ make TEST_NAME= SIMULATOR=xcelium WAVES=1 -``` - -###### Run test with Xcelium and dump WAVES in shm: -```console -$ make TEST_NAME= SIMULATOR=xcelium WAVES=1 DUMP=shm -``` - -###### Run only (This assumes the sim executable for the specified compile key is available): - -```console -$ make run TEST_NAME= SEED=123423334 WAVES=1 -``` +# DV simulation flow +TODO diff --git a/vendor/lowrisc_ip/dv/tools/common.tcl b/vendor/lowrisc_ip/dv/tools/common.tcl new file mode 100644 index 0000000000..f9a941d1c6 --- /dev/null +++ b/vendor/lowrisc_ip/dv/tools/common.tcl @@ -0,0 +1,61 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +# Commonly used globals & procs. This file must be sourced first. +set simulator "" +if {[info exists ::env(SIMULATOR)]} { + set simulator "$::env(SIMULATOR)" +} else { + puts "ERROR: tool script run without SIMULATOR environment variable." + quit +} + +set waves "none" +if {[info exists ::env(WAVES)]} { + set waves "$::env(WAVES)" +} + +set tb_top "tb" +if {[info exists ::(TB_TOP)]} { + set tb_top "$::env(TB_TOP)" + puts "WARNING: TB_TOP environment variable not set - using \"tb\" as the + top level testbench hierarchy." +} + +# Checks if variable is defined, else throw an error and exit. +proc checkVarExists {var} { + upvar $var var_ + if {![info exists var_]} { + puts "ERROR: Variable \"$var\" not found." + quit + } +} + +# If variable is defined, then use it, else set the default value. +proc setDefault {var value} { + upvar $var var_ + if {[info exists var_]} { + puts "INFO: \"$var\" is already set to \"$var_\"." + } else { + puts "INFO: Setting \"$var\" to \"$value\"." + set var_ $value + } + return $var_ +} + +proc checkEq {var value} { + upvar $var var_ + if {$var_ != $value} { + puts "ERROR: Check failed \"$var\" == \"$value\"!. Actual: \"$var_\"." + quit + } +} + +proc checkNe {var value} { + upvar $var var_ + if {$var_ == $value} { + puts "ERROR: Check failed \"$var\" != \"$value\"!. Actual: \"$var_\"." + quit + } +} diff --git a/vendor/lowrisc_ip/dv/tools/common_tests.mk b/vendor/lowrisc_ip/dv/tools/common_tests.mk deleted file mode 100644 index 12a4246f02..0000000000 --- a/vendor/lowrisc_ip/dv/tools/common_tests.mk +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright lowRISC contributors. -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 -# Makefile option groups that can be enabled by test Makefile / command line. -# These are generic set of option groups that apply to all testbenches. -# These are meant to be simulator agnostic -# Please add tool specific options with appropriate ifeq's - -TEST_PREFIX ?= ${DUT_TOP} - -ifeq (${TEST_NAME},${TEST_PREFIX}_csr_hw_reset) - UVM_TEST_SEQ = ${TEST_PREFIX}_common_vseq - RUN_OPTS += +csr_hw_reset - RUN_OPTS += +en_scb=0 -endif - -ifeq (${TEST_NAME},${TEST_PREFIX}_csr_rw) - UVM_TEST_SEQ = ${TEST_PREFIX}_common_vseq - RUN_OPTS += +csr_rw - RUN_OPTS += +en_scb=0 -endif - -ifeq (${TEST_NAME},${TEST_PREFIX}_csr_bit_bash) - UVM_TEST_SEQ = ${TEST_PREFIX}_common_vseq - RUN_OPTS += +csr_bit_bash - RUN_OPTS += +en_scb=0 -endif - -ifeq (${TEST_NAME},${TEST_PREFIX}_csr_aliasing) - UVM_TEST_SEQ = ${TEST_PREFIX}_common_vseq - RUN_OPTS += +csr_aliasing - RUN_OPTS += +en_scb=0 -endif - -ifeq (${TEST_NAME},${TEST_PREFIX}_same_csr_outstanding) - UVM_TEST_SEQ = ${TEST_PREFIX}_common_vseq - RUN_OPTS += +run_same_csr_outstanding - RUN_OPTS += +en_scb=0 -endif - -# make sure DUT has memory and support this seq before run the test -ifeq (${TEST_NAME},${TEST_PREFIX}_csr_mem_walk) - UVM_TEST_SEQ = ${TEST_PREFIX}_common_vseq - RUN_OPTS += +csr_mem_walk - RUN_OPTS += +en_scb=0 -endif - -ifeq (${TEST_NAME},${TEST_PREFIX}_tl_errors) - UVM_TEST_SEQ = ${TEST_PREFIX}_common_vseq - RUN_OPTS += +run_tl_errors -endif - -ifeq (${TEST_NAME},${TEST_PREFIX}_intr_test) - UVM_TEST_SEQ = ${TEST_PREFIX}_common_vseq - RUN_OPTS += +run_intr_test -endif - -ifeq (${TEST_NAME},${TEST_PREFIX}_stress_all_with_rand_reset) - UVM_TEST_SEQ = ${TEST_PREFIX}_common_vseq - RUN_OPTS += +run_stress_all_with_rand_reset - // 10ms - RUN_OPTS += +test_timeout_ns=10000000000 - RUN_OPTS += +stress_seq=${TEST_PREFIX}_stress_all_vseq -endif - - diff --git a/vendor/lowrisc_ip/dv/data/common_modes.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/common_modes.hjson similarity index 100% rename from vendor/lowrisc_ip/dv/data/common_modes.hjson rename to vendor/lowrisc_ip/dv/tools/dvsim/common_modes.hjson diff --git a/vendor/lowrisc_ip/dv/data/common_sim_cfg.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/common_sim_cfg.hjson similarity index 71% rename from vendor/lowrisc_ip/dv/data/common_sim_cfg.hjson rename to vendor/lowrisc_ip/dv/tools/dvsim/common_sim_cfg.hjson index aaaeb3ac24..a3ad1e9923 100644 --- a/vendor/lowrisc_ip/dv/data/common_sim_cfg.hjson +++ b/vendor/lowrisc_ip/dv/tools/dvsim/common_sim_cfg.hjson @@ -6,12 +6,12 @@ dv_root: "{proj_root}/vendor/lowrisc_ip/dv" flow: sim - flow_makefile: "{dv_root}/data/sim.mk" + flow_makefile: "{dv_root}/tools/dvsim/sim.mk" import_cfgs: ["{proj_root}/dv/uvm/common_project_cfg.hjson", - "{dv_root}/data/common_modes.hjson", - "{dv_root}/data/fusesoc.hjson", - "{dv_root}/data/{tool}/{tool}.hjson"] + "{dv_root}/tools/dvsim/common_modes.hjson", + "{dv_root}/tools/dvsim/fusesoc.hjson", + "{dv_root}/tools/dvsim/{tool}.hjson"] // Default directory structure for the output build_dir: "{scratch_path}/{build_mode}" @@ -37,11 +37,15 @@ tl_dbw: 4 // Default UVM verbosity settings - n: UVM_NONE - l: UVM_LOW - m: UVM_MEDIUM - h: UVM_HIGH - d: UVM_DEBUG + expand_uvm_verbosity_n: UVM_NONE + expand_uvm_verbosity_l: UVM_LOW + expand_uvm_verbosity_m: UVM_MEDIUM + expand_uvm_verbosity_h: UVM_HIGH + expand_uvm_verbosity_d: UVM_DEBUG + + // Default simulation verbosity (l => UVM_LOW). Can be overridden by + // the --verbosity command-line argument. + verbosity: l // Path to the dut instance (this is used in a couple of places such as coverage cfg // file, xprop cfg file etc. If this is different for your block, then override it with @@ -63,43 +67,38 @@ "+define+UVM_REG_BYTENABLE_WIDTH={tl_dbw}"] run_opts: ["+UVM_NO_RELNOTES", - "+UVM_VERBOSITY={verbosity}"] + "+UVM_VERBOSITY={expand_uvm_verbosity_{verbosity}}"] // Default list of things to export to shell exports: [ - TOOL_SRCS_DIR: {tool_srcs_dir} - EN_WAVES: {waves} - DUMP_FMT: {dump_fmt} - DUT_TOP: {dut} - TB_TOP: {tb} - dut_instance: {dut_instance} + { TOOL_SRCS_DIR: "{tool_srcs_dir}" }, + { SIMULATOR: "{tool}" }, + { WAVES: "{waves}" }, + { DUT_TOP: "{dut}" }, + { TB_TOP: "{tb}" }, + { dut_instance: "{dut_instance}" } ] // Build modes are collection of build_opts and run_opts - // A test can enable a specific build mode by setting 'use_build_mode' key - build_modes: [ - { - name: foo - build_opts: ["+define+bx", - "+define+by", - "+define+bz"] - run_opts: ["+rx=1", - "+ry=2", - "+rz=3"] - } - { - name: bar - build_opts: ["+define+bbaru1", - "+define+bbaru2", - "+define+bbaru3"] - run_opts: ["+rbar1u=1", - "+rbar2u=2", - "+rbar3u=3"] - } - { - name: cover_reg_top - } - ] + // + // To define a build mode that overrides these flags, add something + // like the following to the IP block's configuration: + // + // build_modes: [ + // { + // name: foo + // build_opts: ["+define+bx", + // "+define+by", + // "+define+bz"] + // run_opts: ["+rx=1", + // "+ry=2", + // "+rz=3"] + // } + // ] + // + // To use a build mode for a specific test, set the 'use_build_mode' key. + // + build_modes: [] // Regressions are tests that can be grouped together and run in one shot // By default, two regressions are made available - "all" and "nightly". Both @@ -110,7 +109,7 @@ // tests. regressions: [ { - name: sanity + name: smoke tests: [] reseed: 1 } @@ -133,7 +132,9 @@ // Add waves.tcl to the set of sources to be copied over to // {tool_srcs_dir}. This can be sourced by the tool-specific TCL // script to set up wave dumping. - tool_srcs: ["{dv_root}/tools/waves.tcl"], + tool_srcs: ["{dv_root}/tools/sim.tcl", + "{dv_root}/tools/common.tcl", + "{dv_root}/tools/waves.tcl"] // Project defaults for VCS vcs_cov_cfg_file: "{{build_mode}_vcs_cov_cfg_file}" diff --git a/vendor/lowrisc_ip/dv/data/dsim/dsim.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/dsim.hjson similarity index 78% rename from vendor/lowrisc_ip/dv/data/dsim/dsim.hjson rename to vendor/lowrisc_ip/dv/tools/dvsim/dsim.hjson index 54fb0a6fee..f5a61a36b9 100644 --- a/vendor/lowrisc_ip/dv/data/dsim/dsim.hjson +++ b/vendor/lowrisc_ip/dv/tools/dvsim/dsim.hjson @@ -5,8 +5,13 @@ build_cmd: "{job_prefix} dsim" run_cmd: "{job_prefix} dsim" - build_opts: [ - "-work {build_dir}/dsim_out", + // Indicate the tool specific helper sources - these are copied over to the + // {tool_srcs_dir} before running the simulation. + // TODO, there is no dsim tool file, point to vcs for now to avoid error from script + // tool_srcs: ["{dv_root}/tools/dsim/*"] + + + build_opts: ["-work {build_dir}/dsim_out", "-genimage image", "-sv", // Set parallel compilation jobs limit @@ -21,24 +26,23 @@ "+incdir+{build_dir}", // Suppress following DSim errors and warnings: // EnumMustBePositive - UVM 1.2 violates this - "-suppress EnumMustBePositive" - ] + "-suppress EnumMustBePositive"] - run_opts: [ - "-work {build_dir}/dsim_out", + run_opts: ["-work {build_dir}/dsim_out", "-image image", // UVM DPI "-sv_lib {DSIM_HOME}/lib/libuvm_dpi.so", "-sv_seed {seed}", - // tell DSim to write line-buffered std output (lines will be written in proper order) + // tell DSim to write line-buffered stdout (lines will be written in proper order) "-linebuf", "+UVM_TESTNAME={uvm_test}", "+UVM_TEST_SEQ={uvm_test_seq}"] - // Indicate the tool specific helper sources - these are copied over to the - // {tool_srcs_dir} before running the simulation. - // TODO, there is no dsim tool file, point to vcs for now to avoid error from script - tool_srcs: ["{dv_root}/tools/vcs/*"] + // Supported wave dumping formats (in order of preference). + supported_wave_formats: ["vcd", "fst"] + + // Default tcl script used when running the sim. Override if needed. + run_script: "" // TODO: refactor coverage configuration for DSim. @@ -56,13 +60,12 @@ cov_merge_dir: "{scratch_base_path}/cov_merge" cov_merge_db_dir: "{cov_merge_dir}/merged.vdb" cov_merge_cmd: "{job_prefix} urg" - cov_merge_opts: [ - ] + cov_merge_opts: [] + // Generate coverage reports in text as well as html. cov_report_dir: "{scratch_base_path}/cov_report" cov_report_cmd: "{job_prefix} urg" - cov_report_opts: [ - ] + cov_report_opts: [] cov_report_txt: "{cov_report_dir}/dashboard.txt" cov_report_page: "dashboard.html" @@ -72,40 +75,36 @@ cov_analyze_cmd: "{job_prefix} verdi" cov_analyze_opts: ["-cov", "-covdir {cov_merge_db_dir}", - "-line nocasedef" + "-line nocasedef", "-elfile {vcs_cov_excl_files}"] // Vars that need to exported to the env. exports: [ + { PATH: "{DSIM_HOME}:{PATH}" } + { LD_LIBRARY_PATH: "{DSIM_HOME}/lib:{DSIM_HOME}/system_lib:{LD_LIBRARY_PATH}" } ] // Defaults for DSim // TODO: there is currently no equivalent of "all" coverage metrics in DSim - cov_metrics: "" + cov_metrics: "" // pass and fail patterns build_fail_patterns: ["^Error-.*$"] run_fail_patterns: ["^Error-.*$"] // Null pointer error // waveform - wave_type: "vcd" - wave_file: "dsim_wave.{wave_type}" - probe_file: "dsim.probe" + probe_file: "dsim.probe" build_modes: [ { name: dsim_waves is_sim_mode: 1 - build_opts: [ - "+acc+b" - ] - run_opts: [ - "-waves {wave_file}", - // dsim.probe is currently undefined - //"-wave-scope-specs {probe_file}", - // Dump unpacked structs and arrays. - "-dump-agg" - ] + build_opts: ["+acc+b"] + run_opts: ["-waves waves.{waves}", + // dsim.probe is currently undefined + //"-wave-scope-specs {probe_file}", + // Dump unpacked structs and arrays. + "-dump-agg"] } // TODO: support coverage mode // Note: no specific build or run options are required for dsim to produce functional diff --git a/vendor/lowrisc_ip/dv/data/fusesoc.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/fusesoc.hjson similarity index 100% rename from vendor/lowrisc_ip/dv/data/fusesoc.hjson rename to vendor/lowrisc_ip/dv/tools/dvsim/fusesoc.hjson diff --git a/vendor/lowrisc_ip/dv/data/riviera/riviera.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/riviera.hjson similarity index 88% rename from vendor/lowrisc_ip/dv/data/riviera/riviera.hjson rename to vendor/lowrisc_ip/dv/tools/dvsim/riviera.hjson index e862897496..6be02dcd49 100644 --- a/vendor/lowrisc_ip/dv/data/riviera/riviera.hjson +++ b/vendor/lowrisc_ip/dv/tools/dvsim/riviera.hjson @@ -7,7 +7,7 @@ // Indicate the tool specific helper sources - these are copied over to the // {tool_srcs_dir} before running the simulation. - tool_srcs: ["{proj_root}/dv/uvm/data/riviera/*"] + tool_srcs: ["{dv_root}/tools/riviera/*"] build_opts: ["-sv", "-timescale 1ns/1ps", @@ -20,7 +20,14 @@ "-lib {sv_flist_gen_dir}/work", "+UVM_TESTNAME={uvm_test}", "+UVM_TEST_SEQ={uvm_test_seq}", - "-do {tool_srcs_dir}/riviera_run.do"] + "-do {run_script}"] + + + // Supported wave dumping formats (in order of preference). + supported_wave_formats: [] + + // Default tcl script used when running the sim. Override if needed. + run_script: "{tool_srcs_dir}/riviera_run.do" // Coverage related. // TODO: These options have to be filled in. diff --git a/vendor/lowrisc_ip/dv/data/sim.mk b/vendor/lowrisc_ip/dv/tools/dvsim/sim.mk similarity index 79% rename from vendor/lowrisc_ip/dv/data/sim.mk rename to vendor/lowrisc_ip/dv/tools/dvsim/sim.mk index 72d111a4aa..702f3e6ff8 100644 --- a/vendor/lowrisc_ip/dv/data/sim.mk +++ b/vendor/lowrisc_ip/dv/tools/dvsim/sim.mk @@ -19,11 +19,11 @@ prep_tool_srcs: mkdir -p ${tool_srcs_dir} ${LOCK_TOOL_SRCS_DIR} "cp -Ru ${tool_srcs} ${tool_srcs_dir}/." -pre_compile: +pre_compile: prep_tool_srcs @echo "[make]: pre_compile" mkdir -p ${build_dir} -gen_sv_flist: pre_compile prep_tool_srcs +gen_sv_flist: pre_compile @echo "[make]: gen_sv_flist" cd ${build_dir} && ${sv_flist_gen_cmd} ${sv_flist_gen_opts} @@ -39,7 +39,7 @@ compile_result: post_compile run: run_result -pre_run: +pre_run: prep_tool_srcs @echo "[make]: pre_run" mkdir -p ${run_dir} ifneq (${sw_test},) @@ -62,11 +62,13 @@ ifneq (${sw_test},) -n "rom" -o "${run_dir}" # Copy over the boot rom image to the run_dir. cp ${sw_build_dir}/build-out/sw/device/boot_rom/boot_rom_${sw_build_device}.32.vmem \ - ${run_dir}/rom.32.vmem + ${run_dir}/rom.vmem + cp ${sw_build_dir}/build-out/sw/device/boot_rom/boot_rom_${sw_build_device}.elf \ + ${run_dir}/rom.elf ifeq (${sw_test_is_prebuilt},1) # Copy over the sw test image and related sources to the run_dir. - cp ${proj_root}/${sw_test}.64.vmem ${run_dir}/sw.64.vmem + cp ${proj_root}/${sw_test}.64.vmem ${run_dir}/sw.vmem # Optionally, assume that ${sw_test}_logs.txt exists and copy over to the run_dir. # Ignore copy error if it actually doesn't exist. Likewise for ${sw_test}_rodata.txt. -cp ${proj_root}/${sw_test}_logs.txt ${run_dir}/sw_logs.txt @@ -76,14 +78,23 @@ else # Compile the sw test code and generate the image. ${LOCK_SW_BUILD} "ninja -C ${sw_build_dir}/build-out \ ${sw_test}_export_${sw_build_device}" + # Convert sw image to frame format + # TODO only needed for loading sw image through SPI. Can enhance this later + ${LOCK_SW_BUILD} "ninja -C ${sw_build_dir}/build-out sw/host/spiflash/spiflash_export" + ${LOCK_SW_BUILD} "${sw_build_dir}/build-bin/sw/host/spiflash/spiflash --input \ + ${sw_build_dir}/build-bin/${sw_test}_${sw_build_device}.bin \ + --dump-frames=${run_dir}/sw.frames.bin" + ${LOCK_SW_BUILD} "srec_cat ${run_dir}/sw.frames.bin --binary \ + --offset 0x0 --byte-swap 4 --fill 0xff -within ${run_dir}/sw.frames.bin -binary -range-pad 4 \ + --output ${run_dir}/sw.frames.vmem --vmem" # Extract the sw test logs. ${proj_root}/util/device_sw_utils/extract_sw_logs.py \ -e "${sw_build_dir}/build-out/${sw_test}_${sw_build_device}.elf" \ -f .logs.fields -r .rodata \ -n "sw" -o "${run_dir}" # Copy over the sw test image to the run_dir. - cp ${sw_build_dir}/build-out/${sw_test}_${sw_build_device}.64.vmem \ - ${run_dir}/sw.64.vmem + cp ${sw_build_dir}/build-out/${sw_test}_${sw_build_device}.64.vmem ${run_dir}/sw.vmem + cp ${sw_build_dir}/build-out/${sw_test}_${sw_build_device}.elf ${run_dir}/sw.elf endif endif diff --git a/vendor/lowrisc_ip/dv/tools/testplans/csr_testplan.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/testplans/csr_testplan.hjson similarity index 100% rename from vendor/lowrisc_ip/dv/tools/testplans/csr_testplan.hjson rename to vendor/lowrisc_ip/dv/tools/dvsim/testplans/csr_testplan.hjson diff --git a/vendor/lowrisc_ip/dv/tools/testplans/enable_reg_testplan.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/testplans/enable_reg_testplan.hjson similarity index 100% rename from vendor/lowrisc_ip/dv/tools/testplans/enable_reg_testplan.hjson rename to vendor/lowrisc_ip/dv/tools/dvsim/testplans/enable_reg_testplan.hjson diff --git a/vendor/lowrisc_ip/dv/tools/testplans/fpv_csr_testplan.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/testplans/fpv_csr_testplan.hjson similarity index 100% rename from vendor/lowrisc_ip/dv/tools/testplans/fpv_csr_testplan.hjson rename to vendor/lowrisc_ip/dv/tools/dvsim/testplans/fpv_csr_testplan.hjson diff --git a/vendor/lowrisc_ip/dv/tools/testplans/intr_test_testplan.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/testplans/intr_test_testplan.hjson similarity index 100% rename from vendor/lowrisc_ip/dv/tools/testplans/intr_test_testplan.hjson rename to vendor/lowrisc_ip/dv/tools/dvsim/testplans/intr_test_testplan.hjson diff --git a/vendor/lowrisc_ip/dv/tools/testplans/mem_testplan.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/testplans/mem_testplan.hjson similarity index 100% rename from vendor/lowrisc_ip/dv/tools/testplans/mem_testplan.hjson rename to vendor/lowrisc_ip/dv/tools/dvsim/testplans/mem_testplan.hjson diff --git a/vendor/lowrisc_ip/dv/tools/testplans/shadow_reg_errors_testplan.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/testplans/shadow_reg_errors_testplan.hjson similarity index 100% rename from vendor/lowrisc_ip/dv/tools/testplans/shadow_reg_errors_testplan.hjson rename to vendor/lowrisc_ip/dv/tools/dvsim/testplans/shadow_reg_errors_testplan.hjson diff --git a/vendor/lowrisc_ip/dv/tools/testplans/stress_all_with_reset_testplan.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/testplans/stress_all_with_reset_testplan.hjson similarity index 100% rename from vendor/lowrisc_ip/dv/tools/testplans/stress_all_with_reset_testplan.hjson rename to vendor/lowrisc_ip/dv/tools/dvsim/testplans/stress_all_with_reset_testplan.hjson diff --git a/vendor/lowrisc_ip/dv/tools/dvsim/testplans/tl_device_access_types_testplan.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/testplans/tl_device_access_types_testplan.hjson new file mode 100644 index 0000000000..4e78edaef3 --- /dev/null +++ b/vendor/lowrisc_ip/dv/tools/dvsim/testplans/tl_device_access_types_testplan.hjson @@ -0,0 +1,57 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +{ + entries: [ + { + name: tl_d_oob_addr_access + desc: "Access out of bounds address and verify correctness of response / behavior" + milestone: V2 + tests: ["{name}_tl_errors"] + } + { + name: tl_d_illegal_access + desc: '''Drive unsupported requests via TL interface and verify correctness of response + / behavior. Below error cases are tested + - TL-UL protocol error cases + - Unsupported opcode. e.g a_opcode isn't Get, PutPartialData or PutFullData + - Mask isn't all active if opcode = PutFullData + - Mask isn't in enabled lanes, e.g. a_address = 0x00, a_size = 0, a_mask = 'b0010 + - Mask doesn't align with address, e.g. a_address = 0x01, a_mask = 'b0001 + - Address and size aren't aligned, e.g. a_address = 0x01, a_size != 0 + - Size is over 2. + - OpenTitan defined error cases + - Access unmapped address, return d_error = 1 when devmode_i == 1 + - Write CSR with unaligned address, e.g. a_address[1:0] != 0 + - Write CSR less than its width, e.g. when CSR is 2 bytes wide, only write 1 byte + - Write a memory without enabling all lanes (a_mask = '1) if memory doesn't support + byte enabled write + - Read a WO (write-only) memory''' + milestone: V2 + tests: ["{name}_tl_errors"] + } + { + name: tl_d_outstanding_access + desc: '''Drive back-to-back requests without waiting for response to ensure there is one + transaction outstanding within the TL device. Also, verify one outstanding when back- + to-back accesses are made to the same address.''' + milestone: V2 + tests: ["{name}_csr_hw_reset", + "{name}_csr_rw", + "{name}_csr_aliasing", + "{name}_same_csr_outstanding"] + } + { + name: tl_d_partial_access + desc: '''Access CSR with one or more bytes of data + For read, expect to return all word value of the CSR + For write, enabling bytes should cover all CSR valid fields''' + milestone: V2 + tests: ["{name}_csr_hw_reset", + "{name}_csr_rw", + "{name}_csr_aliasing", + "{name}_same_csr_outstanding"] + } + ] +} + diff --git a/vendor/lowrisc_ip/dv/data/tests/csr_tests.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/tests/csr_tests.hjson similarity index 98% rename from vendor/lowrisc_ip/dv/data/tests/csr_tests.hjson rename to vendor/lowrisc_ip/dv/tools/dvsim/tests/csr_tests.hjson index b936ed5740..93e6e01047 100644 --- a/vendor/lowrisc_ip/dv/data/tests/csr_tests.hjson +++ b/vendor/lowrisc_ip/dv/tools/dvsim/tests/csr_tests.hjson @@ -62,7 +62,7 @@ regressions: [ { - name: sanity + name: smoke tests: ["{name}_csr_hw_reset", "{name}_csr_rw"] } diff --git a/vendor/lowrisc_ip/dv/data/tests/intr_test.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/tests/intr_test.hjson similarity index 100% rename from vendor/lowrisc_ip/dv/data/tests/intr_test.hjson rename to vendor/lowrisc_ip/dv/tools/dvsim/tests/intr_test.hjson diff --git a/vendor/lowrisc_ip/dv/data/tests/mem_tests.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/tests/mem_tests.hjson similarity index 100% rename from vendor/lowrisc_ip/dv/data/tests/mem_tests.hjson rename to vendor/lowrisc_ip/dv/tools/dvsim/tests/mem_tests.hjson diff --git a/vendor/lowrisc_ip/dv/data/tests/shadow_reg_errors_tests.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/tests/shadow_reg_errors_tests.hjson similarity index 100% rename from vendor/lowrisc_ip/dv/data/tests/shadow_reg_errors_tests.hjson rename to vendor/lowrisc_ip/dv/tools/dvsim/tests/shadow_reg_errors_tests.hjson diff --git a/vendor/lowrisc_ip/dv/data/tests/stress_tests.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/tests/stress_tests.hjson similarity index 100% rename from vendor/lowrisc_ip/dv/data/tests/stress_tests.hjson rename to vendor/lowrisc_ip/dv/tools/dvsim/tests/stress_tests.hjson diff --git a/vendor/lowrisc_ip/dv/data/tests/tl_access_tests.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/tests/tl_access_tests.hjson similarity index 100% rename from vendor/lowrisc_ip/dv/data/tests/tl_access_tests.hjson rename to vendor/lowrisc_ip/dv/tools/dvsim/tests/tl_access_tests.hjson diff --git a/vendor/lowrisc_ip/dv/data/vcs/vcs.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/vcs.hjson similarity index 70% rename from vendor/lowrisc_ip/dv/data/vcs/vcs.hjson rename to vendor/lowrisc_ip/dv/tools/dvsim/vcs.hjson index 4ec6397fef..812eae844d 100644 --- a/vendor/lowrisc_ip/dv/data/vcs/vcs.hjson +++ b/vendor/lowrisc_ip/dv/tools/dvsim/vcs.hjson @@ -25,22 +25,74 @@ // and final value of the selection input at the end of a simulation timestep. // See https://github.com/lowRISC/ibex/issues/845. "-xlrm uniq_prior_final", - // Force DPI-C compilation in C99 mode - "-CFLAGS \"--std=c99\"", + // Force DPI-C compilation in C99 mode. The -fno-extended-identifiers flag tells g++ + // not to worry about unicode. For some bizarre reason, the VCS DPI code contains + // preprocessor macros with smart quotes, which causes GCC 10.2 and later to choke + // otherwise. The double-escaped quotes are because this needs to go inside a string + // that gets passed to Make (stripping one level of quotes), and then needs to + // result in an argument with an embedded space (the other one). + "-CFLAGS \\\"--std=c99 -fno-extended-identifiers\\\"", + // C++11 standard is enforced for all sources, including the DPI-C constructs. + // TODO, may need to update to c++14 to meet our requirements + // Refer to https://docs.opentitan.org/doc/ug/install_instructions + "-CFLAGS --std=c++11", // Without this magic LDFLAGS argument below, we get compile time errors with // VCS on Google Linux machines that look like this: // .../libvcsnew.so: undefined reference to `snpsReallocFunc' // .../libvcsnew.so: undefined reference to `snpsCheckStrdupFunc' // .../libvcsnew.so: undefined reference to `snpsGetMemBytes' - "-LDFLAGS \"-Wl,--no-as-needed\"", + "-LDFLAGS -Wl,--no-as-needed", // This option enables the following: (needed for uvm_hdl_*) // - Read capability on registers, variables, and nets // - Write (deposit) capability on registers and variables // - Force capability on registers, variables, and nets - "-debug_access+f"] + "-debug_access+f", + // Use this to conditionally compile for VCS (example: LRM interpretations differ + // across tools). + "+define+VCS", + // Upgrade below warnings to errors to make VCS more strict on syntax to avoid + // having issue with other simulators but passing with VCS + // + // Identifier previously declared + "-error=IPDW", + // Input Supply Port with no driver + "-error=UPF_ISPND", + // Invalid generic or parameter assignment + "-error=IGPA", + // Class scope used outside of class + "-error=PCSRMIO", + // Attempt to override undefined parameter + "-error=AOUP", + // Unbound component + "-error=ELW_UNBOUND", + // Illegal Use of Wildcard Index + "-error=IUWI", + // Index into non-array variable + "-error=INAV", + // Illegal Static Cast + "-error=SV-ISC", + // Obsolete System Verilog feature + "-error=OSVF-NPVIUFPI", + // Duplicate port in module instantiation + "-error=DPIMI", + // Identifier in ANSI port declaration + "-error=IPDASP", + // File not found + "-error=CM-HIER-FNF", + // Concatenations with unsized constants + "-error=CWUC", + // More arguments than needed + "-error=MATN", + // Specifying negative delays is invalid + "-error=STASKW_NDTAZ1", + // Too many parameter overrides + "-error=TMPO", + // Class objects must not hide other class members due to same name + "-error=SV-OHCM", + ] run_opts: ["-licqueue", - "-ucli -do {tool_srcs_dir}/vcs.tcl", + "-ucli -do {run_script}", "+ntb_random_seed={seed}", // Disable the display of the SystemVerilog assert and cover statement summary // at the end of simulation. This summary is list of assertions that started but @@ -51,6 +103,12 @@ "+UVM_TESTNAME={uvm_test}", "+UVM_TEST_SEQ={uvm_test_seq}"] + // Supported wave dumping formats (in order of preference). + supported_wave_formats: ["fsdb", "vpd"] + + // Default tcl script used when running the sim. Override if needed. + run_script: "{tool_srcs_dir}/sim.tcl" + // Coverage related. cov_db_dir: "{scratch_path}/coverage/{build_mode}.vdb" @@ -105,8 +163,8 @@ // Vars that need to exported to the env. exports: [ - VCS_ARCH_OVERRIDE: linux - VCS_LIC_EXPIRE_WARNING: 1 + { VCS_ARCH_OVERRIDE: "linux" }, + { VCS_LIC_EXPIRE_WARNING: 1 } ] // Defaults for VCS diff --git a/vendor/lowrisc_ip/dv/data/xcelium/xcelium.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/xcelium.hjson similarity index 80% rename from vendor/lowrisc_ip/dv/data/xcelium/xcelium.hjson rename to vendor/lowrisc_ip/dv/tools/dvsim/xcelium.hjson index a816192644..b859f816c8 100644 --- a/vendor/lowrisc_ip/dv/data/xcelium/xcelium.hjson +++ b/vendor/lowrisc_ip/dv/tools/dvsim/xcelium.hjson @@ -20,33 +20,51 @@ "-xmlibdirname {build_dir}/xcelium.d", // for uvm_hdl_* used by csr backdoor "-access +rw", + // Use this to conditionally compile for Xcelium (example: LRM interpretations differ + // across tools). "+define+XCELIUM", + // Ignore "timescale is not specified for the package" warning + "-nowarn TSNSPK", + // Ignore "IEEE 1800-2009 SystemVerilog simulation semantics" warning + "-nowarn DSEMEL", + // Ignore hierarchial ref warnings in interfaces + "-nowarn CUVIHR", ] - run_opts: ["-input {tool_srcs_dir}/xcelium.tcl", + run_opts: ["-input {run_script}", "-licqueue", "-64bit -xmlibdirname {build_dir}/xcelium.d -R", "+SVSEED={seed}", "+UVM_TESTNAME={uvm_test}", - "+UVM_TEST_SEQ={uvm_test_seq}"] + "+UVM_TEST_SEQ={uvm_test_seq}", + // Ignore "IEEE 1800-2009 SystemVerilog simulation semantics" warning + "-nowarn DSEM2009", + ] // Vars that need to exported to the env. exports: [ // Poll for an available license in all servers. - CDS_LIC_QUEUE_POLL: 1 + { CDS_LIC_QUEUE_POLL: 1 }, + // Poll for an available license every 1 min. - CDS_LIC_QUEUE_POLL_INT: 60 + { CDS_LIC_QUEUE_POLL_INT: 60 }, // X-prop related: these were suggested by Xcelium as warnings during the build time. // These enable array corruption when the index is out of range or invalid. - VL_ENABLE_INVALID_IDX_XPROP: 1 - VL_ENABLE_OUTOFRANGE_IDX_XPROP: 1 + { VL_ENABLE_INVALID_IDX_XPROP: 1 }, + { VL_ENABLE_OUTOFRANGE_IDX_XPROP: 1 }, // Export the cov_report path so that the tcl file can read these as env vars. - cov_merge_db_dir: "{cov_merge_db_dir}" - cov_report_dir: "{cov_report_dir}" + { cov_merge_db_dir: "{cov_merge_db_dir}" }, + { cov_report_dir: "{cov_report_dir}" } ] + // Supported wave dumping formats (in order of preference). + supported_wave_formats: ["shm", "fsdb", "vcd"] + + // Default tcl script used when running the sim. Override if needed. + run_script: "{tool_srcs_dir}/sim.tcl" + // Coverage related. // By default, collect all coverage metrics: block:expr:fsm:toggle:functional. cov_metrics: all @@ -57,7 +75,7 @@ // Supply the cov refinement files. // Note that this needs to be set as -load_refinement . - xcelium_cov_refine_files: [""] + xcelium_cov_refine_files: [] // Set the coverage directories. cov_work_dir: "{scratch_path}/coverage" diff --git a/vendor/lowrisc_ip/dv/tools/fail_patterns b/vendor/lowrisc_ip/dv/tools/fail_patterns deleted file mode 100644 index 298ab7ed88..0000000000 --- a/vendor/lowrisc_ip/dv/tools/fail_patterns +++ /dev/null @@ -1,3 +0,0 @@ -^TEST FAILED (UVM_)?CHECKS$ -^UVM_ERROR\s[^:].*$ -^\s*Offending '.*' diff --git a/vendor/lowrisc_ip/dv/tools/fusesoc.mk b/vendor/lowrisc_ip/dv/tools/fusesoc.mk deleted file mode 100644 index 85bc44b364..0000000000 --- a/vendor/lowrisc_ip/dv/tools/fusesoc.mk +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright lowRISC contributors. -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 -# Make variables specific to FUSESOC tool used for generating the filelist -# The following Make variables are to be set in the Test Makefile -# FUSESOC_CORE: the top level fusesoc core file developed for the ip/top level testbench -# see hw/ip/uart/dv/uart_sim.core as an example -# Rest of the Make variables added here are intermeditiate ones used in the flow - -# fusesoc tool and options -SV_FLIST_GEN_TOOL ?= fusesoc -SV_FLIST_GEN_OPTS += --cores-root ${PROJ_ROOT} --cores-root ${RAL_MODEL_DIR} \ - run --target=sim --setup ${FUSESOC_CORE} -FUSESOC_CORE_ = $(shell echo "${FUSESOC_CORE}" | tr ':' '_') -SV_FLIST_GEN_DIR = ${BUILD_DIR}/build/${FUSESOC_CORE_}/sim-vcs -SV_FLIST := ${SV_FLIST_GEN_DIR}/${FUSESOC_CORE_}.scr diff --git a/vendor/lowrisc_ip/dv/tools/modes.mk b/vendor/lowrisc_ip/dv/tools/modes.mk deleted file mode 100644 index 3c187b7fb3..0000000000 --- a/vendor/lowrisc_ip/dv/tools/modes.mk +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright lowRISC contributors. -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 -# Makefile option groups that can be enabled by test Makefile / command line. -# These are generic set of option groups that apply to all testbenches. -# These are meant to be simulator agnostic -# Please add tool specific options with appropriate ifeq's - -# Distinguish UVM TB and the other environments for Verilator, FPGA etc -BUILD_OPTS += +define+UVM -# uvm specific - set default widths -BUILD_OPTS += +define+UVM_NO_DEPRECATED -BUILD_OPTS += +define+UVM_REGEX_NO_DPI -BUILD_OPTS += +define+UVM_REG_ADDR_WIDTH=${TL_AW} -BUILD_OPTS += +define+UVM_REG_DATA_WIDTH=${TL_DW} -BUILD_OPTS += +define+UVM_REG_BYTENABLE_WIDTH=${TL_DBW} - -# Enable UVM trace options -UVM_TRACE ?= 0 -ifeq (${UVM_TRACE},1) - RUN_OPTS += +UVM_PHASE_TRACE - RUN_OPTS += +UVM_CONFIG_DB_TRACE - RUN_OPTS += +UVM_OBJECTION_TRACE -endif - -# Options for generating waves / debugging. -WAVES ?= 0 -DUMP ?= fsdb -DUMP_FILE ?= waves.${DUMP} -export WAVES -export DUMP -export DUMP_FILE - -ifeq (${WAVES},1) - ifeq (${SIMULATOR},vcs) - VCS_WAVES = 1 - endif -endif - -# Enable simulation profiling -SIMPROFILE ?= 0 -ifeq (${SIMPROFILE},1) - ifeq (${SIMULATOR},vcs) - VCS_SIMPROFILE = 1 - else ifeq (${SIMULATOR},xcelium) - XCELIUM_SIMPROFILE = 1 - endif -endif - -# Enable coverage -COV ?= 0 -ifeq (${COV},1) - ifeq (${SIMULATOR},vcs) - VCS_COV = 1 - else ifeq (${SIMULATOR},xcelium) - XCELIUM_COV = 1 - endif -endif diff --git a/vendor/lowrisc_ip/dv/tools/pass_fail b/vendor/lowrisc_ip/dv/tools/pass_fail deleted file mode 100644 index ee6b5cff55..0000000000 --- a/vendor/lowrisc_ip/dv/tools/pass_fail +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bash - -# Copyright lowRISC contributors. -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 - -# this script checks for test pass/fail signatures at the end of the test - -usage="Error: usage: $0 [path-to-run-log] [path-to-pass-patterns] [path-to-fail-patterns]"; -# need exactly 1 args (path to the run.log) -if [[ $# -ne 3 || ! -f $1 || ! -f $2 || ! -f $3 ]]; then - echo $usage - exit 1; -fi - -# none of the fail patterns should be present -while ifs= read -r fail_pattern; do - grep_cmd="grep -c -m 1 -E '$fail_pattern' $1"; - fail_pattern_found=$(eval $grep_cmd); - if [[ $fail_pattern_found -ne 0 ]]; then - echo "Fail pattern '$fail_pattern' found" - exit 1 - fi -done < $3 - -# all pass patterns should be present -while ifs= read -r pass_pattern; do - grep_cmd="grep -c -m 1 -E '$pass_pattern' $1"; - pass_pattern_found=$(eval $grep_cmd); - if [[ $pass_pattern_found -eq 0 ]]; then - echo "Pass pattern '$pass_pattern' not found" - exit 1 - fi -done < $2 diff --git a/vendor/lowrisc_ip/dv/tools/pass_patterns b/vendor/lowrisc_ip/dv/tools/pass_patterns deleted file mode 100644 index 4e5b505064..0000000000 --- a/vendor/lowrisc_ip/dv/tools/pass_patterns +++ /dev/null @@ -1 +0,0 @@ -^TEST PASSED (UVM_)?CHECKS$ diff --git a/vendor/lowrisc_ip/dv/data/riviera/riviera_run.do b/vendor/lowrisc_ip/dv/tools/riviera/riviera_run.do similarity index 100% rename from vendor/lowrisc_ip/dv/data/riviera/riviera_run.do rename to vendor/lowrisc_ip/dv/tools/riviera/riviera_run.do diff --git a/vendor/lowrisc_ip/dv/tools/rules.mk b/vendor/lowrisc_ip/dv/tools/rules.mk deleted file mode 100644 index 5736971c98..0000000000 --- a/vendor/lowrisc_ip/dv/tools/rules.mk +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright lowRISC contributors. -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 - -.DEFAULT_GOAL := all - -all: build run - -############################### -## sim build and run targets ## -############################### -build: compile_result - -pre_compile: - mkdir -p ${BUILD_DIR} && \ - env > ${BUILD_DIR}/env_vars - -gen_sv_flist: pre_compile - cd ${BUILD_DIR} && ${SV_FLIST_GEN_TOOL} ${SV_FLIST_GEN_OPTS} - -compile: gen_sv_flist - cd ${SV_FLIST_GEN_DIR} && $(BUILD_JOB_OPTS) ${SIMCC} ${BUILD_OPTS} ${CL_BUILD_OPTS} - -post_compile: compile - -compile_result: post_compile - -run: run_result - -pre_run: - rm -rf ${RUN_PATH}/latest - mkdir -p ${RUN_DIR} - ln -s ${RUN_DIR} ${RUN_PATH}/latest - /bin/bash ${MAKE_ROOT}/run_dir_limiter ${RUN_PATH} ${RUN_DIR_LIMIT} - env > ${RUN_DIR}/env_vars - -sw_build: pre_run -ifneq (${SW_NAME},) - # NOTE: Pass -f, since we're going to be re-building everything every time, - # anyways. - cd $(PROJ_ROOT) && \ - BUILD_ROOT=$(SW_BUILD_DIR) $(PROJ_ROOT)/meson_init.sh -f - # NOTE: We're using the fpga platform for now, because there is no - # such thing as a DV platform yet (nor does any code do anything - # special for DV yet). - ninja -C $(SW_BUILD_DIR)/build-out sw/device/boot_rom/boot_rom_export_$(SW_BUILD_DEVICE) - ninja -C $(SW_BUILD_DIR)/build-out sw/device/$(SW_DIR)/$(SW_NAME)_export_$(SW_BUILD_DEVICE) - - mkdir -p $(SW_BUILD_DIR)/sw $(SW_BUILD_DIR)/rom - cp $(SW_BUILD_DIR)/build-out/sw/device/boot_rom/boot_rom_$(SW_BUILD_DEVICE).vmem \ - $(SW_BUILD_DIR)/rom/rom.vmem - cp $(SW_BUILD_DIR)/build-out/sw/device/$(SW_DIR)/$(SW_NAME)_$(SW_BUILD_DEVICE).vmem \ - $(SW_BUILD_DIR)/sw/sw.vmem -endif - -simulate: sw_build - cd ${RUN_DIR} && $(RUN_JOB_OPTS) ${SIMX} ${RUN_OPTS} ${CL_RUN_OPTS} - -post_run: simulate - -run_result: post_run - /bin/bash ${MAKE_ROOT}/pass_fail ${RUN_LOG} ${MAKE_ROOT}/pass_patterns ${MAKE_ROOT}/fail_patterns - -############################ -## coverage rated targets ## -############################ -cov_merge: - # TODO: add script to merge coverage in scratch scope - -# open coverage tool to review and create report or exclusion file -cov_analyze: - cd ${SCRATCH_PATH} && ${COV_ANALYZE_TOOL} ${COV_ANALYZE_OPTS} - -# generate coverage report directly -cov_report: - cd ${SCRATCH_PATH} && ${COV_REPORT_TOOL} ${COV_REPORT_OPTS} - -clean: - rm -rf ${SCRATCH_PATH}/* - -.PHONY: ral \ - build \ - run \ - reg \ - pre_compile \ - compile \ - post_compile \ - compile_result \ - sw_build \ - pre_run \ - simulate \ - post_run \ - run_result \ - cov_merge \ - cov_analyze \ - cov_report \ - clean diff --git a/vendor/lowrisc_ip/dv/tools/run_dir_limiter b/vendor/lowrisc_ip/dv/tools/run_dir_limiter deleted file mode 100755 index 52d34dd8af..0000000000 --- a/vendor/lowrisc_ip/dv/tools/run_dir_limiter +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash - -# Copyright lowRISC contributors. -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 - -# run_dir_limiter does what the name suggests - often, when tests are run multiple times, the number -# of run directories created might end up getting large. This script finds and deletes N oldest -# directories in a given path P, where P and N are the arguments to this script respedtively - -usage="Error: usage: $0 [path-to-run-dir] [num-run-dir-limit]"; -# need exactly 2 args, 1st needs to be the path and 2nd, a number -if [[ $# -ne 2 || ! -d $1 || ! $2 =~ ^[0-9]+$ ]]; then - echo $usage - exit 1; -fi - -run_dir=$(realpath $1); -find_cmd="find $run_dir -mindepth 1 -maxdepth 1 -type d"; -num_dirs=$($find_cmd | wc -l); -num_rm_dirs=$(($num_dirs - $2)); -if [[ $num_rm_dirs -gt 0 ]]; then - dirs=$($find_cmd -printf '%T+ %p\n' | sort | head -n $num_rm_dirs | awk '{print $2}'); - for dir in $dirs; do - echo "Removing $dir..." - /bin/rm -rf $dir - done -fi diff --git a/vendor/lowrisc_ip/dv/tools/sim.tcl b/vendor/lowrisc_ip/dv/tools/sim.tcl new file mode 100644 index 0000000000..9bad74937c --- /dev/null +++ b/vendor/lowrisc_ip/dv/tools/sim.tcl @@ -0,0 +1,21 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +# Common TCL script invoked at run-time by the simulator. +# VCS syntax: -ucli -do +# Xcelium syntax: -input + +set tool_srcs_dir "" +if {[info exists ::env(TOOL_SRCS_DIR)]} { + set tool_srcs_dir "$::env(TOOL_SRCS_DIR)" +} else { + puts "ERROR: Script run without TOOL_SRCS_DIR environment variable." + quit +} + +source "${tool_srcs_dir}/common.tcl" +source "${tool_srcs_dir}/waves.tcl" + +run +quit diff --git a/vendor/lowrisc_ip/dv/tools/testplans/tl_device_access_types_testplan.hjson b/vendor/lowrisc_ip/dv/tools/testplans/tl_device_access_types_testplan.hjson deleted file mode 100644 index 97c5267ffd..0000000000 --- a/vendor/lowrisc_ip/dv/tools/testplans/tl_device_access_types_testplan.hjson +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 -{ - entries: [ - { - name: oob_addr_access - desc: "Access out of bounds address and verify correctness of response / behavior" - milestone: V2 - tests: ["{name}_tl_errors"] - } - { - name: illegal_access - desc: '''Drive unsupported requests via TL interface and verify correctness of response - / behavior ''' - milestone: V2 - tests: ["{name}_tl_errors"] - } - { - name: outstanding_access - desc: '''Drive back-to-back requests without waiting for response to ensure there is one - transaction outstanding within the TL device. Also, verify one outstanding when back- - to-back accesses are made to the same address.''' - milestone: V2 - tests: ["{name}{intf}_csr_hw_reset", - "{name}{intf}_csr_rw", - "{name}{intf}_csr_aliasing", - "{name}{intf}_same_csr_outstanding"] - } - { - name: partial_access - desc: '''Do partial accesses.''' - milestone: V2 - tests: ["{name}{intf}_csr_hw_reset", - "{name}{intf}_csr_rw", - "{name}{intf}_csr_aliasing"] - } - ] -} - diff --git a/vendor/lowrisc_ip/dv/tools/vcs/vcs.mk b/vendor/lowrisc_ip/dv/tools/vcs/vcs.mk deleted file mode 100644 index 94b6b43b62..0000000000 --- a/vendor/lowrisc_ip/dv/tools/vcs/vcs.mk +++ /dev/null @@ -1,117 +0,0 @@ -# Copyright lowRISC contributors. -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 -# Makefile option groups that can be enabled by test Makefile / command line. -# These are generic set of option groups that apply to all testbenches. -# Simulator too specific options -# Mandatory items to set (these are used by rules.mk): -# SIMCC - Simulator compiler used to build / elaborate the bench -# SIMX - Simulator executable used to run the tests - -SIMCC := vcs -SIMX ?= ${BUILD_DIR}/simv -SIM_SETUP ?= ${MAKE_ROOT}/vcs/vcs.tcl - -# set standard build options -BUILD_OPTS += -sverilog -full64 -licqueue -timescale=1ns/1ps -kdb -BUILD_OPTS += -ntb_opts uvm-1.2 -BUILD_OPTS += -Mdir=${BUILD_DIR}/simv.csrc -BUILD_OPTS += -l ${BUILD_LOG} -BUILD_OPTS += -o ${SIMX} -BUILD_OPTS += -f ${SV_FLIST} -BUILD_OPTS += +incdir+${BUILD_DIR} -BUILD_OPTS += -debug_access+pp -BUILD_OPTS += +warn=noUII-L -# turn on warnings if functions are called with return value ignored -BUILD_OPTS += +warn=SV-NFIVC -# option below is required for $error / $fatal system calls -BUILD_OPTS += -assert svaext -# Force DPI-C compilation in C99 mode -BUILD_OPTS += -CFLAGS "--std=c99" -# Without this magic LDFLAGS argument below, we get compile time errors with -# VCS on Google Linux machines that look like this: -# .../libvcsnew.so: undefined reference to `snpsReallocFunc' -# .../libvcsnew.so: undefined reference to `snpsCheckStrdupFunc' -# .../libvcsnew.so: undefined reference to `snpsGetMemBytes' -BUILD_OPTS += -LDFLAGS "-Wl,--no-as-needed" - -# set standard run options -RUN_OPTS += -licqueue -RUN_OPTS += -ucli -do ${SIM_SETUP} -RUN_OPTS += +ntb_random_seed=${SEED} -RUN_OPTS += +UVM_VERBOSITY=${UVM_VERBOSITY} -RUN_OPTS += +UVM_TESTNAME=${UVM_TEST} -RUN_OPTS += +UVM_TEST_SEQ=${UVM_TEST_SEQ} -RUN_OPTS += -l ${RUN_LOG} - -######################### -## Tool Specific Modes ## -######################### - -# Enable simulation profiling -VCS_SIMPROFILE ?= 0 -ifeq (${VCS_SIMPROFILE},1) - BUILD_OPTS += -simprofile - RUN_OPTS += -simprofile time -endif - -# Enable waves -VCS_WAVES ?= 0 -ifeq (${VCS_WAVES},1) - BUILD_OPTS += -debug_access+all -endif - -# Enable coverage -VCS_COV ?= 0 -ifeq (${VCS_COV},1) - COV_METRICS ?= line+cond+fsm+tgl+branch+assert - BUILD_OPTS += -cm ${COV_METRICS} - CM_HIER ?= ${MAKE_ROOT}/vcs/cover.cfg - # Add -cm_hier switch if ${CM_HIER} file exists - BUILD_OPTS += $(shell if [ -f ${CM_HIER} ]; then echo "-cm_hier ${CM_HIER}"; fi) - # Cover all continuous assignments - BUILD_OPTS += -cm_line contassign - # Dump toggle coverage on mdas, array of structs and on ports only - BUILD_OPTS += -cm_tgl mda+structarr+portsonly - # Ignore initial blocks for coverage - BUILD_OPTS += -cm_report noinitial - # Filter unreachable/statically constant blocks - BUILD_OPTS += -cm_noconst - # Don't count coverage that's coming from zero-time glitches - BUILD_OPTS += -cm_glitch 0 - # Ignore warnings about not applying cm_glitch to path and FSM - BUILD_OPTS += "+warn=noVCM-OPTIGN" - # Coverage database output location - BUILD_OPTS += -cm_dir ${BUILD_DIR}/cov.vdb - - RUN_OPTS += -cm ${COV_METRICS} - # Same directory as build - RUN_OPTS += -cm_dir ${BUILD_DIR}/cov.vdb - # Don't output cm.log which can be quite large - RUN_OPTS += -cm_log /dev/null - # Provide a name to the coverage collected for this test - RUN_OPTS += -cm_name ${TEST_NAME}_${RUN_LOC}_${SEED} - # Don't dump all the coverage assertion attempts at the end of simulation - RUN_OPTS += -assert nopostproc -endif - -# Enable XPROP -XPROP ?= 1 -ifeq (${XPROP},1) - VCS_XPROP_CFG_FILE ?= ${MAKE_ROOT}/vcs/xprop.cfg - BUILD_OPTS += -xprop=${VCS_XPROP_CFG_FILE} -endif - -# Coverage analyze/report options -COV_COMMON_EXCL ?= ${MAKE_ROOT}/vcs/common_cov_excl.el -COV_EXCL += ${COV_COMMON_EXCL} ${COV_DUT_EXCL} -COV_ANALYZE_TOOL ?= verdi -COV_REPORT_TOOL ?= urg -COV_DIR ?= ${BUILD_DIR}/cov.vdb -COV_EXCL_OPTS ?= -line nocasedef -elfile ${COV_EXCL} -COV_ANALYZE_OPTS ?= -cov -covdir ${COV_DIR} ${COV_EXCL_OPTS} -COV_REPORT_OPTS ?= -dir ${COV_DIR} ${COV_EXCL_OPTS} -report ${COV_REPORT_DIR} - -# env variables to be exported for VCS -export VCS_ARCH_OVERRIDE := linux -export VCS_LIC_EXPIRE_WARNING := 1 diff --git a/vendor/lowrisc_ip/dv/tools/vcs/vcs.tcl b/vendor/lowrisc_ip/dv/tools/vcs/vcs.tcl deleted file mode 100644 index aca0eed8c0..0000000000 --- a/vendor/lowrisc_ip/dv/tools/vcs/vcs.tcl +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright lowRISC contributors. -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 - -# TCL file invoked from VCS's simv at run-time using this: -ucli -do - -# Get some environment variables we need. -set en_waves 0 -set tool_srcs_dir "" -if {[info exists ::env(EN_WAVES)]} { - set en_waves "$::env(EN_WAVES)" -} -if {[info exists ::env(TOOL_SRCS_DIR)]} { - set tool_srcs_dir "$::env(TOOL_SRCS_DIR)" -} else { - puts "ERROR: tool script run without TOOL_SRCS_DIR environment variable." - quit -} - -# If wave dumping is enabled, run waves.tcl -if {"$en_waves" == 1} { - source "${tool_srcs_dir}/waves.tcl" -} - -run -quit diff --git a/vendor/lowrisc_ip/dv/tools/vcs/xprop.cfg b/vendor/lowrisc_ip/dv/tools/vcs/xprop.cfg index 552a1849e1..022d2baf09 100644 --- a/vendor/lowrisc_ip/dv/tools/vcs/xprop.cfg +++ b/vendor/lowrisc_ip/dv/tools/vcs/xprop.cfg @@ -1,3 +1,7 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + merge = xmerge; // Turn on xprop for dut only diff --git a/vendor/lowrisc_ip/dv/tools/waves.tcl b/vendor/lowrisc_ip/dv/tools/waves.tcl index 87d64ad94b..23f806a8d7 100644 --- a/vendor/lowrisc_ip/dv/tools/waves.tcl +++ b/vendor/lowrisc_ip/dv/tools/waves.tcl @@ -2,44 +2,157 @@ # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -# -# Generic TCL included by tool-specific scripts when wave dumping is -# enabled. -# -# This is used by all supported simulators, and the driver scripts +# This is sourced by all supported simulators. The driver scripts # (dvsim.py) need to make sure that we don't ask for an unsupported -# dumping format (SHM with VCS, for example). -# +# dumping format (SHM with VCS, for example). The adjoining common.tcl +# must be sourced prior to sourcing this file. + +if {[info proc setDefault] ne "setDefault"} { + puts "ERROR: Please ensure that common.tcl is sourced." + quit +} + +global simulator +global waves +global tb_top + +set wavedump_db "waves.$waves" + +# TODO: convert this to a proc? +switch $waves { + "none" { + puts "INFO: Dumping waves is not enabled." + } -set dump_fmt none -if {[info exists ::env(DUMP_FMT)]} { - set dump_fmt "$::env(DUMP_FMT)" -} else { - puts "ERROR: No DUMP_FMT specified for wave dumping." + "fsdb" { + if {$simulator eq "xcelium"} { + call fsdbDumpfile $wavedump_db + } else { + fsdbDumpfile $wavedump_db + } + } + + "shm" { + checkEq simulator "xcelium" + database -open $wavedump_db -default -shm + } + + "vpd" { + checkEq simulator "vcs" + dump -file $wavedump_db -type VPD + } + + "vcd" { + if {$simulator eq "xcelium"} { + database -open $wavedump_db -default -vcd + } else { + puts "ERROR: Simulator $simulator does not support dumping waves in VCD." + quit + } + } + + "evcd" { + if {$simulator eq "xcelium"} { + database -open $wavedump_db -default -evcd + } else { + puts "ERROR: Simulator $simulator does not support dumping waves in EVCD." + quit + } + } + + default { + puts "ERROR: Unknown wave format: ${waves}." quit + } } -set tb_top "tb" -if {[info exists ::(TB_TOP)]} { - set tb_top "$::env(TB_TOP)" +if {$waves ne "none"} { + puts "INFO: Dumping waves in [string toupper $waves] format to $wavedump_db." } -if {"$dump_fmt" == "fsdb"} { - # The fsdbDumpvars +all command dumps everything: memories, - # MDA signals, structs, unions, power and packed structs. - puts "Dumping waves with VERDI to waves.fsdb" - fsdbDumpfile "waves.fsdb" - fsdbDumpvars 0 $tb_top +all - fsdbDumpSVA 0 $tb_top -} elseif {"$dump_fmt" == "shm"} { - puts "Dumping waves in SHM format to waves.shm" - database -open -default -shm "waves.shm" - probe "$tb_top" -all -depth all -shm -} elseif {"$dump_fmt" == "vpd"} { - puts "Dumping waves in VCD+ format to waves.vpd" - dump -file "waves.vpd" - dump -add "$tb_top" -depth 0 -aggregates -scope "." -} else { - puts "ERROR: Unknown dump format: ${dump_fmt}" - quit +# Provides wave-format-agnostic way to set a scope (design heirarchy). +# +# In large designs, dumping waves on the entire hierarchy can significantly slow down the +# simulation. It is useful in that case to only dump the relevant scopes of interest during debug. +# +# scope : Design / testbench hierarchy to dump waves. Defaults to $tb_top. +# depth : Levels in the hierarchy to dump waves. Defaults to 0 (dump all levels). +# fsdb_flags : Additional string flags passed to fsdbDumpVars. Defaults to "+all". +# probe_flags : Additional string flags passed to probe command (Xcelium). Defaults to "-all". +# dump_flags : Additional string flags passed to dump command (VCS). Defaults to "-aggregates". +# +# Depending on the need, more such technlogy specific flags can be added in future. +proc wavedumpScope {scope {depth 0} {fsdb_flags "+all"} {probe_flags "-all"} + {dump_flags "-aggregates"}} { + global simulator + global waves + global wavedump_db + + switch $waves { + "none" { + } + + "fsdb" { + # The fsdbDumpvars +all command dumps everything: memories, MDAs, + # structs, unions, power, packed structs. In addition, also dump SVAs. + if {$simulator eq "xcelium"} { + call fsdbDumpvars $depth $scope $fsdb_flags + call fsdbDumpSVA $depth $scope + } else { + fsdbDumpvars $depth $scope $fsdb_flags + fsdbDumpSVA $depth $scope + } + } + + "shm" { + if {$depth == 0} { + set depth "all" + } + probe "$scope" $probe_flags -depth $depth -shm + } + + "vpd" { + # The dump command switch -aggregates enables dumping of structs & + # arrays. + dump -add "$scope" -depth $depth $dump_flags + } + + "vcd" { + if {$simulator eq "xcelium"} { + if {$depth == 0} { + set depth "all" + } + probe "$scope" $probe_flags -depth $depth -vcd + } + } + + "evcd" { + if {$simulator eq "xcelium"} { + if {$depth == 0} { + set depth "all" + } + probe "$scope" $probe_flags -depth $depth -evcd + } + } + + default { + puts "ERROR: Unknown wave format: ${waves}." + quit + } + } + puts "INFO: Dumping waves in scope \"$scope:$depth\"." +} + +# Decide whether to dump the entire testbench hierarchy by default. +# +# If this variable is not set externally, it is set to 1 by default here. When set to 1, it adds the +# entire top-level testbench instance for dumping waves. For larger designs, this may slow down the +# simulation. The user can if needed, set it to 0 in the external tcl script that sources this +# script and manually add the hierarchies of interest in there, using the wavedumpScope proc. +setDefault dump_tb_top 1 + + +# By default, add the full test bench scope for wavedump. +if {$dump_tb_top == 1} { + wavedumpScope $tb_top } diff --git a/vendor/lowrisc_ip/dv/tools/xcelium/xcelium.mk b/vendor/lowrisc_ip/dv/tools/xcelium/xcelium.mk deleted file mode 100644 index 45fec21bfd..0000000000 --- a/vendor/lowrisc_ip/dv/tools/xcelium/xcelium.mk +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright lowRISC contributors. -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 -# Makefile option groups that can be enabled by test Makefile / command line. -# These are generic set of option groups that apply to all testbenches. -# Simulator too specific options -# Mandatory items to set (these are used by rules.mk): -# SIMCC - Simulator compiler used to build / elaborate the bench -# SIMX - Simulator executable used to run the tests - -SIMCC := xrun -elaborate -SIMX ?= xrun -SIM_SETUP ?= ${MAKE_ROOT}/xcelium/xcelium.tcl - -# max number of errors before the run is stopped -ERROR_MAX := 50 -# set standard build options -BUILD_OPTS += -l ${BUILD_LOG} -BUILD_OPTS += -access +r -BUILD_OPTS += -messages -BUILD_OPTS += -errormax ${ERROR_MAX} -BUILD_OPTS += -sv -BUILD_OPTS += -timescale 1ns/1ps -BUILD_OPTS += -uvmhome ${UVM_HOME} -BUILD_OPTS += -xmlibdirname ${SV_FLIST_GEN_DIR}/xcelium.d -BUILD_OPTS += -f ${SV_FLIST} -BUILD_OPTS += -64bit -BUILD_OPTS += -xprop F # -xverbose << add to see which modules does not have xprop enabled - - -# set standard run options -RUN_OPTS += -input ${SIM_SETUP} -RUN_OPTS += +SVSEED=${SEED} -RUN_OPTS += +UVM_VERBOSITY=${UVM_VERBOSITY} -RUN_OPTS += +UVM_TESTNAME=${UVM_TEST} -RUN_OPTS += +UVM_TEST_SEQ=${UVM_TEST_SEQ} -RUN_OPTS += -l ${RUN_LOG} -RUN_OPTS += -xmlibdirname ${SV_FLIST_GEN_DIR}/xcelium.d -R -RUN_OPTS += -64bit - - -######################### -## Tool Specific Modes ## -######################### -# Enable simulation profiling -XCELIUM_SIMPROFILE ?= 0 -ifeq (${XCELIUM_SIMPROFILE},1) -endif - -# Enable coverage -XCELIUM_COV ?= 0 -ifeq (${XCELIUM_COV},1) -endif diff --git a/vendor/lowrisc_ip/dv/tools/xcelium/xcelium.tcl b/vendor/lowrisc_ip/dv/tools/xcelium/xcelium.tcl deleted file mode 100644 index bd328c7215..0000000000 --- a/vendor/lowrisc_ip/dv/tools/xcelium/xcelium.tcl +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright lowRISC contributors. -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 - -# TCL file invoked from xcelium simulations at run-time using this: -input - -# Get some environment variables we need. -set en_waves 0 -set tool_srcs_dir "" -if {[info exists ::env(EN_WAVES)]} { - set en_waves "$::env(EN_WAVES)" -} -if {[info exists ::env(TOOL_SRCS_DIR)]} { - set tool_srcs_dir "$::env(TOOL_SRCS_DIR)" -} else { - puts "ERROR: tool script run without TOOL_SRCS_DIR environment variable." - quit -} - -# If wave dumping is enabled, run waves.tcl -if {"$en_waves" == 1} { - source "${tool_srcs_dir}/waves.tcl" -} - -run -quit diff --git a/vendor/lowrisc_ip/dv/verilator/cpp/dpi_memutil.cc b/vendor/lowrisc_ip/dv/verilator/cpp/dpi_memutil.cc new file mode 100644 index 0000000000..7e348af81e --- /dev/null +++ b/vendor/lowrisc_ip/dv/verilator/cpp/dpi_memutil.cc @@ -0,0 +1,666 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "dpi_memutil.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sv_scoped.h" + +// DPI Exports +extern "C" { + +/** + * Write |file| to a memory + * + * @param file path to a SystemVerilog $readmemh()-compatible file (VMEM file) + */ +extern void simutil_memload(const char *file); + +/** + * Write a 32 bit word |val| to memory at index |index| + * + * @return 1 if successful, 0 otherwise + */ +extern int simutil_set_mem(int index, const svBitVecVal *val); +} + +namespace { +// Convenience class for runtime errors when loading an ELF file +class ElfError : public std::exception { + public: + ElfError(const std::string &path, const std::string &msg) { + std::ostringstream oss; + oss << "Failed to load ELF file at `" << path << "': " << msg; + msg_ = oss.str(); + } + + const char *what() const noexcept override { return msg_.c_str(); } + + private: + std::string msg_; +}; + +// Class wrapping an open ELF file +class ElfFile { + public: + ElfFile(const std::string &path) : path_(path) { + (void)elf_errno(); + if (elf_version(EV_CURRENT) == EV_NONE) { + throw std::runtime_error(elf_errmsg(-1)); + } + + fd_ = open(path.c_str(), O_RDONLY, 0); + if (fd_ < 0) { + throw ElfError(path, "could not open file."); + } + + ptr_ = elf_begin(fd_, ELF_C_READ, NULL); + if (!ptr_) { + close(fd_); + throw ElfError(path, elf_errmsg(-1)); + } + + if (elf_kind(ptr_) != ELF_K_ELF) { + elf_end(ptr_); + close(fd_); + throw ElfError(path, "not an ELF file."); + } + } + + ~ElfFile() { + elf_end(ptr_); + close(fd_); + } + + size_t GetPhdrNum() { + size_t phnum; + if (elf_getphdrnum(ptr_, &phnum) != 0) { + throw ElfError(path_, elf_errmsg(-1)); + } + return phnum; + } + + const Elf32_Phdr *GetPhdrs() { + const Elf32_Phdr *phdrs = elf32_getphdr(ptr_); + if (!phdrs) + throw ElfError(path_, elf_errmsg(-1)); + return phdrs; + } + + std::string path_; + int fd_; + Elf *ptr_; +}; +} // namespace + +// Convert a string to a MemImageType, throwing a std::runtime_error +// if it's not a known name. +static MemImageType GetMemImageTypeByName(const std::string &name) { + if (name == "elf") + return kMemImageElf; + if (name == "vmem") + return kMemImageVmem; + + std::ostringstream oss; + oss << "Unknown image type: `" << name << "'."; + throw std::runtime_error(oss.str()); +} + +// Return a MemImageType for the file at filepath or throw a std::runtime_error. +// Never returns kMemImageUnknown. +static MemImageType DetectMemImageType(const std::string &filepath) { + size_t ext_pos = filepath.find_last_of("."); + if (ext_pos == std::string::npos) { + // Assume ELF files if no file extension is given. + // TODO: Make this more robust by actually checking the file contents. + return kMemImageElf; + } + + std::string ext = filepath.substr(ext_pos + 1); + MemImageType image_type = GetMemImageTypeByName(ext); + if (image_type == kMemImageUnknown) { + std::ostringstream oss; + oss << "Cannot auto-detect file type for `" << filepath << "'."; + throw std::runtime_error(oss.str()); + } + + return image_type; +} + +// Generate a single array of bytes representing the contents of PT_LOAD +// segments of the ELF file. Like objcopy, this generates a single "giant +// segment" whose first byte corresponds to the first byte of the lowest +// addressed segment and whose last byte corresponds to the last byte of the +// highest address. +static std::vector FlattenElfFile(const std::string &filepath) { + ElfFile elf(filepath); + + size_t phnum = elf.GetPhdrNum(); + const Elf32_Phdr *phdrs = elf.GetPhdrs(); + + // To mimic what objcopy does (that is, the binary target of BFD), we need to + // iterate over all loadable program headers, find the lowest address, and + // then copy in our loadable data based on their offset with respect to the + // found base address. + + bool any = false; + Elf32_Addr low = 0, high = 0; + for (size_t i = 0; i < phnum; i++) { + const Elf32_Phdr &phdr = phdrs[i]; + + if (phdr.p_type != PT_LOAD) { + std::cout << "Program header number " << i << " in `" << filepath + << "' is not of type PT_LOAD; ignoring." << std::endl; + continue; + } + + if (phdr.p_memsz == 0) { + continue; + } + + if (!any || phdr.p_paddr < low) { + low = phdr.p_paddr; + } + + Elf32_Addr seg_top = phdr.p_paddr + (phdr.p_memsz - 1); + if (seg_top < phdr.p_paddr) { + std::ostringstream oss; + oss << "phdr for segment " << i << " has start 0x" << std::hex + << phdr.p_paddr << " and size 0x" << phdr.p_memsz + << ", which overflows the address space."; + throw ElfError(filepath, oss.str()); + } + + if (!any || seg_top > high) { + high = seg_top; + } + + any = true; + } + + // If any is false, there were no segments that contributed to the + // file. Return nothing. + if (!any) + return std::vector(); + + // Otherwise, we know every valid byte of data has an address in the + // range [low, high] (inclusive). + assert(low <= high); + + size_t file_size; + const char *file_data = elf_rawfile(elf.ptr_, &file_size); + assert(file_data); + + StagedMem ret; + + for (size_t i = 0; i < phnum; i++) { + const Elf32_Phdr &phdr = phdrs[i]; + + if (phdr.p_type != PT_LOAD) { + continue; + } + + // Check the segment actually fits in the file + if (file_size < phdr.p_offset + phdr.p_filesz) { + std::ostringstream oss; + oss << "phdr for segment " << i << " claims to end at offset 0x" + << std::hex << phdr.p_offset + phdr.p_filesz + << ", but the file only has size 0x" << file_size << "."; + throw ElfError(filepath, oss.str()); + } + + uint32_t off = phdr.p_paddr - low; + uint32_t dst_len = phdr.p_memsz; + uint32_t src_len = std::min(phdr.p_filesz, dst_len); + + if (!dst_len) + continue; + + std::vector seg(dst_len, 0); + memcpy(&seg[0], file_data + phdr.p_offset, src_len); + ret.AddSegment(off, std::move(seg)); + } + + return ret.GetFlat(); +} + +// Write a "segment" of data to the given memory area. +static void WriteSegment(const MemArea &m, uint32_t offset, + const std::vector &data) { + assert(m.width_byte <= 32); + assert(m.addr_loc.size == 0 || offset + data.size() <= m.addr_loc.size); + assert((offset % m.width_byte) == 0); + + // If this fails to set scope, it will throw an error which should + // be caught at this function's callsite. + SVScoped scoped(m.location.data()); + + // This "mini buffer" is used to transfer each write to SystemVerilog. It's + // not massively efficient, but doing so ensures that we pass 256 bits (32 + // bytes) of initialised data each time. This is for simutil_set_mem (defined + // in prim_util_memload.svh), whose "val" argument has SystemVerilog type bit + // [255:0]. + uint8_t minibuf[32]; + memset(minibuf, 0, sizeof minibuf); + assert(m.width_byte <= sizeof minibuf); + + uint32_t all_words = (data.size() + m.width_byte - 1) / m.width_byte; + uint32_t full_data_words = data.size() / m.width_byte; + uint32_t part_data_word_len = data.size() % m.width_byte; + bool has_part_data_word = part_data_word_len != 0; + + uint32_t word_offset = offset / m.width_byte; + + // Copy the full data words + for (uint32_t i = 0; i < full_data_words; ++i) { + uint32_t dst_word = word_offset + i; + uint32_t src_byte = i * m.width_byte; + memcpy(minibuf, &data[src_byte], m.width_byte); + if (!simutil_set_mem(dst_word, (svBitVecVal *)minibuf)) { + std::ostringstream oss; + oss << "Could not set `" << m.name << "' memory at byte offset 0x" + << std::hex << dst_word * m.width_byte << "."; + throw std::runtime_error(oss.str()); + } + } + + // Copy any partial data, zeroing minibuf first to ensure that the latter + // bytes in the word are zero. + if (has_part_data_word) { + memset(minibuf, 0, sizeof minibuf); + uint32_t dst_word = word_offset + full_data_words; + uint32_t src_byte = full_data_words * m.width_byte; + memcpy(minibuf, &data[src_byte], part_data_word_len); + if (!simutil_set_mem(dst_word, (svBitVecVal *)minibuf)) { + std::ostringstream oss; + oss << "Could not set `" << m.name << "' memory at byte offset 0x" + << std::hex << dst_word * m.width_byte << " (partial data word)."; + throw std::runtime_error(oss.str()); + } + } +} + +static void WriteElfToMem(const MemArea &m, const std::string &filepath) { + WriteSegment(m, 0, FlattenElfFile(filepath)); +} + +static void WriteVmemToMem(const MemArea &m, const std::string &filepath) { + SVScoped scoped(m.location.data()); + // TODO: Add error handling. + simutil_memload(filepath.data()); +} + +// Merge seg0 and seg1, overwriting any overlapping data in seg0 with +// that from seg1. rng0/rng1 is the base and top address of seg0/seg1, +// respectively. +static std::vector MergeSegments(const AddrRange &rng0, + std::vector &&seg0, + const AddrRange &rng1, + std::vector &&seg1) { + // First, deal with the special case where seg1 completely contains + // seg0 (since there's no copying needed at all). + if (rng1.lo <= rng0.lo && rng0.hi <= rng1.hi) { + return std::move(seg1); + } + + uint32_t new_bot = std::min(rng0.lo, rng1.lo); + uint32_t new_top = std::max(rng0.hi, rng1.hi); + assert(new_bot <= new_top); + size_t new_len = 1 + (size_t)(new_top - new_bot); + assert(seg0.size() <= new_len); + assert(seg1.size() <= new_len); + + // We want to avoid copying if possible. The next most efficient + // case (after just returning seg1) is when seg0 doesn't stick out + // the left hand end. In this case, we can extend seg1 to the right + // (which might not cause a copy) and then copy just the bytes we + // need from seg0. + if (rng1.lo <= rng0.lo) { + assert(rng1.hi < rng0.hi); + assert(new_len == seg1.size() + (rng0.hi - rng1.hi)); + + size_t old_len = seg1.size(); + std::vector ret = std::move(seg1); + ret.resize(new_len); + + // We know that that rng0 isn't completely contained in rng1 and + // that rng0 doesn't stick out of the left hand end. That means it + // must stick out of the right (so rng1.hi < rng0.hi). However, we + // also know that the two ranges overlap, so rng0.lo <= rng1.hi. + assert(rng0.lo <= rng1.hi); + + // src_off is the index of the first byte that needs copying from + // seg0. Note that this is always at least 1 (because there is an + // actual overlap). + uint32_t src_off = 1 + (rng1.hi - rng0.lo); + + assert(seg0.size() == src_off + (rng0.hi - rng1.hi)); + + memcpy(&ret[old_len], &seg0[src_off], rng0.hi - rng1.hi); + return ret; + } + + // In this final case, seg0 sticks out the left hand end. That means + // we'll have to copy seg1 whatever happens (because we have to + // shuffle its elements to the right). Work by resizing seg0 and + // then writing seg1 where it's needed. + std::vector ret = std::move(seg0); + ret.resize(new_len); + + uint32_t off = rng1.lo - rng0.lo; + memcpy(&ret[off], &seg1[0], seg1.size()); + return ret; +} + +void StagedMem::AddSegment(uint32_t offset, std::vector &&seg) { + if (seg.empty()) + return; + + uint32_t seg_top = offset + seg.size() - 1; + assert(seg_top >= offset); + + min_addr_ = std::min(min_addr_, offset); + max_addr_ = std::max(max_addr_, seg_top); + segs_.Emplace(offset, seg_top, std::move(seg), MergeSegments); +} + +std::vector StagedMem::GetFlat() const { + // Since max_addr_ and min_addr_ are inclusive, the size to allocate + // is 1+(max-min). We cast to size_t to make sure the +1 doesn't + // overflow. + size_t len = (size_t)1 + (max_addr_ - min_addr_); + std::vector ret(len, 0); + + for (const auto &pr : segs_) { + const AddrRange &rng = pr.first; + const std::vector &seg = pr.second; + assert(seg.size() == 1 + (rng.hi - rng.lo)); + assert(min_addr_ <= rng.lo); + + uint32_t off = rng.lo - min_addr_; + assert(off + seg.size() <= ret.size()); + + memcpy(&ret[off], &seg[0], seg.size()); + } + return ret; +} + +bool DpiMemUtil::RegisterMemoryArea(const std::string name, + const std::string location) { + // Default to 32bit width and no address + return RegisterMemoryArea(name, location, 32, nullptr); +} + +bool DpiMemUtil::RegisterMemoryArea(const std::string name, + const std::string location, + size_t width_bit, + const MemAreaLoc *addr_loc) { + assert((width_bit <= 256) && + "TODO: Memory loading only supported up to 256 bits."); + assert(width_bit % 8 == 0); + + // First, create and register the memory by name + MemArea mem = {.name = name, + .location = location, + .width_byte = (uint32_t)width_bit / 8, + .addr_loc = {.base = 0, .size = 0}}; + auto ret = name_to_mem_.emplace(name, mem); + if (ret.second == false) { + std::cerr << "ERROR: Can not register \"" << name << "\" at: \"" << location + << "\" (Previously defined at: \"" << ret.first->second.location + << "\")" << std::endl; + return false; + } + + MemArea *stored_mem_area = &ret.first->second; + + // If we have no address information, there's nothing more to do. However, if + // we do have address information, we should add an entry to addr_to_mem_. + if (!addr_loc) { + return true; + } + + // Check that the size of the new area is positive, and that we don't overflow + // the address space. + if (addr_loc->size == 0) { + std::cerr << "ERROR: Can not register '" << name + << "' because it has zero size.\n"; + return false; + } + uint32_t addr_top = addr_loc->base + (addr_loc->size - 1); + if (addr_top < addr_loc->base) { + std::cerr << "ERROR: Can not register '" << name + << "' because it overflows the top of the address space.\n"; + return false; + } + + auto clash = addr_to_mem_.EmplaceDisjoint(addr_loc->base, addr_top, + std::move(stored_mem_area)); + if (clash) { + assert(*clash); + std::cerr << "ERROR: Can not register '" << name + << "' because its address range overlaps the existing area `" + << (*clash)->name << "'.\n"; + return false; + } + stored_mem_area->addr_loc = *addr_loc; + return true; +} + +MemImageType DpiMemUtil::GetMemImageType(const std::string &path, + const char *type) { + return type ? GetMemImageTypeByName(type) : DetectMemImageType(path); +} + +void DpiMemUtil::PrintMemRegions() const { + std::cout << "Registered memory regions:" << std::endl; + for (const auto &pr : name_to_mem_) { + const MemArea &m = pr.second; + std::cout << "\t'" << m.name << "' (" << m.width_byte * 8 + << "bits) at location: '" << m.location << "'"; + if (m.addr_loc.size) { + uint32_t low = m.addr_loc.base; + uint32_t high = m.addr_loc.base + m.addr_loc.size - 1; + std::cout << " (LMA range [0x" << std::hex << low << ", 0x" << high + << "])" << std::dec; + } + std::cout << std::endl; + } +} + +void DpiMemUtil::LoadFileToNamedMem(bool verbose, const std::string &name, + const std::string &filepath, + MemImageType type) { + // If the image type isn't specified, try to figure it out from the file name + if (type == kMemImageUnknown) { + type = DetectMemImageType(filepath); + } + assert(type != kMemImageUnknown); + + // Search for corresponding registered memory based on the name + auto it = name_to_mem_.find(name); + if (it == name_to_mem_.end()) { + std::ostringstream oss; + oss << "`" << name + << ("' is not the name of a known memory region. " + "Run with --meminit=list to get a list."); + throw std::runtime_error(oss.str()); + } + + if (verbose) { + std::cout << "Loading data from file `" << filepath << "' into memory `" + << name << "'." << std::endl; + } + + const MemArea &m = it->second; + + try { + switch (type) { + case kMemImageElf: + WriteElfToMem(m, filepath); + break; + case kMemImageVmem: + WriteVmemToMem(m, filepath); + break; + default: + assert(0); + } + } catch (const SVScoped::Error &err) { + std::ostringstream oss; + oss << "No memory found at `" << err.scope_name_ + << "' (the scope associated with region `" << m.name << "')."; + throw std::runtime_error(oss.str()); + } +} + +void DpiMemUtil::LoadElfToMemories(bool verbose, const std::string &filepath) { + // Load the contents of the ELF file into the staging area + StageElf(verbose, filepath); + + for (const auto &pr : staging_area_) { + const std::string &mem_name = pr.first; + const StagedMem &staged_mem = pr.second; + + auto mem_area_it = name_to_mem_.find(mem_name); + assert(mem_area_it != name_to_mem_.end()); + + const MemArea &mem_area = mem_area_it->second; + + for (const auto seg_pr : staged_mem.GetSegs()) { + const AddrRange &seg_rng = seg_pr.first; + const std::vector &seg_data = seg_pr.second; + try { + WriteSegment(mem_area, seg_rng.lo, seg_data); + } catch (const SVScoped::Error &err) { + std::ostringstream oss; + oss << "No memory found at `" << err.scope_name_ + << "' (the scope associated with region `" << mem_area.name + << "', used by a segment that starts at LMA 0x" << std::hex + << mem_area.addr_loc.base + seg_rng.lo << ")."; + throw std::runtime_error(oss.str()); + } + } + } +} + +void DpiMemUtil::StageElf(bool verbose, const std::string &path) { + // Clear out anything that was in the staging area before + staging_area_.clear(); + + ElfFile elf(path); + + size_t file_size; + const char *file_data = elf_rawfile(elf.ptr_, &file_size); + assert(file_data); + + size_t phnum = elf.GetPhdrNum(); + const Elf32_Phdr *phdrs = elf.GetPhdrs(); + + for (size_t i = 0; i < phnum; ++i) { + const Elf32_Phdr &phdr = phdrs[i]; + if (phdr.p_type != PT_LOAD) + continue; + + if (phdr.p_memsz == 0) + continue; + + const MemArea &mem_area = + GetRegionForSegment(path, i, phdr.p_paddr, phdr.p_memsz); + + // Check that the segment is aligned correctly for the memory + uint32_t local_base = phdr.p_paddr - mem_area.addr_loc.base; + if (local_base % mem_area.width_byte) { + std::ostringstream oss; + oss << "Segment " << i << " has LMA 0x" << std::hex << phdr.p_paddr + << ", which starts at offset 0x" << local_base + << " in the memory region `" << mem_area.name + << "'. This offset is not aligned to the region's word width of " + << std::dec << 8 * mem_area.width_byte << " bits."; + throw ElfError(path, oss.str()); + } + + // Where does the segment finish in the file image? We don't need + // to worry about overflow here, because we're adding two + // uint32_t's into a size_t. But we do need to check the segment + // actually fits in the file + size_t off_end = (size_t)phdr.p_offset + phdr.p_filesz; + if (file_size < off_end) { + std::ostringstream oss; + oss << "phdr for segment " << i << " claims to end at offset 0x" + << std::hex << off_end - 1 << ", but the file only has size 0x" + << file_size << "."; + throw ElfError(path, oss.str()); + } + + if (verbose) { + std::cout << "Loading segment " << i << " from ELF file `" << path + << "' into memory `" << mem_area.name << "'." << std::endl; + } + + // Get the StagedMem object associated with this memory area. If + // there isn't one, make a new empty one. + StagedMem &staged_mem = staging_area_[mem_area.name]; + + const char *seg_data = file_data + phdr.p_offset; + std::vector vec(phdr.p_memsz, 0); + memcpy(&vec[0], seg_data, std::min(phdr.p_filesz, phdr.p_memsz)); + + staged_mem.AddSegment(local_base, std::move(vec)); + } +} + +const StagedMem &DpiMemUtil::GetMemoryData(const std::string &mem_name) const { + auto it = staging_area_.find(mem_name); + return (it == staging_area_.end()) ? empty_ : it->second; +} + +const MemArea &DpiMemUtil::GetRegionForSegment(const std::string &path, + int seg_idx, uint32_t lma, + uint32_t mem_sz) const { + assert(mem_sz > 0); + + auto mem_area_it = addr_to_mem_.find(lma); + if (mem_area_it == addr_to_mem_.end()) { + std::ostringstream oss; + oss << "No memory region is registered that contains the address 0x" + << std::hex << lma << " (the base address of segment " << seg_idx + << ")."; + throw ElfError(path, oss.str()); + } + const MemArea *mem_area = mem_area_it->second; + assert(mem_area); + assert(mem_area->addr_loc.base <= lma); + + uint32_t lma_top = lma + (mem_sz - 1); + if (lma_top < lma) { + std::ostringstream oss; + oss << "Integer overflow for top address of segment " << seg_idx << "."; + throw ElfError(path, oss.str()); + } + + uint32_t local_base = lma - mem_area->addr_loc.base; + uint32_t local_top = lma_top - mem_area->addr_loc.base; + + if (mem_area->addr_loc.size <= local_top) { + std::ostringstream oss; + oss << "Segment " << seg_idx << " has size 0x" << std::hex << mem_sz + << " bytes. Its LMA of 0x" << lma << " is at offset 0x" << local_base + << " in the memory region `" << mem_area->name + << "', so the segment finishes at offset 0x" << local_top + << ", but the memory region is only 0x" << mem_area->addr_loc.size + << " bytes long."; + throw ElfError(path, oss.str()); + } + + return *mem_area; +} diff --git a/vendor/lowrisc_ip/dv/verilator/cpp/dpi_memutil.h b/vendor/lowrisc_ip/dv/verilator/cpp/dpi_memutil.h new file mode 100644 index 0000000000..f37ef97ccb --- /dev/null +++ b/vendor/lowrisc_ip/dv/verilator/cpp/dpi_memutil.h @@ -0,0 +1,166 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include +#include +#include +#include + +#include "ranged_map.h" + +enum MemImageType { + kMemImageUnknown = 0, + kMemImageElf, + kMemImageVmem, +}; + +// The "load" location of a memory area. base is the lowest address in +// the area, and should correspond to an ELF file's LMA. size is the +// length of the area in bytes. +struct MemAreaLoc { + uint32_t base; + uint32_t size; +}; + +struct MemArea { + std::string name; // Unique identifier + std::string location; // Design scope location + uint32_t width_byte; // Memory width in bytes + MemAreaLoc addr_loc; // Address location. If !size, location is unknown. +}; + +// Staged data for a given memory area. +// +// This is represented as an ordered list of disjoint segments (as loaded from +// an ELF file). +// +// Once it is nonempty, the class maintains the invariant that min_addr_ / +// max_addr_ is the smallest / largest byte offset with valid data. +class StagedMem { + public: + StagedMem() : min_addr_(~(uint32_t)0), max_addr_(0) {} + + // Add a segment to the tracked memory + void AddSegment(uint32_t offset, std::vector &&seg); + + // Glob together the tracked segments, interspersing them with + // zeros, and return as a single flat array. + std::vector GetFlat() const; + + typedef RangedMap> SegMap; + + std::pair GetBounds() const { + return std::make_pair(min_addr_, max_addr_); + } + const SegMap &GetSegs() const { return segs_; } + + private: + uint32_t min_addr_, max_addr_; + SegMap segs_; +}; + +/** + * Provide various memory loading utilities for verilog simulations + * + * These utilities require the corresponding DPI functions: + * simutil_memload() + * simutil_set_mem() + * to be defined somewhere as SystemVerilog functions. + */ +class DpiMemUtil { + public: + /** + * Register a memory as instantiated by generic ram + * + * The |name| must be a unique identifier. The function will return false if + * |name| is already used. |location| is the path to the scope of the + * instantiated memory, which needs to support the DPI-C interfaces + * 'simutil_memload' and 'simutil_set_mem' used for 'vmem' and 'elf' files, + * respectively. + * + * The |width_bit| argument specifies the with in bits of the target memory + * instance (used for packing data). This must be a multiple of 8. If + * |addr_loc| is not null, it gives the base and size of the memory for + * loading in the address space (corresponding to LMAs in an ELF file). + * + * Memories must be registered before command arguments are parsed by + * ParseCommandArgs() in order for them to be known. + */ + bool RegisterMemoryArea(const std::string name, const std::string location, + size_t width_bit, const MemAreaLoc *addr_loc); + + /** + * Register a memory with default width (32bits) + */ + bool RegisterMemoryArea(const std::string name, const std::string location); + + /** + * Guess the type of the file at |path|. + * + * If |type| is non-null, it is the name of an image type and will be used. + * Otherwise, the check is based on |path|. If |type| is not a valid name or + * if the function can't guess from the path, throws a std::runtime_error + * with a message about what went wrong. + * + * Never returns kMemImageUnknown. + */ + static MemImageType GetMemImageType(const std::string &path, + const char *type); + + /** + * Print a list of all registered memory regions + * + * @see RegisterMemoryArea() + */ + void PrintMemRegions() const; + + /** + * Load the file at filepath into the named memory. If type is + * kMemImageUnknown, the file type is determined from the path. + */ + void LoadFileToNamedMem(bool verbose, const std::string &name, + const std::string &filepath, MemImageType type); + + /** + * Load an ELF file, placing segments in memories by LMA. + * + * Replaces any data currently in the staging area. + */ + void LoadElfToMemories(bool verbose, const std::string &filepath); + + /** + * Load an ELF file into a staging area in this object, which can then be + * accessed with GetMemoryData(). + * + * If the load fails, raises a std::exception with information about what + * happened. + */ + void StageElf(bool verbose, const std::string &path); + + /** + * Get the contents of the staging area by memory name + */ + const StagedMem &GetMemoryData(const std::string &mem_name) const; + + private: + // Memory area registry + std::map name_to_mem_; + RangedMap addr_to_mem_; + + // Staging area, loaded by StageElf. The map is keyed by names of memories + // stored in name_to_mem_. We also ensure that every segment in a StagedMem + // for a memory starts at an address that's aligned for the word width of + // that memory. Note: we don't also check segments' lengths are aligned. + std::map staging_area_; + const StagedMem empty_; + + /** + * Find a region containing for the given segment's addresses. + * Raises a std::exception if none is found. + */ + const MemArea &GetRegionForSegment(const std::string &path, int seg_idx, + uint32_t lma, uint32_t mem_sz) const; +}; diff --git a/vendor/lowrisc_ip/dv/verilator/cpp/ranged_map.h b/vendor/lowrisc_ip/dv/verilator/cpp/ranged_map.h new file mode 100644 index 0000000000..e9de6e25d9 --- /dev/null +++ b/vendor/lowrisc_ip/dv/verilator/cpp/ranged_map.h @@ -0,0 +1,181 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +// Utility class representing disjoint segments of memory + +#include +#include + +// The type used to represent address ranges. This is essentially a std::pair, +// but we need a operator< custom for the internal map. +template +struct AddrRange { + addr_t lo, hi; +}; + +template +bool operator<(const AddrRange &a, const AddrRange &b) { + return a.lo < b.lo; +} + +template +class RangedMap { + public: + using rng_t = AddrRange; + + // A function used to merge overlapping segments. When called by + // Emplace(), val1 will be the newer value and val0 will be the + // older. + typedef val_t (*MergeFun)(const rng_t &rng0, val_t &&val0, const rng_t &rng1, + val_t &&val1); + + // Insert an entry that covers the address range [min_addr, max_addr] + // (inclusive) with value val. + void Emplace(addr_t min_addr, addr_t max_addr, val_t &&new_val, + MergeFun merge) { + assert(min_addr <= max_addr); + + // Construct hit_lo / hit_hi, a pair of iterators that bound the + // segments that touch the new value. + auto hit_lo = map_.end(); + auto hit_hi = map_.end(); + + rng_t rng = {.lo = min_addr, .hi = max_addr}; + + if (!map_.empty()) { + // Start by finding the first region that starts strictly above min_addr. + auto right_it = map_.upper_bound(rng); + hit_hi = right_it; + + // If hit_hi is map_.end(), every region starts at or below min_addr. If + // not, the region it points to overlaps with the range if hit_hi->first + // <= max_addr. Increment hit_hi until we get to the end or are no longer + // overlapping. The result is the end iterator for our range. + while (hit_hi != map_.end() && hit_hi->first.lo <= max_addr) { + ++hit_hi; + } + + // Now we need to find the low end of the range. Start at right_it and + // decrement while we've not got to the beginning and while the previous + // iterator has a top >= min_addr. + hit_lo = right_it; + while (hit_lo != map_.begin() && + min_addr <= std::prev(hit_lo)->first.hi) { + --hit_lo; + } + } + + // The entry is disjoint from all others iff hit_lo == hit_hi. In which + // case, we can just insert it. + if (hit_lo == hit_hi) { + map_.insert(std::make_pair(rng, std::move(new_val))); + return; + } + + // Otherwise, we use the merge function to merge everything together. + // Accumulate into a new val_t and update min_addr / max_addr as we go. + // Peel off the 1st iteration of the loop to avoid an unnecessary move/copy + // of new_val. + val_t acc = merge(hit_lo->first, std::move(hit_lo->second), rng, + std::move(new_val)); + min_addr = std::min(min_addr, hit_lo->first.lo); + max_addr = std::max(max_addr, hit_lo->first.hi); + + for (auto it = std::next(hit_lo); it != hit_hi; ++it) { + rng_t rng1 = {.lo = min_addr, .hi = max_addr}; + acc = merge(it->first, std::move(it->second), rng1, std::move(acc)); + min_addr = std::min(min_addr, it->first.lo); + max_addr = std::max(max_addr, it->first.hi); + } + + // We've merged everything, and have possibly trashed the values pointed to + // by all the iterators in the range. Throw that lot away and finally + // insert the merged result. + map_.erase(hit_lo, hit_hi); + rng_t rng1 = {.lo = min_addr, .hi = max_addr}; + map_.insert(std::make_pair(rng1, std::move(acc))); + } + + // Try to insert an entry that covers the address range [min_addr, max_addr] + // (inclusive) with value val. + // + // If there is an existing entry that overlaps with the range on either side, + // the map and val are unchanged and a pointer to the existing entry is + // returned. Otherwise, returns nullptr. + const val_t *EmplaceDisjoint(addr_t min_addr, addr_t max_addr, val_t &&val) { + assert(min_addr <= max_addr); + rng_t rng = {.lo = min_addr, .hi = max_addr}; + + if (!map_.empty()) { + // We start by checking for an overlap "from the right". This would be a + // region that starts strictly above min_addr, but where it's low address + // is still <= max_addr. We can use std::map::upper_bound to find the + // first region strictly above min_addr (which returns the end iterator + // if there isn't one). + auto right_it = map_.upper_bound(rng); + if (right_it != map_.end()) { + addr_t right_min = right_it->first.lo; + if (right_min <= max_addr) { + return &right_it->second; + } + } + + // We also need to check from the left side. This would be a region that + // starts at or before min_addr and extends past it. If right_it is + // mem_.begin(), there is no such region (because the lowest addressed + // region already starts above min_addr). Otherwise, decrement right_it + // to get the highest addressed region that starts at or before min_addr. + // Note this still works if right_it is the end iterator: we just pick up + // the last region, which we know exists because map_ is not empty. + if (right_it != map_.begin()) { + auto left_it = std::prev(right_it); + addr_t left_max = left_it->first.hi; + + if (min_addr <= left_max) { + return &left_it->second; + } + } + } + + // Phew, no overlap! + map_.insert(std::make_pair(rng, std::move(val))); + return nullptr; + } + + // Iteration interface + using map_t = std::map; + using const_iterator = typename map_t::const_iterator; + + const_iterator begin() const { return const_iterator(map_.begin()); } + const_iterator end() const { return const_iterator(map_.end()); } + size_t size() const { return map_.size(); } + + // Try to find an entry hitting the given address. Returns end() if there is + // none. + const_iterator find(addr_t addr) const { + // To find the entry containing addr, use upper_bound to find the first + // region strictly after it, and then std::prev to step backwards. This + // fails if either the map is empty (obviously!) or if ub_it is already the + // beginning of the map. + if (map_.empty()) + return end(); + + rng_t diag = {.lo = addr, .hi = addr}; + auto it = map_.upper_bound(diag); + if (it == map_.begin()) + return end(); + + --it; + + // At this point, it will point at the right region if there is one. We + // know that it->first.lo <= addr (because of how upper_bound works). We + // now just need to check that addr <= it->first.hi. + return (addr <= it->first.hi) ? const_iterator(it) : end(); + } + + private: + std::map map_; +}; diff --git a/vendor/lowrisc_ip/dv/verilator/cpp/sv_scoped.cc b/vendor/lowrisc_ip/dv/verilator/cpp/sv_scoped.cc new file mode 100644 index 0000000000..102b0aa94c --- /dev/null +++ b/vendor/lowrisc_ip/dv/verilator/cpp/sv_scoped.cc @@ -0,0 +1,95 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "sv_scoped.h" + +#include +#include + +// Set scope by name, returning the old scope. If the name doesn't describe a +// valid scope, throw an SVScoped::Error. +static svScope SetAbsScope(const std::string &name) { + svScope new_scope = svGetScopeFromName(name.c_str()); + if (!new_scope) + throw SVScoped::Error(name); + return svSetScope(new_scope); +} + +// Resolve name to a scope, using the rules described in the comment above the +// class in sv_scoped.h, and then set it. Returns the old scope. +static svScope SetRelScope(const std::string &name) { + // Absolute (or empty) names resolve to themselves + if (name[0] != '.') { + return SetAbsScope(name); + } + + svScope prev_scope = svGetScope(); + + // Special case: If name is ".", it means to use the current scope. Rather + // than changing scope, we can just return where we are going to stay. + if (name == ".") + return prev_scope; + + // For anything else, count how many dots appear after the first one (so + // ..foo gives an up_count of 1; ...bar gives an up_count of 2). + size_t first_not_dot = name.find_first_not_of('.', 1); + if (first_not_dot == std::string::npos) { + // name looks like "....": that's fine, it just means to go up some number + // of steps from the current position and not down again. Amend + // first_not_dot to point at the '\0'. + first_not_dot = name.size(); + } + size_t up_count = first_not_dot - 1; + + // Get the name of the current scope, so that we can perform surgery. + std::string scope_name = svGetNameFromScope(prev_scope); + + // scope_name will look something like "TOP.foo.bar". Search up_count + // dots from the end, setting last_dot to point at the last dot that should + // appear in the resolved name. + // + // If up_count is too large, behave like "cd /; cd .." and stop at the + // left-most dot. + size_t last_dot = scope_name.size(); + for (size_t i = 0; i < up_count; ++i) { + // This shouldn't ever trigger (because it would mean scope_name was + // either empty or started with a "."), but allowing it makes the code a + // bit more uniform. + if (last_dot == 0) + break; + + size_t dot = scope_name.rfind('.', last_dot - 1); + if (dot == std::string::npos) + break; + + last_dot = dot; + } + + // Delete everything from last_dot onwards. If we are actually pointing at a + // dot, this will do something like "TOP.foo.bar" -> "TOP.foo". If up_count + // was zero or there were no dots, last_dot will equal the size of the string + // (which means, conveniently, that erase is a no-op). + scope_name.erase(last_dot); + + // If first_not_dot points inside name (so name looked like "..foo.bar" + // rather than "..."), subtract one to point at the last dot of the initial + // segment (we know there is one because name[0] == '.') and then append + // everything to scope_name starting from there. For example, if scope_name + // was "TOP.foo.bar.baz" and name was "..qux", we will have just amended + // scope_name to be "TOP.foo.bar". Now we want to add ".qux". + if (first_not_dot < name.size()) { + scope_name.append(name, first_not_dot - 1, std::string::npos); + } + + return SetAbsScope(scope_name); +} + +SVScoped::SVScoped(const std::string &name) : prev_scope_(SetRelScope(name)) {} + +SVScoped::Error::Error(const std::string &scope_name) + : scope_name_(scope_name) { + std::ostringstream oss; + oss << "No such SystemVerilog scope: `" << scope_name << "'."; + msg_ = oss.str(); +} diff --git a/vendor/lowrisc_ip/dv/verilator/cpp/sv_scoped.h b/vendor/lowrisc_ip/dv/verilator/cpp/sv_scoped.h new file mode 100644 index 0000000000..daa1247f95 --- /dev/null +++ b/vendor/lowrisc_ip/dv/verilator/cpp/sv_scoped.h @@ -0,0 +1,51 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef OPENTITAN_HW_DV_VERILATOR_CPP_SV_SCOPED_H_ +#define OPENTITAN_HW_DV_VERILATOR_CPP_SV_SCOPED_H_ + +#include +#include +#include + +/** + * Wrapper and guard class for SV Scope + * + * Call the constructor with a string for the scope that should be used. If + * this string starts with '.', it is taken to be a name relative to the + * current scope. Multiple periods at the start of the string move up in the + * tree (like Python imports). + * + * If the resolved scope cannot be found, the constructor leaves the current + * scope unchanged and throws an SVScoped::Error detailing the non-existent + * scope it tried to use. + * + * For example, if the current scope has name "TOP.foo.bar", then the string + * ".baz" resolves to the scope with name "TOP.foo.bar.baz". The string "..baz" + * resolves to the scope with name "TOP.foo.baz". The string "qux" resolves to + * the scope with name "qux". + * + * This guard restores the previous scope at destruction. + */ +class SVScoped { + public: + SVScoped(const std::string &name); + ~SVScoped() { svSetScope(prev_scope_); } + + class Error : public std::exception { + public: + Error(const std::string &scope_name); + const char *what() const noexcept override { return msg_.c_str(); } + + std::string scope_name_; + + private: + std::string msg_; + }; + + private: + svScope prev_scope_; +}; + +#endif // OPENTITAN_HW_DV_VERILATOR_CPP_SV_SCOPED_H_ diff --git a/vendor/lowrisc_ip/dv/verilator/cpp/verilator_memutil.cc b/vendor/lowrisc_ip/dv/verilator/cpp/verilator_memutil.cc index ba563514cc..9f6c317865 100644 --- a/vendor/lowrisc_ip/dv/verilator/cpp/verilator_memutil.cc +++ b/vendor/lowrisc_ip/dv/verilator/cpp/verilator_memutil.cc @@ -4,58 +4,92 @@ #include "verilator_memutil.h" -#include -#include -#include -#include -#include -#include - +#include #include #include +#include #include -#include +#include +#include +#include + +namespace { +// An instruction to load the file at filepath to the memory called name. If +// name is the empty string then type must be kMemImageElf and this is an +// instruction to load an ELF file, picking memories by LMA. +struct LoadArg { + std::string name; + std::string filepath; + MemImageType type; +}; +} // namespace + +// Parse a meminit command-line argument. This should be of the form +// mem_area,file[,type]. Throw a std::runtime_error if something looks wrong. +static LoadArg ParseMemArg(std::string mem_argument) { + std::array args; + size_t pos = 0; + size_t end_pos = 0; + size_t i; -// DPI Exports -extern "C" { + for (i = 0; i < 3; ++i) { + end_pos = mem_argument.find(",", pos); + // Check for possible exit conditions + if (pos == end_pos) { + std::ostringstream oss; + oss << "empty field in: `" << mem_argument << "'."; + throw std::runtime_error(oss.str()); + } + if (end_pos == std::string::npos) { + args[i] = mem_argument.substr(pos); + break; + } + args[i] = mem_argument.substr(pos, end_pos - pos); + pos = end_pos + 1; + } + // mem_argument is not empty as getopt requires an argument, + // but not a valid argument for memory initialization + if (i == 0) { + std::ostringstream oss; + oss << "meminit must be in the format `name,file[,type]'. Got: `" + << mem_argument << "'."; + throw std::runtime_error(oss.str()); + } -/** - * Write |file| to a memory - * - * @param file path to a SystemVerilog $readmemh()-compatible file (VMEM file) - */ -extern void simutil_verilator_memload(const char *file); + const char *str_type = (2 <= i) ? args[2].c_str() : nullptr; + MemImageType type = DpiMemUtil::GetMemImageType(args[1], str_type); -/** - * Write a 32 bit word |val| to memory at index |index| - * - * @return 1 if successful, 0 otherwise - */ -extern int simutil_verilator_set_mem(int index, const svBitVecVal *val); + return {.name = args[0], .filepath = args[1], .type = type}; } -bool VerilatorMemUtil::RegisterMemoryArea(const std::string name, - const std::string location) { - // Default to 32bit width - return RegisterMemoryArea(name, location, 32); +// Print a usage message to stdout +static void PrintHelp() { + std::cout << "Simulation memory utilities:\n\n" + "-r|--rominit=FILE\n" + " Initialize the ROM with FILE (elf/vmem)\n\n" + "-m|--raminit=FILE\n" + " Initialize the RAM with FILE (elf/vmem)\n\n" + "-f|--flashinit=FILE\n" + " Initialize the FLASH with FILE (elf/vmem)\n\n" + "-l|--meminit=NAME,FILE[,TYPE]\n" + " Initialize memory region NAME with FILE [of TYPE]\n" + " TYPE is either 'elf' or 'vmem'\n\n" + "-E|--load-elf=FILE\n" + " Load ELF file, using segment LMAs to pick memory regions\n\n" + "-l list|--meminit=list\n" + " Print registered memory regions\n\n" + "--verbose-mem-load\n" + " Print a message for each memory load\n\n" + "-h|--help\n" + " Show help\n\n"; } -bool VerilatorMemUtil::RegisterMemoryArea(const std::string name, - const std::string location, - size_t width_bit) { - MemArea mem = {.name = name, .location = location, .width_bit = width_bit}; - - assert((width_bit <= 256) && - "TODO: Memory loading only supported up to 256 bits."); +VerilatorMemUtil::VerilatorMemUtil() : allocation_(new DpiMemUtil()) { + mem_util_ = allocation_.get(); +} - auto ret = mem_register_.emplace(name, mem); - if (ret.second == false) { - std::cerr << "ERROR: Can not register \"" << name << "\" at: \"" << location - << "\" (Previously defined at: \"" << ret.first->second.location - << "\")" << std::endl; - return false; - } - return true; +VerilatorMemUtil::VerilatorMemUtil(DpiMemUtil *mem_util) : mem_util_(mem_util) { + assert(mem_util); } bool VerilatorMemUtil::ParseCLIArguments(int argc, char **argv, @@ -65,14 +99,19 @@ bool VerilatorMemUtil::ParseCLIArguments(int argc, char **argv, {"raminit", required_argument, nullptr, 'm'}, {"flashinit", required_argument, nullptr, 'f'}, {"meminit", required_argument, nullptr, 'l'}, + {"verbose-mem-load", no_argument, nullptr, 'V'}, + {"load-elf", required_argument, nullptr, 'E'}, {"help", no_argument, nullptr, 'h'}, {nullptr, no_argument, nullptr, 0}}; + std::vector load_args; + bool verbose = false; + // Reset the command parsing index in-case other utils have already parsed // some arguments optind = 1; while (1) { - int c = getopt_long(argc, argv, ":r:m:f:l:h", long_options, nullptr); + int c = getopt_long(argc, argv, ":r:m:f:l:E:h", long_options, nullptr); if (c == -1) { break; } @@ -84,43 +123,39 @@ bool VerilatorMemUtil::ParseCLIArguments(int argc, char **argv, case 0: break; case 'r': - if (!MemWrite("rom", optarg)) { - std::cerr << "ERROR: Unable to initialize memory." << std::endl; - return false; - } + load_args.push_back( + {.name = "rom", .filepath = optarg, .type = kMemImageUnknown}); break; case 'm': - if (!MemWrite("ram", optarg)) { - std::cerr << "ERROR: Unable to initialize memory." << std::endl; - return false; - } + load_args.push_back( + {.name = "ram", .filepath = optarg, .type = kMemImageUnknown}); break; case 'f': - if (!MemWrite("flash", optarg)) { - std::cerr << "ERROR: Unable to initialize memory." << std::endl; - return false; - } + load_args.push_back( + {.name = "flash", .filepath = optarg, .type = kMemImageUnknown}); break; - case 'l': { + case 'l': if (strcasecmp(optarg, "list") == 0) { - PrintMemRegions(); + mem_util_->PrintMemRegions(); exit_app = true; return true; } - std::string name; - std::string filepath; - MemImageType type; - if (!ParseMemArg(optarg, name, filepath, type)) { - std::cerr << "ERROR: Unable to parse meminit arguments." << std::endl; - return false; - } - - if (!MemWrite(name, filepath, type)) { - std::cerr << "ERROR: Unable to initialize memory." << std::endl; + // --meminit / -l + try { + load_args.emplace_back(ParseMemArg(optarg)); + } catch (const std::runtime_error &err) { + std::cerr << "ERROR: " << err.what() << std::endl; return false; } - } break; + break; + case 'V': + verbose = true; + break; + case 'E': + load_args.push_back( + {.name = "", .filepath = optarg, .type = kMemImageElf}); + break; case 'h': PrintHelp(); return true; @@ -134,339 +169,20 @@ bool VerilatorMemUtil::ParseCLIArguments(int argc, char **argv, } } - return true; -} - -void VerilatorMemUtil::PrintMemRegions() const { - std::cout << "Registered memory regions:" << std::endl; - for (const auto &m : mem_register_) { - std::cout << "\t'" << m.second.name << "' (" << m.second.width_bit - << "bits) at location: '" << m.second.location << "'" - << std::endl; - } -} - -void VerilatorMemUtil::PrintHelp() const { - std::cout << "Simulation memory utilities:\n\n" - "-r|--rominit=FILE\n" - " Initialize the ROM with FILE (elf/vmem)\n\n" - "-m|--raminit=FILE\n" - " Initialize the RAM with FILE (elf/vmem)\n\n" - "-f|--flashinit=FILE\n" - " Initialize the FLASH with FILE (elf/vmem)\n\n" - "-l|--meminit=NAME,FILE[,TYPE]\n" - " Initialize memory region NAME with FILE [of TYPE]\n" - " TYPE is either 'elf' or 'vmem'\n\n" - "-l list|--meminit=list\n" - " Print registered memory regions\n\n" - "-h|--help\n" - " Show help\n\n"; -} - -bool VerilatorMemUtil::ParseMemArg(std::string mem_argument, std::string &name, - std::string &filepath, MemImageType &type) { - std::array args; - size_t pos = 0; - size_t end_pos = 0; - size_t i; - - for (i = 0; i < 3; ++i) { - end_pos = mem_argument.find(",", pos); - // Check for possible exit conditions - if (pos == end_pos) { - std::cerr << "ERROR: empty field in: " << mem_argument << std::endl; - return false; - } - if (end_pos == std::string::npos) { - args[i] = mem_argument.substr(pos); - break; - } - args[i] = mem_argument.substr(pos, end_pos - pos); - pos = end_pos + 1; - } - // mem_argument is not empty as getopt requires an argument, - // but not a valid argument for memory initialization - if (i == 0) { - std::cerr << "ERROR: meminit must be in \"name,file[,type]\"" - << " got: " << mem_argument << std::endl; - return false; - } - - name = args[0]; - filepath = args[1]; - - if (i == 1) { - // Type not set explicitly - type = DetectMemImageType(filepath); - } else { - type = GetMemImageTypeByName(args[2]); - } - - return true; -} - -MemImageType VerilatorMemUtil::DetectMemImageType(const std::string filepath) { - size_t ext_pos = filepath.find_last_of("."); - std::string ext = filepath.substr(ext_pos + 1); - - if (ext_pos == std::string::npos) { - // Assume ELF files if no file extension is given. - // TODO: Make this more robust by actually checking the file contents. - return kMemImageElf; - } - return GetMemImageTypeByName(ext); -} - -MemImageType VerilatorMemUtil::GetMemImageTypeByName(const std::string name) { - if (name.compare("elf") == 0) { - return kMemImageElf; - } - if (name.compare("vmem") == 0) { - return kMemImageVmem; - } - return kMemImageUnknown; -} - -bool VerilatorMemUtil::IsFileReadable(std::string filepath) const { - struct stat statbuf; - return stat(filepath.data(), &statbuf) == 0; -} - -bool VerilatorMemUtil::ElfFileToBinary(const std::string &filepath, - uint8_t **data, - size_t &len_bytes) const { - uint8_t *buf; - bool retval, any = false; - GElf_Phdr phdr; - GElf_Addr high = 0; - GElf_Addr low = (GElf_Addr)-1; - Elf_Data *elf_data; - size_t i; - - (void)elf_errno(); - len_bytes = 0; - - if (elf_version(EV_CURRENT) == EV_NONE) { - std::cerr << elf_errmsg(-1) << std::endl; - return false; - } - - int fd = open(filepath.c_str(), O_RDONLY, 0); - if (fd < 0) { - std::cerr << "Could not open file: " << filepath << std::endl; - return false; - } - - Elf *elf_desc; - elf_desc = elf_begin(fd, ELF_C_READ, NULL); - if (elf_desc == NULL) { - std::cerr << elf_errmsg(-1) << " in: " << filepath << std::endl; - retval = false; - goto return_fd_end; - } - if (elf_kind(elf_desc) != ELF_K_ELF) { - std::cerr << "Not a ELF file: " << filepath << std::endl; - retval = false; - goto return_elf_end; - } - // TODO: add support for ELFCLASS64 - if (gelf_getclass(elf_desc) != ELFCLASS32) { - std::cerr << "Not a 32-bit ELF file: " << filepath << std::endl; - retval = false; - goto return_elf_end; - } - - size_t phnum; - if (elf_getphdrnum(elf_desc, &phnum) != 0) { - std::cerr << elf_errmsg(-1) << " in: " << filepath << std::endl; - retval = false; - goto return_elf_end; - } - - // - // To mimic what objcopy does (that is, the binary target of BFD), we need to - // iterate over all loadable program headers, find the lowest address, and - // then copy in our loadable sections based on their offset with respect to - // the found base address. - // - for (i = 0; i < phnum; i++) { - if (gelf_getphdr(elf_desc, i, &phdr) == NULL) { - std::cerr << elf_errmsg(-1) << " segment number: " << i - << " in: " << filepath << std::endl; - retval = false; - goto return_elf_end; - } - - if (phdr.p_type != PT_LOAD) { - std::cout << "Program header number " << i << " is not of type PT_LOAD; " - << "ignoring." << std::endl; - continue; - } - - if (phdr.p_filesz == 0) { - continue; - } - - if (!any || phdr.p_paddr < low) { - low = phdr.p_paddr; - } - - if (!any || phdr.p_paddr + phdr.p_filesz > high) { - high = phdr.p_paddr + phdr.p_filesz; - } - - any = true; - } - - len_bytes = high - low; - buf = (uint8_t *)malloc(len_bytes); - assert(buf != NULL); - - for (i = 0; i < phnum; i++) { - (void)gelf_getphdr(elf_desc, i, &phdr); - - if (phdr.p_type != PT_LOAD || phdr.p_filesz == 0) { - continue; - } - - elf_data = elf_getdata_rawchunk(elf_desc, phdr.p_offset, phdr.p_filesz, - ELF_T_BYTE); - - if (elf_data == NULL) { - retval = false; - free(buf); - goto return_elf_end; - } - - memcpy(&buf[phdr.p_paddr - low], (uint8_t *)elf_data->d_buf, - elf_data->d_size); - } - - *data = buf; - retval = true; - -return_elf_end: - elf_end(elf_desc); -return_fd_end: - close(fd); - return retval; -} - -bool VerilatorMemUtil::MemWrite(const std::string &name, - const std::string &filepath) { - MemImageType type = DetectMemImageType(filepath); - if (type == kMemImageUnknown) { - std::cerr << "ERROR: Unable to detect file type for: " << filepath - << std::endl; - // Continuing for more error messages - } - return MemWrite(name, filepath, type); -} - -bool VerilatorMemUtil::MemWrite(const std::string &name, - const std::string &filepath, - MemImageType type) { - // Search for corresponding registered memory based on the name - auto it = mem_register_.find(name); - if (it == mem_register_.end()) { - std::cerr << "ERROR: Memory location not set for: '" << name << "'" - << std::endl; - PrintMemRegions(); - return false; - } - - if (!MemWrite(it->second, filepath, type)) { - std::cerr << "ERROR: Setting memory '" << name << "' failed." << std::endl; - return false; - } - return true; -} - -bool VerilatorMemUtil::MemWrite(const MemArea &m, const std::string &filepath, - MemImageType type) { - if (!IsFileReadable(filepath)) { - std::cerr << "ERROR: Memory initialization file " - << "'" << filepath << "'" - << " is not readable." << std::endl; - return false; - } - - svScope scope = svGetScopeFromName(m.location.data()); - if (!scope) { - std::cerr << "ERROR: No memory found at " << m.location << std::endl; - return false; - } - - if ((m.width_bit % 8) != 0) { - std::cerr << "ERROR: width for: " << m.name - << "must be a multiple of 8 (was : " << m.width_bit << ")" - << std::endl; - return false; - } - size_t size_byte = m.width_bit / 8; - - switch (type) { - case kMemImageElf: - if (!WriteElfToMem(scope, filepath, size_byte)) { - std::cerr << "ERROR: Writing ELF file to memory \"" << m.name << "\" (" - << m.location << ") failed." << std::endl; - return false; + for (const LoadArg &arg : load_args) { + try { + if (!arg.name.empty()) { + mem_util_->LoadFileToNamedMem(verbose, arg.name, arg.filepath, + arg.type); + } else { + assert(arg.type == kMemImageElf); + mem_util_->LoadElfToMemories(verbose, arg.filepath); } - break; - case kMemImageVmem: - if (!WriteVmemToMem(scope, filepath)) { - std::cerr << "ERROR: Writing VMEM file to memory \"" << m.name << "\" (" - << m.location << ") failed." << std::endl; - return false; - } - break; - case kMemImageUnknown: - default: - std::cerr << "ERROR: Unknown file type for " << m.name << std::endl; + } catch (const std::exception &err) { + std::cerr << "ERROR: " << err.what() << std::endl; return false; - } - return true; -} - -bool VerilatorMemUtil::WriteElfToMem(const svScope &scope, - const std::string &filepath, - size_t size_byte) { - bool retcode; - svScope prev_scope = svSetScope(scope); - - uint8_t *buf = nullptr; - size_t len_bytes; - - if (!ElfFileToBinary(filepath, &buf, len_bytes)) { - std::cerr << "ERROR: Could not load: " << filepath << std::endl; - retcode = false; - goto ret; - } - for (int i = 0; i < (len_bytes + size_byte - 1) / size_byte; ++i) { - if (!simutil_verilator_set_mem(i, (svBitVecVal *)&buf[size_byte * i])) { - std::cerr << "ERROR: Could not set memory byte: " << i * size_byte << "/" - << len_bytes << "" << std::endl; - - retcode = false; - goto ret; } } - retcode = true; - -ret: - svSetScope(prev_scope); - free(buf); - return retcode; -} - -bool VerilatorMemUtil::WriteVmemToMem(const svScope &scope, - const std::string &filepath) { - svScope prev_scope = svSetScope(scope); - - // TODO: Add error handling. - simutil_verilator_memload(filepath.data()); - - svSetScope(prev_scope); return true; } diff --git a/vendor/lowrisc_ip/dv/verilator/cpp/verilator_memutil.h b/vendor/lowrisc_ip/dv/verilator/cpp/verilator_memutil.h index 2833c37596..9452612fc7 100644 --- a/vendor/lowrisc_ip/dv/verilator/cpp/verilator_memutil.h +++ b/vendor/lowrisc_ip/dv/verilator/cpp/verilator_memutil.h @@ -2,114 +2,41 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -#ifndef OPENTITAN_HW_DV_VERILATOR_CPP_VERILATOR_MEMUTIL_H_ -#define OPENTITAN_HW_DV_VERILATOR_CPP_VERILATOR_MEMUTIL_H_ +#pragma once -#include "sim_ctrl_extension.h" - -#include +// +// A wrapper class that converts a VerilatorMemutil into a SimCtrlExtension +// -#include -#include +#include -enum MemImageType { - kMemImageUnknown = 0, - kMemImageElf, - kMemImageVmem, -}; - -struct MemArea { - std::string name; // Unique identifier - std::string location; // Design scope location - size_t width_bit; // Memory width -}; +#include "dpi_memutil.h" +#include "sim_ctrl_extension.h" -/** - * Provide various memory loading utilities for Verilator simulations - * - * These utilities require the corresponding DPI functions: - * simutil_verilator_memload() - * simutil_verilator_set_mem() - * to be defined somewhere as SystemVerilog functions. - */ class VerilatorMemUtil : public SimCtrlExtension { public: - /** - * Register a memory as instantiated by generic ram - * - * The |name| must be a unique identifier. The function will return false - * if |name| is already used. |location| is the path to the scope of the - * instantiated memory, which needs to support the DPI-C interfaces - * 'simutil_verilator_memload' and 'simutil_verilator_set_mem' used for - * 'vmem' and 'elf' files, respectively. - * The |width_bit| argument specifies the with in bits of the target memory - * instance (used for packing data). - * - * Memories must be registered before command arguments are parsed by - * ParseCommandArgs() in order for them to be known. - */ - bool RegisterMemoryArea(const std::string name, const std::string location, - size_t width_bit); + // No-argument constructor makes a VerilatorMemUtil. Single-argument + // constructor wraps its mem_util argument (but does not take ownership). + VerilatorMemUtil(); + explicit VerilatorMemUtil(DpiMemUtil *mem_util); - /** - * Register a memory with default width (32bits) - */ - bool RegisterMemoryArea(const std::string name, const std::string location); + // Declared in SimCtrlExtension + bool ParseCLIArguments(int argc, char **argv, bool &exit_app) override; - /** - * Parse command line arguments - * - * Process all recognized command-line arguments from argc/argv. - * - * @param argc, argv Standard C command line arguments - * @param exit_app Indicate that program should terminate - * @return Return code, true == success - */ - virtual bool ParseCLIArguments(int argc, char **argv, bool &exit_app); - - private: - std::map mem_register_; + // Get underlying DpiMemUtil object + DpiMemUtil *GetUnderlying() { return mem_util_; } - /** - * Print a list of all registered memory regions - * - * @see RegisterMemoryArea() - */ - void PrintMemRegions() const; - - /** - * Print help how to use this tool - */ - void PrintHelp() const; - - /** - * Parse argument section specific to memory initialization. - * - * Must be in the form of: name,file[,type]. - */ - bool ParseMemArg(std::string mem_argument, std::string &name, - std::string &filepath, MemImageType &type); - - MemImageType DetectMemImageType(const std::string filepath); - - MemImageType GetMemImageTypeByName(const std::string name); - - bool IsFileReadable(std::string filepath) const; + // Pass-thru functions to underlying object + bool RegisterMemoryArea(const std::string name, const std::string location, + size_t width_bit, const MemAreaLoc *addr_loc) { + return mem_util_->RegisterMemoryArea(name, location, width_bit, addr_loc); + } - /** - * Dump an ELF file into a raw binary - */ - bool ElfFileToBinary(const std::string &filepath, uint8_t **data, - size_t &len_bytes) const; + bool RegisterMemoryArea(const std::string name, const std::string location) { + return mem_util_->RegisterMemoryArea(name, location); + } - bool MemWrite(const std::string &name, const std::string &filepath); - bool MemWrite(const std::string &name, const std::string &filepath, - MemImageType type); - bool MemWrite(const MemArea &m, const std::string &filepath, - MemImageType type); - bool WriteElfToMem(const svScope &scope, const std::string &filepath, - size_t size_byte); - bool WriteVmemToMem(const svScope &scope, const std::string &filepath); + private: + DpiMemUtil *mem_util_; + std::unique_ptr allocation_; }; - -#endif // OPENTITAN_HW_DV_VERILATOR_CPP_VERILATOR_MEMUTIL_H_ diff --git a/vendor/lowrisc_ip/dv/verilator/memutil_dpi.core b/vendor/lowrisc_ip/dv/verilator/memutil_dpi.core new file mode 100644 index 0000000000..490d62592a --- /dev/null +++ b/vendor/lowrisc_ip/dv/verilator/memutil_dpi.core @@ -0,0 +1,21 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +name: "lowrisc:dv_verilator:memutil_dpi" +description: "DPI memory utilities" +filesets: + files_cpp: + files: + - cpp/ranged_map.h: { is_include_file: true } + - cpp/dpi_memutil.cc + - cpp/dpi_memutil.h: { is_include_file: true } + - cpp/sv_scoped.cc + - cpp/sv_scoped.h: { is_include_file: true } + file_type: cppSource + +targets: + default: + filesets: + - files_cpp diff --git a/vendor/lowrisc_ip/dv/verilator/memutil_verilator.core b/vendor/lowrisc_ip/dv/verilator/memutil_verilator.core index 2cd1831bfd..b2f27c1537 100644 --- a/vendor/lowrisc_ip/dv/verilator/memutil_verilator.core +++ b/vendor/lowrisc_ip/dv/verilator/memutil_verilator.core @@ -9,6 +9,7 @@ filesets: files_cpp: depend: - lowrisc:dv_verilator:simutil_verilator + - lowrisc:dv_verilator:memutil_dpi files: - cpp/verilator_memutil.cc - cpp/verilator_memutil.h: { is_include_file: true } diff --git a/vendor/lowrisc_ip/dv/verilator/simutil_verilator/cpp/verilator_sim_ctrl.cc b/vendor/lowrisc_ip/dv/verilator/simutil_verilator/cpp/verilator_sim_ctrl.cc index ec4ec908f8..39a712ac2f 100644 --- a/vendor/lowrisc_ip/dv/verilator/simutil_verilator/cpp/verilator_sim_ctrl.cc +++ b/vendor/lowrisc_ip/dv/verilator/simutil_verilator/cpp/verilator_sim_ctrl.cc @@ -22,6 +22,18 @@ */ double sc_time_stamp() { return VerilatorSimCtrl::GetInstance().GetTime(); } +#ifdef VL_USER_STOP +/** + * A simulation stop was requested, e.g. through $stop() or $error() + * + * This function overrides Verilator's default implementation to more gracefully + * shut down the simulation. + */ +void vl_stop(const char *filename, int linenum, const char *hier) VL_MT_UNSAFE { + VerilatorSimCtrl::GetInstance().RequestStop(false); +} +#endif + VerilatorSimCtrl &VerilatorSimCtrl::GetInstance() { static VerilatorSimCtrl instance; return instance; diff --git a/vendor/lowrisc_ip/ip/prim/doc/prim_packer_fifo.md b/vendor/lowrisc_ip/ip/prim/doc/prim_packer_fifo.md new file mode 100644 index 0000000000..95e5eaae5f --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/doc/prim_packer_fifo.md @@ -0,0 +1,67 @@ +--- +title: "Primitive Component: Packer FIFO" +--- + +# Overview + +`prim_packer_fifo` is a module that supports three modes of operation: packing, +unpacking, and single depth FIFO modes. Packing mode is where the input +data width is less than the output data width. Unpacking mode is where the input +data width is greater than the output data width. Single depth FIFO is where +the input and output data widths are the same. Because masking options are not +supported, the larger data size must be an even multiple of the smaller size. +The controls for this module are modeled after the `prim_fifo_sync` module, +both in name and functional behavior. +It is one of a set of shared primitive modules +available for use within OpenTitan as referred to in the Comportability +Specification section on shared primitives. + +## Parameters + +Name | type | Description +-----|------|------------- +InW | int | Input data width +OutW | int | Output data width + +## Signal Interfaces + +Name | In/Out | Description +-------------|--------|------------- +clk_i | input | Input clock +rst_ni | input | Input reset, negative active +clr_i | input | Input clear, clears all internal flops. +wvalid_i | input | Writes data into the first available position. +wdata_i[InW] | input | Input data. +wready_o | output | Indicates if prim_packer_fifo is able to accept data. +rvalid_o | output | Indicates if output data is valid. +rdata_o[OutW]| output | Output data. +rready_i | input | Output data is popped from the FIFO. +depth_o | output | Indicates the fullness of the FIFO. + +# Theory of Opeations + +```code + /----------\ +wvalid_i | | rvalid_o +---------->| |---------------> +wdata_i | Flop | rdata_o +=====/====>| FIFO |=======/=======> + [InW] | | [OutW] + | | depth_o + | |---------------> +wready_o | | rready_i +<----------| |<--------------- + | | + \----------/ +``` + +In pack mode, `prim_packer_fifo` accepts `InW` bits of data. On a `wvalid_i`/ +`wready_o` handshake, `wdata_i` is stored to internal registers and accumulated +until `OutW` data has been gathered. Once the FIFO is full, a single pop (when +rvalid_o and rready_i are coincident), will clear the data and depth values on +the next clock cycle. The complimentary flow occurs when the`prim_packer_fifo` +module is in unpack mode. + +The internal register size is the greate of `InW` and `OutW` bits. +Timing diagrams are shown in the header of the `prim_packer_fifo` module. + diff --git a/vendor/lowrisc_ip/ip/prim/doc/prim_present.md b/vendor/lowrisc_ip/ip/prim/doc/prim_present.md index da7856eed2..89407472c6 100644 --- a/vendor/lowrisc_ip/ip/prim/doc/prim_present.md +++ b/vendor/lowrisc_ip/ip/prim/doc/prim_present.md @@ -13,11 +13,14 @@ I.e., this primitive is only intended to be used as a lightweight data scramblin ## Parameters -Name | type | Description --------------|--------|---------------------------------------------------------- -DataWidth | int | Block size, can be 32 or 64 -KeyWidth | int | Key size, can be 64, 80 or 128 -NumRounds | int | Number of PRESENT rounds, has to be greater than 0 +Name | type | Description +--------------|--------|---------------------------------------------------------- +DataWidth | int | Block size, can be 32 or 64 +KeyWidth | int | Key size, can be 64, 80 or 128 +NumRounds | int | Number of PRESENT rounds, has to be greater than 0 +NumPhysRounds | int | Number of physically instantiated PRESENT rounds (defaults to NumRounds) + +Note that by setting `NumRounds = 31` and `NumPhysRounds = 1` we can construct a PRESENT primitive that is suitable for iterative evaluation of a full-round PRESENT pass, where each iteration evaluates one of the 31 rounds. ## Signal Interfaces @@ -25,19 +28,28 @@ Name | In/Out | Description -------------|--------|--------------------------------- data_i | input | Plaintext input key_i | input | Key input +idx_i | input | Round index input data_o | output | Output of the ciphertext +key_o | output | Key output after keyschedule update +idx_o | output | Round index output after keyschedule update + +The `key_o` and `idx_o` are useful for iterative implementations where the state of the scheduled key, as well as the current round index have to be registered in between rounds. +Note that `idx_i` should be initialized to 1 for encryption mode, and to `NumRounds` for decryption mode. # Theory of Operations ``` /---------------\ | | +idx_i | | idx_o +=====/======>| |=====/======> + [5] | | [5] | PRESENT | -key_i | | -=====/======>| DataWidth | - [KeyWidth] | KeyWidth | +key_i | | key_o +=====/======>| DataWidth |=====/======> + [KeyWidth] | KeyWidth | [KeyWidth] | NumRounds | -data_i | | data_o +data_i | NumPhysRounds | data_o =====/======>| |=====/=======> [DataWidth] | | [DataWidth] | | @@ -49,21 +61,25 @@ The only inputs are the key and the plaintext, and the only output is the cipher The internal construction follows the the algorithm described in the original [paper](http://www.lightweightcrypto.org/present/present_ches2007.pdf). The block size is 64bit and the key size can be either 80bit or 128bit, depending on the security requirements. -In its original formulation, this cipher has 31 rounds comprised of an XOR operation with a round key, followed by the application of an s-box and a permutation layer: +In its original formulation, this cipher has 31 rounds comprised of an XOR operation with a round key, followed by the application of an s-box and a permutation layer, as illustrated for the encryption pass below: ```c++ +NumRounds = 32; +idx_i = 1; -round_keys = key_derivation(key_i); +round_keys = key_derivation(key_i, idx_i); state = data_i; -for (int i=1; i < 32; i++) { +for (int i=0; i < NumRounds; i++) { state = state ^ round_keys[i]; state = sbox4_layer(state); state = perm_layer(state); } -data_o = state ^ round_keys[32]; +data_o = state ^ round_keys[NumRounds-1]; +key_o = round_keys[NumRounds-1]; +idx_o = idx_i + NumRounds; ``` The reduced 32bit block-size variant implemented is non-standard and should only be used for scrambling purposes, since it **is not secure**. diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/data/prim_lfsr_cov_excl.el b/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/data/prim_lfsr_cov_excl.el new file mode 100644 index 0000000000..7734a00d85 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/data/prim_lfsr_cov_excl.el @@ -0,0 +1,48 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +//================================================== +// This file contains the Excluded objects +// Generated By User: udij +// Format Version: 2 +// Date: Fri Oct 16 15:45:46 2020 +// ExclMode: default +//================================================== +CHECKSUM: "2196990883" +INSTANCE: prim_lfsr_tb.gen_duts[24].i_prim_lfsr +ANNOTATION: "[EXTERNAL] seed/entropy inputs tied off in DV as they are covered in FPV." +Assert gen_lockup_mechanism_sva.LfsrLockupCheck_A "assertion" +ANNOTATION: "[EXTERNAL] seed/entropy inputs tied off in DV as they are covered in FPV." +Assert gen_ext_seed_sva.ExtDefaultSeedInputCheck_A "assertion" +CHECKSUM: "2196990883 1520894529" +INSTANCE: prim_lfsr_tb.gen_duts[24].i_prim_lfsr +ANNOTATION: "[EXTERNAL] Covered in FPV testbench." +Condition 2 "2655198170" "((lfsr_en_i && lockup) ? DefaultSeed : (lfsr_en_i ? next_lfsr_state : lfsr_q)) 1 -1" (2 "1") +ANNOTATION: "[EXTERNAL] Covered in FPV testbench." +Condition 3 "1026054222" "(lfsr_en_i && lockup) 1 -1" (3 "11") +ANNOTATION: "[EXTERNAL] Covered in FPV testbench." +Condition 3 "1026054222" "(lfsr_en_i && lockup) 1 -1" (1 "01") +ANNOTATION: "[EXTERNAL] Covered in FPV testbench." +Condition 5 "4214161107" "((lfsr_en_i && lockup) ? '0 : ((lfsr_en_i && (gen_max_len_sva.cnt_q == gen_max_len_sva.cmp_val)) ? '0 : (lfsr_en_i ? ((gen_max_len_sva.cnt_q + 1'b1)) : gen_max_len_sva.cnt_q))) 1 -1" (2 "1") +ANNOTATION: "[EXTERNAL] Covered in FPV testbench." +Condition 6 "3622507969" "(lfsr_en_i && lockup) 1 -1" (3 "11") +ANNOTATION: "[EXTERNAL] Covered in FPV testbench." +Condition 6 "3622507969" "(lfsr_en_i && lockup) 1 -1" (1 "01") +ANNOTATION: "[EXTERNAL] Covered in FPV testbench." +Condition 8 "1510648413" "(lfsr_en_i && (gen_max_len_sva.cnt_q == gen_max_len_sva.cmp_val)) 1 -1" (1 "01") +CHECKSUM: "2196990883 2214500533" +INSTANCE: prim_lfsr_tb.gen_duts[24].i_prim_lfsr +ANNOTATION: "[EXTERNAL] Covered in FPV testbench." +Branch 0 "780369097" "seed_en_i" (0) "seed_en_i 1,-,-" +ANNOTATION: "[EXTERNAL] Covered in FPV testbench." +Branch 0 "780369097" "seed_en_i" (1) "seed_en_i 0,1,-" +ANNOTATION: "[EXTERNAL] Covered in FPV testbench." +Branch 1 "864650299" "(lfsr_en_i && lockup)" (0) "(lfsr_en_i && lockup) 1,-,-" +CHECKSUM: "2196990883 528004685" +INSTANCE: prim_lfsr_tb.gen_duts[24].i_prim_lfsr +ANNOTATION: "[EXTERNAL] Covered in FPV testbench." +Block 33 "1545234335" "state = DefaultSeed;" +CHECKSUM: "2196990883 1321015592" +INSTANCE: prim_lfsr_tb.gen_duts[24].i_prim_lfsr +ANNOTATION: "[LOW_RISK] DV bench is meant to be extremely light-weight and already tests that prim_lfsr can come out of reset correctly" +Toggle rst_ni "net rst_ni" diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/data/prim_lfsr_cover.cfg b/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/data/prim_lfsr_cover.cfg new file mode 100644 index 0000000000..8c389c6410 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/data/prim_lfsr_cover.cfg @@ -0,0 +1,12 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// We only collect coverage for the LFSR with width 24 as it is the largest +// width tested in DV - FPV fully covers a large range of widths, +// so this is ok. + ++tree prim_lfsr_tb.gen_duts[24].i_prim_lfsr +begin tgl(portsonly) + +tree prim_lfsr_tb.gen_duts[24].i_prim_lfsr +end diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/data/prim_lfsr_cover_assert.cfg b/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/data/prim_lfsr_cover_assert.cfg new file mode 100644 index 0000000000..8938694003 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/data/prim_lfsr_cover_assert.cfg @@ -0,0 +1,9 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// We only collect coverage for the LFSR with width 24 as it is the largest +// width tested in DV - FPV fully covers a large range of widths, +// so this is ok. + ++tree prim_lfsr_tb.gen_duts[24].i_prim_lfsr diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_sim.core b/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_sim.core index 2555492723..c70bd3b675 100644 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_sim.core +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_sim.core @@ -19,9 +19,12 @@ filesets: file_type: systemVerilogSource targets: - sim: + sim: &sim_target toplevel: prim_lfsr_tb filesets: - files_rtl - files_dv default_tool: vcs + + lint: + <<: *sim_target diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_sim_cfg.hjson b/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_sim_cfg.hjson index 65cc60387c..2ce01dd461 100644 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_sim_cfg.hjson +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_sim_cfg.hjson @@ -17,15 +17,20 @@ // Fusesoc core file used for building the file list. fusesoc_core: lowrisc:dv:prim_lfsr_sim:0.1 - // Testplan hjson file. - testplan: "{proj_root}/hw/ip/prim/dv/prim_lfsr/prim_lfsr_testplan.hjson" - // Import additional common sim cfg files. - import_cfgs: ["{proj_root}/hw/dv/data/common_sim_cfg.hjson"] + import_cfgs: ["{proj_root}/hw/dv/tools/dvsim/common_sim_cfg.hjson"] // Default iterations for all tests - each test entry can override this. reseed: 50 + // Add the coverage configuration and exclusion files so they get copied + // over to the scratch area. + tool_srcs: ["{proj_root}/hw/ip/prim/dv/prim_lfsr/data/prim_lfsr_cover.cfg", + "{proj_root}/hw/ip/prim/dv/prim_lfsr/data/prim_lfsr_cover_assert.cfg", + "{proj_root}/hw/ip/prim/dv/prim_lfsr/data/prim_lfsr_cov_excl.el"] + + vcs_cov_excl_files: ["{tool_srcs_dir}/prim_lfsr_cov_excl.el"] + build_modes: [ { name: prim_lfsr_dw_8 @@ -37,10 +42,10 @@ } ] - // TODO: each build_mode needs to supply {build_mode}_{tool}_cov_cfg_file, else the - // build breaks. + // dw_8 is only used for "smoke" sims, so coverage collection is not needed. prim_lfsr_dw_8_vcs_cov_cfg_file: "" - prim_lfsr_dw_24_vcs_cov_cfg_file: "" + prim_lfsr_dw_24_vcs_cov_cfg_file: "-cm_hier {tool_srcs_dir}/prim_lfsr_cover.cfg" + vcs_cov_assert_cfg_file: "-cm_assert_hier {tool_srcs_dir}/prim_lfsr_cover_assert.cfg" prim_lfsr_dw_8_xcelium_cov_cfg_file: "" prim_lfsr_dw_24_xcelium_cov_cfg_file: "" @@ -48,12 +53,12 @@ // List of test specifications. tests: [ { - name: prim_lfsr_sanity + name: prim_lfsr_smoke // limit max lfsr length to reduce private CI runtime. build_mode: prim_lfsr_dw_8 } { - name: prim_lfsr_basic_test + name: prim_lfsr_test build_mode: prim_lfsr_dw_24 } ] @@ -61,8 +66,12 @@ // List of regressions. regressions: [ { - name: sanity - tests: ["prim_lfsr_sanity"] + name: smoke + tests: ["prim_lfsr_smoke"] + } + { + name: nightly + tests:["prim_lfsr_test"] } ] } diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_testplan.hjson b/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_testplan.hjson deleted file mode 100644 index d828196eb4..0000000000 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_testplan.hjson +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 -{ - name: "prim_lfsr" - import_testplans: [] - entries: [ - { - name: sanity - desc: '''Simple LFSR test - sweep through all implementations within a - certain range to check whether they are max length.''' - milestone: V2 - tests: ["prim_lfsr_sanity"] - } - ] -} diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/tb/prim_lfsr_tb.sv b/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/tb/prim_lfsr_tb.sv index e75a16c34f..1422af8e33 100644 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/tb/prim_lfsr_tb.sv +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/tb/prim_lfsr_tb.sv @@ -49,18 +49,96 @@ module prim_lfsr_tb; // DUTs ////////////////////////////////////////////////////// + // The StatePerm below is only defined for LFSRs up to 256bit wide. + `ASSERT_INIT(MaxStateSizeCheck_A, MaxLfsrDw < 256) + logic [MaxLfsrDw:0] lfsr_en, err; logic [MaxLfsrDw:MinLfsrDw][MaxLfsrDw-1:0] state_out; logic [MaxLfsrDw:MinLfsrDw][MaxLfsrDw-1:0] lfsr_periods; for (genvar k = MinLfsrDw; k <= MaxLfsrDw; k++) begin : gen_duts + // This is used to specify an identity permutation via the custom state output + // permutation parameter for all LFSRs up to 256bit wide. + localparam int Dw = $clog2(k); + localparam logic [255:0][Dw-1:0] StatePerm = '{ + Dw'(32'd255), Dw'(32'd254), Dw'(32'd253), Dw'(32'd252), + Dw'(32'd251), Dw'(32'd250), Dw'(32'd249), Dw'(32'd248), + Dw'(32'd247), Dw'(32'd246), Dw'(32'd245), Dw'(32'd244), + Dw'(32'd243), Dw'(32'd242), Dw'(32'd241), Dw'(32'd240), + Dw'(32'd239), Dw'(32'd238), Dw'(32'd237), Dw'(32'd236), + Dw'(32'd235), Dw'(32'd234), Dw'(32'd233), Dw'(32'd232), + Dw'(32'd231), Dw'(32'd230), Dw'(32'd229), Dw'(32'd228), + Dw'(32'd227), Dw'(32'd226), Dw'(32'd225), Dw'(32'd224), + Dw'(32'd223), Dw'(32'd222), Dw'(32'd221), Dw'(32'd220), + Dw'(32'd219), Dw'(32'd218), Dw'(32'd217), Dw'(32'd216), + Dw'(32'd215), Dw'(32'd214), Dw'(32'd213), Dw'(32'd212), + Dw'(32'd211), Dw'(32'd210), Dw'(32'd209), Dw'(32'd208), + Dw'(32'd207), Dw'(32'd206), Dw'(32'd205), Dw'(32'd204), + Dw'(32'd203), Dw'(32'd202), Dw'(32'd201), Dw'(32'd200), + Dw'(32'd199), Dw'(32'd198), Dw'(32'd197), Dw'(32'd196), + Dw'(32'd195), Dw'(32'd194), Dw'(32'd193), Dw'(32'd192), + Dw'(32'd191), Dw'(32'd190), Dw'(32'd189), Dw'(32'd188), + Dw'(32'd187), Dw'(32'd186), Dw'(32'd185), Dw'(32'd184), + Dw'(32'd183), Dw'(32'd182), Dw'(32'd181), Dw'(32'd180), + Dw'(32'd179), Dw'(32'd178), Dw'(32'd177), Dw'(32'd176), + Dw'(32'd175), Dw'(32'd174), Dw'(32'd173), Dw'(32'd172), + Dw'(32'd171), Dw'(32'd170), Dw'(32'd169), Dw'(32'd168), + Dw'(32'd167), Dw'(32'd166), Dw'(32'd165), Dw'(32'd164), + Dw'(32'd163), Dw'(32'd162), Dw'(32'd161), Dw'(32'd160), + Dw'(32'd159), Dw'(32'd158), Dw'(32'd157), Dw'(32'd156), + Dw'(32'd155), Dw'(32'd154), Dw'(32'd153), Dw'(32'd152), + Dw'(32'd151), Dw'(32'd150), Dw'(32'd149), Dw'(32'd148), + Dw'(32'd147), Dw'(32'd146), Dw'(32'd145), Dw'(32'd144), + Dw'(32'd143), Dw'(32'd142), Dw'(32'd141), Dw'(32'd140), + Dw'(32'd139), Dw'(32'd138), Dw'(32'd137), Dw'(32'd136), + Dw'(32'd135), Dw'(32'd134), Dw'(32'd133), Dw'(32'd132), + Dw'(32'd131), Dw'(32'd130), Dw'(32'd129), Dw'(32'd128), + Dw'(32'd127), Dw'(32'd126), Dw'(32'd125), Dw'(32'd124), + Dw'(32'd123), Dw'(32'd122), Dw'(32'd121), Dw'(32'd120), + Dw'(32'd119), Dw'(32'd118), Dw'(32'd117), Dw'(32'd116), + Dw'(32'd115), Dw'(32'd114), Dw'(32'd113), Dw'(32'd112), + Dw'(32'd111), Dw'(32'd110), Dw'(32'd109), Dw'(32'd108), + Dw'(32'd107), Dw'(32'd106), Dw'(32'd105), Dw'(32'd104), + Dw'(32'd103), Dw'(32'd102), Dw'(32'd101), Dw'(32'd100), + Dw'(32'd099), Dw'(32'd098), Dw'(32'd097), Dw'(32'd096), + Dw'(32'd095), Dw'(32'd094), Dw'(32'd093), Dw'(32'd092), + Dw'(32'd091), Dw'(32'd090), Dw'(32'd089), Dw'(32'd088), + Dw'(32'd087), Dw'(32'd086), Dw'(32'd085), Dw'(32'd084), + Dw'(32'd083), Dw'(32'd082), Dw'(32'd081), Dw'(32'd080), + Dw'(32'd079), Dw'(32'd078), Dw'(32'd077), Dw'(32'd076), + Dw'(32'd075), Dw'(32'd074), Dw'(32'd073), Dw'(32'd072), + Dw'(32'd071), Dw'(32'd070), Dw'(32'd069), Dw'(32'd068), + Dw'(32'd067), Dw'(32'd066), Dw'(32'd065), Dw'(32'd064), + Dw'(32'd063), Dw'(32'd062), Dw'(32'd061), Dw'(32'd060), + Dw'(32'd059), Dw'(32'd058), Dw'(32'd057), Dw'(32'd056), + Dw'(32'd055), Dw'(32'd054), Dw'(32'd053), Dw'(32'd052), + Dw'(32'd051), Dw'(32'd050), Dw'(32'd049), Dw'(32'd048), + Dw'(32'd047), Dw'(32'd046), Dw'(32'd045), Dw'(32'd044), + Dw'(32'd043), Dw'(32'd042), Dw'(32'd041), Dw'(32'd040), + Dw'(32'd039), Dw'(32'd038), Dw'(32'd037), Dw'(32'd036), + Dw'(32'd035), Dw'(32'd034), Dw'(32'd033), Dw'(32'd032), + Dw'(32'd031), Dw'(32'd030), Dw'(32'd029), Dw'(32'd028), + Dw'(32'd027), Dw'(32'd026), Dw'(32'd025), Dw'(32'd024), + Dw'(32'd023), Dw'(32'd022), Dw'(32'd021), Dw'(32'd020), + Dw'(32'd019), Dw'(32'd018), Dw'(32'd017), Dw'(32'd016), + Dw'(32'd015), Dw'(32'd014), Dw'(32'd013), Dw'(32'd012), + Dw'(32'd011), Dw'(32'd010), Dw'(32'd009), Dw'(32'd008), + Dw'(32'd007), Dw'(32'd006), Dw'(32'd005), Dw'(32'd004), + Dw'(32'd003), Dw'(32'd002), Dw'(32'd001), Dw'(32'd000) + }; + prim_lfsr #( .LfsrType ( LfsrType ), .LfsrDw ( k ), .EntropyDw ( 1 ), .StateOutDw ( k ), .DefaultSeed ( k'(SEED) ), - // enable internal max length check + // The case where this is disabled is already tested with FPV. + // Hence we cover the enabled case with custom permutations + // in this testbench. + .StatePermEn ( 1'b1 ), + .StatePerm ( StatePerm[MaxLfsrDw-1:0] ), + // Enable internal max length check. .MaxLenSVA ( 1'b1 ) ) i_prim_lfsr ( .clk_i ( clk ), diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_present/data/prim_present_cover.cfg b/vendor/lowrisc_ip/ip/prim/dv/prim_present/data/prim_present_cover.cfg index 20079e3e02..8789a92af7 100644 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_present/data/prim_present_cover.cfg +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_present/data/prim_present_cover.cfg @@ -1,3 +1,7 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +module prim_present begin tgl(portsonly) -tree prim_present_tb diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_present/data/prim_present_testplan.hjson b/vendor/lowrisc_ip/ip/prim/dv/prim_present/data/prim_present_testplan.hjson index 9ff6328388..dc3dfe9573 100644 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_present/data/prim_present_testplan.hjson +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_present/data/prim_present_testplan.hjson @@ -6,12 +6,12 @@ import_testplans: [] entries: [ { - name: sanity + name: smoke desc: '''Simple PRESENT test - feed golden and random testvectors into both the encryption and decryption algorithms and verify that all outputs match those from the reference model.''' milestone: V2 - tests: ["prim_present_sanity"] + tests: ["prim_present_smoke"] } ] } diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_present/prim_present_sim.core b/vendor/lowrisc_ip/ip/prim/dv/prim_present/prim_present_sim.core index b4c5c501e5..0356b7843c 100644 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_present/prim_present_sim.core +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_present/prim_present_sim.core @@ -18,9 +18,12 @@ filesets: file_type: systemVerilogSource targets: - sim: + sim: &sim_target toplevel: prim_present_tb filesets: - files_rtl - files_dv default_tool: vcs + + lint: + <<: *sim_target diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_present/prim_present_sim_cfg.hjson b/vendor/lowrisc_ip/ip/prim/dv/prim_present/prim_present_sim_cfg.hjson index bc807e0f92..84745cf1e9 100644 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_present/prim_present_sim_cfg.hjson +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_present/prim_present_sim_cfg.hjson @@ -21,7 +21,7 @@ testplan: "{proj_root}/hw/ip/prim/dv/prim_present/data/prim_present_testplan.hjson" // Import additional common sim cfg files. - import_cfgs: ["{proj_root}/hw/dv/data/common_sim_cfg.hjson"] + import_cfgs: ["{proj_root}/hw/dv/tools/dvsim/common_sim_cfg.hjson"] // Default iterations for all tests - each test entry can override this. reseed: 50 @@ -39,15 +39,15 @@ // List of test specifications. tests: [ { - name: prim_present_sanity + name: prim_present_smoke } ] // List of regressions. regressions: [ { - name: sanity - tests: ["prim_present_sanity"] + name: smoke + tests: ["prim_present_smoke"] } ] } diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_present/tb/prim_present_tb.sv b/vendor/lowrisc_ip/ip/prim/dv/prim_present/tb/prim_present_tb.sv index cf0d556d5d..5fe738359c 100644 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_present/tb/prim_present_tb.sv +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_present/tb/prim_present_tb.sv @@ -40,7 +40,7 @@ module prim_present_tb; localparam bit Decrypt = 1'b1; // this parameter is required for the DPI model. - localparam KeySize80 = (KeyWidth == 80); + localparam bit KeySize80 = (KeyWidth == 80); ////////////////////////////////////////////////////// @@ -51,11 +51,18 @@ module prim_present_tb; // Same scheme used for key_in, data_out, key_out. logic [1:0][NumRounds-1:0][DataWidth-1:0] data_in; logic [1:0][NumRounds-1:0][KeyWidth-1 :0] key_in; + logic [1:0][NumRounds-1:0][4:0] idx_in; logic [1:0][NumRounds-1:0][DataWidth-1:0] data_out; logic [1:0][NumRounds-1:0][KeyWidth-1 :0] key_out; + logic [1:0][NumRounds-1:0][4:0] idx_out; for (genvar j = 0; j < 2; j++) begin : gen_encrypt_decrypt for (genvar k = 0; k < NumRounds; k++) begin : gen_duts + if (j == 0) begin : gen_encrypt + assign idx_in[j][k] = 5'd1; + end else begin : gen_decrypt + assign idx_in[j][k] = 5'(k+1); + end prim_present #( .DataWidth ( DataWidth ), .KeyWidth ( KeyWidth ), @@ -64,8 +71,10 @@ module prim_present_tb; ) dut ( .data_i ( data_in[j][k] ), .key_i ( key_in[j][k] ), + .idx_i ( idx_in[j][k] ), .data_o ( data_out[j][k] ), - .key_o ( key_out[j][k] ) + .key_o ( key_out[j][k] ), + .idx_o ( idx_out[j][k] ) ); end end @@ -77,8 +86,8 @@ module prim_present_tb; // Top level API task that should be called to run a full pass // of encryption and decryption on some input data and key. - task test_present(bit [DataWidth-1:0] plaintext, - bit [KeyWidth-1:0] key); + task automatic test_present(bit [DataWidth-1:0] plaintext, + bit [KeyWidth-1:0] key); bit [NumRounds:0][63:0] key_schedule; bit [NumRounds-1:0][DataWidth-1:0] encrypted_text; @@ -97,10 +106,10 @@ module prim_present_tb; // Helper task to drive plaintext and key into each encryption instance. // Calls a subroutine to perform checks on the outputs (once they are available). - task check_encryption(input bit [DataWidth-1:0] plaintext, - input bit [KeyWidth-1:0] key, - input bit [NumRounds:0][63:0] key_schedule, - output bit [NumRounds-1:0][DataWidth-1:0] expected_ciphertext); + task automatic check_encryption(input bit [DataWidth-1:0] plaintext, + input bit [KeyWidth-1:0] key, + input bit [NumRounds:0][63:0] key_schedule, + output bit [NumRounds-1:0][DataWidth-1:0] expected_ciphertext); // Drive input into encryption instances. for (int unsigned i = 0; i < NumRounds; i++) begin @@ -122,9 +131,9 @@ module prim_present_tb; // Helper task to drive ciphertext and key into each decryption instance. // Calls a subroutine to perform checks on the outputs (once they are available). - task check_decryption(input bit [NumRounds-1:0][DataWidth-1:0] ciphertext, - input bit [KeyWidth-1:0] key, - input bit [NumRounds-1:0][KeyWidth-1:0] decryption_keys); + task automatic check_decryption(input bit [NumRounds-1:0][DataWidth-1:0] ciphertext, + input bit [KeyWidth-1:0] key, + input bit [NumRounds-1:0][KeyWidth-1:0] decryption_keys); // the expected plaintext after decryption will be provided by the C model. bit [NumRounds-1:0][DataWidth-1:0] expected_plaintext; @@ -161,11 +170,11 @@ module prim_present_tb; // // If any comparison error is seen, this task short-circuits immediately, // printing out some debug information and the correct failure signature. - task check_output(input bit [NumRounds-1:0][63:0] expected_key, - input bit [NumRounds-1:0][DataWidth-1:0] expected_text, - input bit [NumRounds-1:0][KeyWidth-1:0] actual_key, - input bit [NumRounds-1:0][DataWidth-1:0] actual_data, - input string msg); + task automatic check_output(input bit [NumRounds-1:0][63:0] expected_key, + input bit [NumRounds-1:0][DataWidth-1:0] expected_text, + input bit [NumRounds-1:0][KeyWidth-1:0] actual_key, + input bit [NumRounds-1:0][DataWidth-1:0] actual_data, + input string msg); bit error = 1'b0; diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_prince/crypto_dpi_prince/crypto_dpi_prince.c b/vendor/lowrisc_ip/ip/prim/dv/prim_prince/crypto_dpi_prince/crypto_dpi_prince.c new file mode 100644 index 0000000000..fba3a5b4d2 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_prince/crypto_dpi_prince/crypto_dpi_prince.c @@ -0,0 +1,33 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifdef _cplusplus +extern "C" { +#endif + +#include +#include +#include + +#include "prince_ref.h" +#include "svdpi.h" + +extern uint64_t c_dpi_prince_encrypt(uint64_t plaintext, uint64_t key0, + uint64_t key1, int num_half_rounds, + int old_key_schedule) { + return prince_enc_dec_uint64(plaintext, key0, key1, 0, num_half_rounds, + old_key_schedule); +} + +extern uint64_t c_dpi_prince_decrypt(const uint64_t ciphertext, + const uint64_t key0, const uint64_t key1, + int num_half_rounds, + int old_key_schedule) { + return prince_enc_dec_uint64(ciphertext, key0, key1, 1, num_half_rounds, + old_key_schedule); +} + +#ifdef _cplusplus +} +#endif diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_prince/crypto_dpi_prince/crypto_dpi_prince.core b/vendor/lowrisc_ip/ip/prim/dv/prim_prince/crypto_dpi_prince/crypto_dpi_prince.core new file mode 100644 index 0000000000..4d83d81bb9 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_prince/crypto_dpi_prince/crypto_dpi_prince.core @@ -0,0 +1,17 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:dv:crypto_dpi_prince:0.1" +description: "PRINCE block cipher reference C implementation from Sebastien Riou" +filesets: + files_dv: + files: + - prince_ref.h: {file_type: cSource, is_include_file: true} + - crypto_dpi_prince.c: {file_type: cSource} + - crypto_dpi_prince_pkg.sv: {file_type: systemVerilogSource} + +targets: + default: + filesets: + - files_dv diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_prince/crypto_dpi_prince/crypto_dpi_prince_pkg.sv b/vendor/lowrisc_ip/ip/prim/dv/prim_prince/crypto_dpi_prince/crypto_dpi_prince_pkg.sv new file mode 100644 index 0000000000..9dd7940646 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_prince/crypto_dpi_prince/crypto_dpi_prince_pkg.sv @@ -0,0 +1,64 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +package crypto_dpi_prince_pkg; + + // dep packages + + // parameters + // Max number of half-rounds. + parameter int unsigned NumRoundsHalf = 5; + + // DPI-C imports + import "DPI-C" context function longint c_dpi_prince_encrypt( + input longint unsigned data, + input longint unsigned key0, + input longint unsigned key1, + input int unsigned num_half_rounds, + input int unsigned new_key_schedule + ); + + import "DPI-C" context function longint c_dpi_prince_decrypt( + input longint unsigned data, + input longint unsigned key0, + input longint unsigned key1, + input int unsigned num_half_rounds, + input int unsigned new_key_schedule + ); + + ////////////////////////////////////////////////////// + // SV wrapper functions to be used by the testbench // + ////////////////////////////////////////////////////// + + function automatic void sv_dpi_prince_encrypt( + input bit [63:0] plaintext, + input bit [127:0] key, + input bit old_key_schedule, + output bit [NumRoundsHalf-1:0][63:0] ciphertext + ); + for (int i = 0; i < NumRoundsHalf; i++) begin + ciphertext[i] = c_dpi_prince_encrypt(plaintext, + key[63:0], + key[127:64], + i+1, + old_key_schedule); + end + endfunction + + function automatic void sv_dpi_prince_decrypt( + input bit [NumRoundsHalf-1:0][63:0] ciphertext, + input bit [127:0] key, + input bit old_key_schedule, + output bit [NumRoundsHalf-1:0][63:0] plaintext + ); + for (int i = 0; i < NumRoundsHalf; i++) begin + plaintext[i] = c_dpi_prince_decrypt(ciphertext[i], + key[63:0], + key[127:64], + i+1, + old_key_schedule); + end + endfunction + +endpackage diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_prince/crypto_dpi_prince/prince_ref.h b/vendor/lowrisc_ip/ip/prim/dv/prim_prince/crypto_dpi_prince/prince_ref.h new file mode 100644 index 0000000000..bd99e3aad7 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_prince/crypto_dpi_prince/prince_ref.h @@ -0,0 +1,344 @@ +// Copyright lowRISC contributors. +// Copyright 2016 Sebastien Riou +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +/*! \file prince_ref.h + \brief Reference implementation of the Prince block cipher, complient to + C99. 'Reference' here means straightforward, unoptimized, and checked against + the few test vectors provided in the original paper + (http://eprint.iacr.org/2012/529.pdf). By defining the macro PRINCE_PRINT, + one can print out all successive internal states. +*/ + +/* + * This C-implementation of the PRINCE block cipher is taken from Sebastien + * Riou's open-sourced 'prince-c-ref' GitHub repository, found here: + * https://github.com/sebastien-riou/prince-c-ref/blob/master/include/prince_ref.h. + * + * Several modifications of varying severity have been made to this C model to + * enable extra external parameterizations for more thorough verification of the + * OpenTitan PRINCE hardware implementation. + * These modifications, in no particular order, are: + * + * - Conversion of `prince_enc_dec_uint64_t(...)` to a non-static function to + * allow usage by an external DPI-C model. + * - Additional arguments added to `prince_enc_dec_uint64_t(...)`, + * `prince_enc_dec(...)`, `prince_encrypt(...)` `prince_decrypt(...)`, and + * `prince_core(...)` to allow an external DPI-C model to control the + * number of cipher half-rounds and to toggle between the "legacy" key + * schedule detailed in the original PRINCE paper and a newer key schedule. + * - Modification of `prince_core(...)` to handle the new key schedule and + * user-specified number of half-rounds. + */ + +#ifndef OPENTITAN_HW_IP_PRIM_DV_PRIM_PRINCE_CRYPTO_DPI_PRINCE_PRINCE_REF_H_ +#define OPENTITAN_HW_IP_PRIM_DV_PRIM_PRINCE_CRYPTO_DPI_PRINCE_PRINCE_REF_H_ + +#include +#include + +#ifndef PRINCE_PRINT +#define PRINCE_PRINT(a) \ + do { \ + } while (0) +#endif + +/** + * Converts a byte array into a 64-bit integer. + * + * The byte at index 0 is placed as the most significant byte. + */ +static uint64_t bytes_to_uint64(const uint8_t in[8]) { + uint64_t out = 0; + unsigned int i; + for (i = 0; i < 8; i++) + out = (out << 8) | in[i]; + return out; +} + +/** + * Converts a 64-bit integer into a byte array. + * + * The most significant byte is placed at index 0. + */ +static void uint64_to_bytes(const uint64_t in, uint8_t out[8]) { + unsigned int i; + for (i = 0; i < 8; i++) + out[i] = in >> ((7 - i) * 8); +} + +/** + * Computes K0' from K0. + */ +static uint64_t prince_k0_to_k0_prime(const uint64_t k0) { + uint64_t k0_ror1 = (k0 >> 1) | (k0 << 63); + uint64_t k0_prime = k0_ror1 ^ (k0 >> 63); + return k0_prime; +} + +static uint64_t prince_round_constant(const unsigned int round) { + uint64_t rc[] = {UINT64_C(0x0000000000000000), UINT64_C(0x13198a2e03707344), + UINT64_C(0xa4093822299f31d0), UINT64_C(0x082efa98ec4e6c89), + UINT64_C(0x452821e638d01377), UINT64_C(0xbe5466cf34e90c6c), + UINT64_C(0x7ef84f78fd955cb1), UINT64_C(0x85840851f1ac43aa), + UINT64_C(0xc882d32f25323c54), UINT64_C(0x64a51195e0e3610d), + UINT64_C(0xd3b5a399ca0c2399), UINT64_C(0xc0ac29b7c97c50dd)}; + return rc[round]; +} + +/** + * The 4 bit Prince sbox. + * + * Only the 4 lsb are taken into account to preserve nibble granularity. + */ +static unsigned int prince_sbox(unsigned int nibble) { + const unsigned int sbox[] = {0xb, 0xf, 0x3, 0x2, 0xa, 0xc, 0x9, 0x1, + 0x6, 0x7, 0x8, 0x0, 0xe, 0x5, 0xd, 0x4}; + return sbox[nibble & 0xF]; +} + +/** + * The 4 bit Prince inverse sbox. + * + * Only the 4 lsb are taken into account to preserve nibble granularity. + */ +static unsigned int prince_sbox_inv(unsigned int nibble) { + const unsigned int sbox[] = {0xb, 0x7, 0x3, 0x2, 0xf, 0xd, 0x8, 0x9, + 0xa, 0x6, 0x4, 0x0, 0x5, 0xe, 0xc, 0x1}; + return sbox[nibble & 0xF]; +} + +/** + * The S step of the Prince cipher. + */ +static uint64_t prince_s_layer(const uint64_t s_in) { + uint64_t s_out = 0; + for (unsigned int i = 0; i < 16; i++) { + const unsigned int shift = i * 4; + const unsigned int sbox_in = s_in >> shift; + const uint64_t sbox_out = prince_sbox(sbox_in); + s_out |= sbox_out << shift; + } + return s_out; +} + +/** + * The S^-1 step of the Prince cipher. + */ +static uint64_t prince_s_inv_layer(const uint64_t s_inv_in) { + uint64_t s_inv_out = 0; + for (unsigned int i = 0; i < 16; i++) { + const unsigned int shift = i * 4; + const unsigned int sbox_in = s_inv_in >> shift; + const uint64_t sbox_out = prince_sbox_inv(sbox_in); + s_inv_out |= sbox_out << shift; + } + return s_inv_out; +} + +static uint64_t gf2_mat_mult16_1(const uint64_t in, const uint64_t mat[16]) { + uint64_t out = 0; + for (unsigned int i = 0; i < 16; i++) { + if ((in >> i) & 1) + out ^= mat[i]; + } + return out; +} + +/** + * Build Prince's 16 bit matrices M0 and M1. + */ +static void prince_m16_matrices(uint64_t m16[2][16]) { + // 4 bits matrices m0 to m3 are stored in array m4 + const uint64_t m4[4][4] = {// m0 + {0x0, 0x2, 0x4, 0x8}, + // m1 + {0x1, 0x0, 0x4, 0x8}, + // m2 + {0x1, 0x2, 0x0, 0x8}, + // m3 + {0x1, 0x2, 0x4, 0x0}}; + // build 16 bits matrices + for (unsigned int i = 0; i < 16; i++) { + const unsigned int base = i / 4; + m16[0][i] = + (m4[(base + 3) % 4][i % 4] << 8) | (m4[(base + 2) % 4][i % 4] << 4) | + (m4[(base + 1) % 4][i % 4] << 0) | (m4[(base + 0) % 4][i % 4] << 12); + m16[1][i] = + (m16[0][i] >> 12) | + (0xFFFF & (m16[0][i] << 4)); // m1 is just a rotated version of m0 + } +} + +/** + * The M' step of the Prince cipher. + */ +static uint64_t prince_m_prime_layer(const uint64_t m_prime_in) { + // 16 bits matrices M0 and M1, generated using the code below + // uint64_t m16[2][16];prince_m16_matrices(m16); + // for(unsigned int i=0;i<16;i++) PRINCE_PRINT(m16[0][i]); + // for(unsigned int i=0;i<16;i++) PRINCE_PRINT(m16[1][i]); + static const uint64_t m16[2][16] = { + {0x0111, 0x2220, 0x4404, 0x8088, 0x1011, 0x0222, 0x4440, 0x8808, 0x1101, + 0x2022, 0x0444, 0x8880, 0x1110, 0x2202, 0x4044, 0x0888}, + + {0x1110, 0x2202, 0x4044, 0x0888, 0x0111, 0x2220, 0x4404, 0x8088, 0x1011, + 0x0222, 0x4440, 0x8808, 0x1101, 0x2022, 0x0444, 0x8880}}; + const uint64_t chunk0 = gf2_mat_mult16_1(m_prime_in >> (0 * 16), m16[0]); + const uint64_t chunk1 = gf2_mat_mult16_1(m_prime_in >> (1 * 16), m16[1]); + const uint64_t chunk2 = gf2_mat_mult16_1(m_prime_in >> (2 * 16), m16[1]); + const uint64_t chunk3 = gf2_mat_mult16_1(m_prime_in >> (3 * 16), m16[0]); + const uint64_t m_prime_out = (chunk3 << (3 * 16)) | (chunk2 << (2 * 16)) | + (chunk1 << (1 * 16)) | (chunk0 << (0 * 16)); + return m_prime_out; +} + +/** + * The shift row and inverse shift row of the Prince cipher. + */ +static uint64_t prince_shift_rows(const uint64_t in, int inverse) { + const uint64_t row_mask = UINT64_C(0xF000F000F000F000); + uint64_t shift_rows_out = 0; + for (unsigned int i = 0; i < 4; i++) { + const uint64_t row = in & (row_mask >> (4 * i)); + const unsigned int shift = inverse ? i * 16 : 64 - i * 16; + shift_rows_out |= (row >> shift) | (row << (64 - shift)); + } + return shift_rows_out; +} + +/** + * The M step of the Prince cipher. + */ +static uint64_t prince_m_layer(const uint64_t m_in) { + const uint64_t m_prime_out = prince_m_prime_layer(m_in); + const uint64_t shift_rows_out = prince_shift_rows(m_prime_out, 0); + return shift_rows_out; +} + +/** + * The M^-1 step of the Prince cipher. + */ +static uint64_t prince_m_inv_layer(const uint64_t m_inv_in) { + const uint64_t shift_rows_out = prince_shift_rows(m_inv_in, 1); + const uint64_t m_prime_out = prince_m_prime_layer(shift_rows_out); + return m_prime_out; +} + +/** + * The core function of the Prince cipher. + */ +static uint64_t prince_core(const uint64_t core_input, const uint64_t k0_new, + const uint64_t k1, int num_half_rounds) { + PRINCE_PRINT(core_input); + PRINCE_PRINT(k1); + uint64_t round_input = core_input ^ k1 ^ prince_round_constant(0); + for (unsigned int round = 1; round <= num_half_rounds; round++) { + PRINCE_PRINT(round_input); + const uint64_t s_out = prince_s_layer(round_input); + PRINCE_PRINT(s_out); + const uint64_t m_out = prince_m_layer(s_out); + PRINCE_PRINT(m_out); + round_input = (round % 2 == 1) + ? m_out ^ k0_new ^ prince_round_constant(round) + : m_out ^ k1 ^ prince_round_constant(round); + } + const uint64_t middle_round_s_out = prince_s_layer(round_input); + PRINCE_PRINT(middle_round_s_out); + const uint64_t m_prime_out = prince_m_prime_layer(middle_round_s_out); + PRINCE_PRINT(m_prime_out); + const uint64_t middle_round_s_inv_out = prince_s_inv_layer(m_prime_out); + round_input = middle_round_s_inv_out; + // for(unsigned int round = 6; round < num_half_rounds * 2 + 1; round ++){ + for (unsigned int round = 1; round <= num_half_rounds; round++) { + PRINCE_PRINT(round_input); + const uint64_t constant_idx = 10 - num_half_rounds + round; + const uint64_t m_inv_in = + ((num_half_rounds + round + 1) % 2 == 1) + ? round_input ^ k0_new ^ prince_round_constant(constant_idx) + : round_input ^ k1 ^ prince_round_constant(constant_idx); + PRINCE_PRINT(m_inv_in); + const uint64_t s_inv_in = prince_m_inv_layer(m_inv_in); + PRINCE_PRINT(s_inv_in); + const uint64_t s_inv_out = prince_s_inv_layer(s_inv_in); + round_input = s_inv_out; + } + const uint64_t core_output = round_input ^ k1 ^ prince_round_constant(11); + PRINCE_PRINT(core_output); + return core_output; +} + +/** + * Top level function for Prince encryption/decryption. + * + * enc_k0 and enc_k1 must be the same for encryption and decryption. + * The handling of decryption is done internally. + */ +uint64_t prince_enc_dec_uint64(const uint64_t input, const uint64_t enc_k0, + const uint64_t enc_k1, int decrypt, + int num_half_rounds, int old_key_schedule) { + const uint64_t prince_alpha = UINT64_C(0xc0ac29b7c97c50dd); + const uint64_t k1 = enc_k1 ^ (decrypt ? prince_alpha : 0); + const uint64_t k0_new = + (old_key_schedule) ? k1 : enc_k0 ^ (decrypt ? prince_alpha : 0); + const uint64_t enc_k0_prime = prince_k0_to_k0_prime(enc_k0); + const uint64_t k0 = decrypt ? enc_k0_prime : enc_k0; + const uint64_t k0_prime = decrypt ? enc_k0 : enc_k0_prime; + PRINCE_PRINT(k0); + PRINCE_PRINT(input); + const uint64_t core_input = input ^ k0; + const uint64_t core_output = + prince_core(core_input, k0_new, k1, num_half_rounds); + const uint64_t output = core_output ^ k0_prime; + PRINCE_PRINT(k0_prime); + PRINCE_PRINT(output); + return output; +} + +/** + * Byte oriented top level function for Prince encryption/decryption. + * + * key_bytes 0 to 7 must contain K0. + * key_bytes 8 to 15 must contain K1. + */ +static void prince_enc_dec(const uint8_t in_bytes[8], + const uint8_t key_bytes[16], uint8_t out_bytes[8], + int decrypt, int num_half_rounds, + int old_key_schedule) { + const uint64_t input = bytes_to_uint64(in_bytes); + const uint64_t enc_k0 = bytes_to_uint64(key_bytes); + const uint64_t enc_k1 = bytes_to_uint64(key_bytes + 8); + const uint64_t output = prince_enc_dec_uint64( + input, enc_k0, enc_k1, decrypt, num_half_rounds, old_key_schedule); + uint64_to_bytes(output, out_bytes); +} + +/** + * Byte oriented top level function for Prince encryption. + * + * key_bytes 0 to 7 must contain K0. + * key_bytes 8 to 15 must contain K1. + */ +static void prince_encrypt(const uint8_t in_bytes[8], + const uint8_t key_bytes[16], uint8_t out_bytes[8], + int num_half_rounds, int old_key_schedule) { + prince_enc_dec(in_bytes, key_bytes, out_bytes, 0, num_half_rounds, + old_key_schedule); +} + +/** + * Byte oriented top level function for Prince decryption. + * + * key_bytes 0 to 7 must contain K0. + * key_bytes 8 to 15 must contain K1. + */ +static void prince_decrypt(const uint8_t in_bytes[8], + const uint8_t key_bytes[16], uint8_t out_bytes[8], + int num_half_rounds, int old_key_schedule) { + prince_enc_dec(in_bytes, key_bytes, out_bytes, 1, num_half_rounds, + old_key_schedule); + uint64_t m16[2][16]; +} + +#endif // OPENTITAN_HW_IP_PRIM_DV_PRIM_PRINCE_CRYPTO_DPI_PRINCE_PRINCE_REF_H_ diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_prince/data/prim_prince_cover.cfg b/vendor/lowrisc_ip/ip/prim/dv/prim_prince/data/prim_prince_cover.cfg new file mode 100644 index 0000000000..574da3b3fb --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_prince/data/prim_prince_cover.cfg @@ -0,0 +1,11 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Enables coverage just only each of the prim_prince instances. +// Limits toggle coverage to DUT IOs. + ++module prim_prince +begin tgl(portsonly) + +module prim_prince +end diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_prince/prim_prince_sim.core b/vendor/lowrisc_ip/ip/prim/dv/prim_prince/prim_prince_sim.core new file mode 100644 index 0000000000..02c6e82173 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_prince/prim_prince_sim.core @@ -0,0 +1,31 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:dv:prim_prince_sim:0.1" +description: "PRINCE block cipher DV sim target" +filesets: + files_rtl: + depend: + - lowrisc:prim:all + file_type: systemVerilogSource + + files_dv: + depend: + - lowrisc:dv:crypto_dpi_prince:0.1 + - lowrisc:dv:dv_utils + - lowrisc:dv:common_ifs + files: + - tb/prim_prince_tb.sv + file_type: systemVerilogSource + +targets: + sim: &sim_target + toplevel: prim_prince_tb + filesets: + - files_rtl + - files_dv + default_tool: vcs + + lint: + <<: *sim_target diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_prince/prim_prince_sim_cfg.hjson b/vendor/lowrisc_ip/ip/prim/dv/prim_prince/prim_prince_sim_cfg.hjson new file mode 100644 index 0000000000..9240a16513 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_prince/prim_prince_sim_cfg.hjson @@ -0,0 +1,57 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +{ + // Name of the sim cfg - typically same as the name of the DUT. + name: prim_prince + + // Top level dut name (sv module). + dut: prim_prince + + // Top level testbench name (sv module). + tb: prim_prince_tb + + // Simulator used to sign off this block + tool: vcs + + // Fusesoc core file used for building the file list. + fusesoc_core: lowrisc:dv:prim_prince_sim:0.1 + + // Import additional common sim cfg files. + import_cfgs: ["{proj_root}/hw/dv/tools/dvsim/common_sim_cfg.hjson"] + + // Default iterations for all tests - each test entry can override this. + reseed: 50 + + tool_srcs: ["{proj_root}/hw/ip/prim/dv/prim_prince/data/prim_prince_cover.cfg"] + + overrides: [ + { + name: vcs_cov_cfg_file + value: "-cm_hier {tool_srcs_dir}/prim_prince_cover.cfg" + } + ] + + // List of test specifications. + tests: [ + { + name: prim_prince_test + } + ] + + // List of regressions. + regressions: [ + { + name: smoke + tests: ["prim_prince_test"] + } + { + name: nightly + // Run the same test as the "smoke" regression, just with a higher reseed value. + // This higher reseed value is due to the rather large state space created by + // the 128-bit key and 64-bit data values. + reseed: 500 + } + ] +} + diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_prince/tb/prim_prince_tb.sv b/vendor/lowrisc_ip/ip/prim/dv/prim_prince/tb/prim_prince_tb.sv new file mode 100644 index 0000000000..4d588f2465 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_prince/tb/prim_prince_tb.sv @@ -0,0 +1,297 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Testbench module for prim_prince, drives various test vectors into all +// implementations and compares intermediate and final output against +// C-reference model, for both encryption and decryption. +// +// This testbench only tests the PRINCE block cipher in its 64-bit data +// and 128-bit key configuration, other configurations with different sets of +// widths remain untested. + +module prim_prince_tb; + +////////////////////////////////////////////////////// +// config +////////////////////////////////////////////////////// + +// Default to {data_width:64, key_width:128} configuration. +// Data width and key width can be overriden from command-line if desired. + +`ifdef DATA_WIDTH + localparam int unsigned DataWidth = `DATA_WIDTH; +`else + localparam int unsigned DataWidth = 64; +`endif + +`ifdef KEY_WIDTH + localparam int unsigned KeyWidth = `KEY_WIDTH; +`else + localparam int unsigned KeyWidth = 128; +`endif + + // Max number of half-rounds according to spec. + // Duplicate parameter definition here to avoid clutter due to long identifier. + localparam int unsigned NumRoundsHalf = crypto_dpi_prince_pkg::NumRoundsHalf; + + // Use these to index the data/key arrays. + localparam bit Unregistered = 1'b0; + localparam bit Registered = 1'b1; + + localparam bit NewKeySched = 1'b0; + localparam bit OldKeySched = 1'b1; + + localparam time ClkPeriod = 10000; + +////////////////////////////////////////////////////// +// Clock interface +////////////////////////////////////////////////////// + + wire clk, rst_n; + + clk_rst_if clk_if ( + .clk, + .rst_n + ); + +////////////////////////////////////////////////////// +// DUTs for both encryption and decryption +////////////////////////////////////////////////////// + + logic [1:0][1:0][NumRoundsHalf-1:0][DataWidth-1:0] data_in; + logic [1:0][1:0][NumRoundsHalf-1:0][DataWidth-1:0] data_out; + logic [1:0][1:0][NumRoundsHalf-1:0] valid_out; + logic valid_in; + logic [KeyWidth-1:0] key_in; + logic dec_in; + + for (genvar i = 0; i < 2; i++) begin : gen_new_key_schedule + for (genvar j = 0; j < 2; j++) begin : gen_registered_variant + for (genvar k = 0; k < NumRoundsHalf; k++) begin : gen_duts + prim_prince #( + .DataWidth ( DataWidth ), + .KeyWidth ( KeyWidth ), + .NumRoundsHalf ( k+1 ), + .UseOldKeySched ( i ), + .HalfwayDataReg ( j ), + .HalfwayKeyReg ( j ) + ) dut ( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .valid_i ( valid_in ), + .data_i ( data_in[i][j][k] ), + .key_i ( key_in ), + .dec_i ( dec_in ), + .valid_o ( valid_out[i][j][k] ), + .data_o ( data_out[i][j][k] ) + ); + end : gen_duts + end : gen_registered_variant + end : gen_new_key_schedule + +////////////////////////////////////////////////////// +// API called by the testbench to drive/check stimulus +////////////////////////////////////////////////////// + + // Top level API task that should be called to run a full pass + // of encryption and decryption on some input data and key. + task automatic test_prince(bit [DataWidth-1:0] plaintext, + bit [KeyWidth-1:0] key); + + bit [1:0][1:0][NumRoundsHalf-1:0][DataWidth-1:0] encrypted_text; + $display("Starting encryption with data[0x%0x] and key[0x%0x]!", plaintext, key); + check_encryption(plaintext, key, encrypted_text); + $display("Starting decryption pass!"); + check_decryption(encrypted_text, key); + + endtask + + + + // Helper task to drive plaintext and key into each encryption instance. + // Calls a subroutine to perform checks on the outputs (once they are available). + task automatic check_encryption( + input bit [DataWidth-1:0] plaintext, + input bit [KeyWidth-1:0] key, + output bit [1:0][1:0][NumRoundsHalf-1:0][DataWidth-1:0] expected_cipher); + + // Drive input into encryption instances. + key_in = key; + dec_in = 0; + valid_in = 1; + for (int unsigned i = 0; i < 2; i++) begin + for (int unsigned j = 0; j < 2; j++) begin + for (int unsigned k = 0; k < NumRoundsHalf; k++) begin + data_in[i][j][k] = plaintext; + end + end + end + // Wait for the DUTs to finish calculations. + clk_if.wait_clks(2); + wait(&valid_out == 1); + valid_in = 0; + // query DPI model for expected encrypted output. + for (int i = 0; i < 2; i++) begin + for (int j = 0; j < 2; j++) begin + crypto_dpi_prince_pkg::sv_dpi_prince_encrypt(plaintext, key, i, + expected_cipher[i][j]); + end + end + check_output(expected_cipher[OldKeySched], + expected_cipher[NewKeySched], + data_out[OldKeySched], + data_out[NewKeySched], + "Encryption"); + endtask + + + // Helper task to drive ciphertext and key into each decryption instance. + // Calls a subroutine to perform checks on the outputs (once they are available). + task automatic check_decryption( + input bit [1:0][1:0][NumRoundsHalf-1:0][DataWidth-1:0] ciphertext, + input bit [KeyWidth-1:0] key); + + // the expected plaintext after decryption will be provided by the C model. + bit [1:0][1:0][NumRoundsHalf-1:0][DataWidth-1:0] expected_plaintext; + // Drive input into decryption instances. + key_in = key; + dec_in = 1; + valid_in = 1; + for (int unsigned i = 0; i < 2; i++) begin + for (int unsigned j = 0; j < 2; j++) begin + for (int unsigned k = 0; k < NumRoundsHalf; k++) begin + data_in[i][j][k] = ciphertext[i][j][k]; + end + end + end + // Wait for the DUTs to finish calculations. + clk_if.wait_clks(2); + wait(&valid_out == 1); + valid_in = 0; + // query DPI model for expected decrypted output. + for (int unsigned i = 0; i < 2; i++) begin + for (int unsigned j = 0; j < 2; j++) begin + crypto_dpi_prince_pkg::sv_dpi_prince_decrypt(ciphertext[i][j], key, i, + expected_plaintext[i][j]); + end + end + check_output(expected_plaintext[OldKeySched], + expected_plaintext[NewKeySched], + data_out[OldKeySched], + data_out[NewKeySched], + "Decryption"); + endtask + + + // Helper subroutine to compare key and data output values from + // the C-reference model and the DUTs. + // + // For each instance of PRINCE (whether using old or new key schedule), + // we need to check that the output data matches the output of the reference model. + // + // If any comparison error is seen, this task short-circuits immediately, + // printing out some debug information and the correct failure signature. + task automatic check_output( + input bit [1:0][NumRoundsHalf-1:0][DataWidth-1:0] expected_text_old_sched, + input bit [1:0][NumRoundsHalf-1:0][DataWidth-1:0] expected_text_new_sched, + input bit [1:0][NumRoundsHalf-1:0][DataWidth-1:0] actual_text_old_sched, + input bit [1:0][NumRoundsHalf-1:0][DataWidth-1:0] actual_text_new_sched, + input string msg); + + string reg_msg; + string err_msg; + for (int unsigned i = 0; i < 2; i++) begin + reg_msg = i ? "registered" : "unregistered"; + for (int unsigned j = 0; j < NumRoundsHalf; j++) begin + // compare outputs generated using old key schedule. + if (expected_text_old_sched[i][j] != actual_text_old_sched[i][j]) begin + err_msg = {$sformatf("%s mismatch in %s design with %0d rounds and old key schedule!\n", + msg, reg_msg, i+1), + $sformatf("Expected[0x%0x] - Actual[0x%0x]\n", expected_text_old_sched[i][j], + actual_text_old_sched[i][j]), + "TEST FAILED CHECKS"}; + $fatal(err_msg); + end + // compare outputs generated using new key schedule. + if (expected_text_new_sched[i][j] != actual_text_new_sched[i][j]) begin + err_msg = {$sformatf("%s mismatch in %s design with %0d rounds and old key schedule!\n", + msg, reg_msg, i+1), + $sformatf("Expected[0x%0x] - Actual[0x%0x]\n", expected_text_new_sched[i][j], + actual_text_new_sched[i][j]), + "TEST FAILED CHECKS"}; + $fatal(err_msg); + end + end + end + endtask + + +////////////////////////////////////////////////////// +// main testbench body +////////////////////////////////////////////////////// + + initial begin : p_stimuli + + // The key and plaintext/ciphertext to be fed into PRINCE instances. + bit [KeyWidth/2-1:0] k0, k1; + bit [DataWidth-1:0] plaintext; + + clk_if.set_period_ns(ClkPeriod); + clk_if.set_active(); + clk_if.apply_reset(); + $timeformat(-12, 0, " ps", 12); + clk_if.wait_clks(10); + + ///////////////////////////// + // Test the 5 golden vectors. + ///////////////////////////// + + plaintext = '0; + k0 = '1; + k1 = '0; + test_prince(plaintext, {k1, k0}); + + plaintext = '0; + k0 = '0; + k1 = '0; + test_prince(plaintext, {k1, k0}); + + plaintext = '1; + k0 = '0; + k1 = '0; + test_prince(plaintext, {k1, k0}); + + plaintext = '0; + k0 = '0; + k1 = '1; + test_prince(plaintext, {k1, k0}); + + plaintext = 'h0123456789ABCDEF; + k0 = '0; + k1 = 'hFEDC_BA98_7654_3210; + test_prince(plaintext, {k1, k0}); + + // Test random vectors + for (int i = 0; i < 25000; i++) begin + if (!std::randomize(plaintext)) begin + $fatal("Randomization of plaintext failed!"); + end + if (!std::randomize(k0)) begin + $fatal("Randomization of k0 failed!"); + end + if (!std::randomize(k1)) begin + $fatal("Randomization of k1 failed!"); + end + test_prince(plaintext, {k1, k0}); + end + + + // Final error checking and print out the test signature (expected by simulation flow). + $display("All encryption and decryption passes were successful!"); + $display("TEST PASSED CHECKS"); + $finish(); + end + + +endmodule : prim_prince_tb diff --git a/vendor/lowrisc_ip/ip/prim/fpv/prim_alert_rxtx_async_fpv.core b/vendor/lowrisc_ip/ip/prim/fpv/prim_alert_rxtx_async_fpv.core index 3189f81250..36569b6a8d 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/prim_alert_rxtx_async_fpv.core +++ b/vendor/lowrisc_ip/ip/prim/fpv/prim_alert_rxtx_async_fpv.core @@ -26,3 +26,6 @@ targets: formal: <<: *default_target + + lint: + <<: *default_target diff --git a/vendor/lowrisc_ip/ip/prim/fpv/prim_alert_rxtx_fpv.core b/vendor/lowrisc_ip/ip/prim/fpv/prim_alert_rxtx_fpv.core index 492fa28ea8..55b36fc4e0 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/prim_alert_rxtx_fpv.core +++ b/vendor/lowrisc_ip/ip/prim/fpv/prim_alert_rxtx_fpv.core @@ -26,3 +26,6 @@ targets: formal: <<: *default_target + + lint: + <<: *default_target diff --git a/vendor/lowrisc_ip/ip/prim/fpv/prim_arbiter_fixed_fpv.core b/vendor/lowrisc_ip/ip/prim/fpv/prim_arbiter_fixed_fpv.core index 4264fee9da..4b3359b652 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/prim_arbiter_fixed_fpv.core +++ b/vendor/lowrisc_ip/ip/prim/fpv/prim_arbiter_fixed_fpv.core @@ -23,3 +23,6 @@ targets: formal: <<: *default_target + + lint: + <<: *default_target diff --git a/vendor/lowrisc_ip/ip/prim/fpv/prim_arbiter_ppc_fpv.core b/vendor/lowrisc_ip/ip/prim/fpv/prim_arbiter_ppc_fpv.core index 9fba5d08c0..aad283072d 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/prim_arbiter_ppc_fpv.core +++ b/vendor/lowrisc_ip/ip/prim/fpv/prim_arbiter_ppc_fpv.core @@ -23,3 +23,6 @@ targets: formal: <<: *default_target + + lint: + <<: *default_target diff --git a/vendor/lowrisc_ip/ip/prim/fpv/prim_arbiter_tree_fpv.core b/vendor/lowrisc_ip/ip/prim/fpv/prim_arbiter_tree_fpv.core index 7c84d8d592..72abea8f6f 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/prim_arbiter_tree_fpv.core +++ b/vendor/lowrisc_ip/ip/prim/fpv/prim_arbiter_tree_fpv.core @@ -23,3 +23,6 @@ targets: formal: <<: *default_target + + lint: + <<: *default_target diff --git a/vendor/lowrisc_ip/ip/prim/fpv/prim_esc_rxtx_fpv.core b/vendor/lowrisc_ip/ip/prim/fpv/prim_esc_rxtx_fpv.core index d3f4bf7e93..3aa4c5a7bd 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/prim_esc_rxtx_fpv.core +++ b/vendor/lowrisc_ip/ip/prim/fpv/prim_esc_rxtx_fpv.core @@ -26,3 +26,6 @@ targets: formal: <<: *default_target + + lint: + <<: *default_target diff --git a/vendor/lowrisc_ip/ip/prim/fpv/prim_fifo_sync_fpv.core b/vendor/lowrisc_ip/ip/prim/fpv/prim_fifo_sync_fpv.core index 00dd74f1a3..79bb7fa856 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/prim_fifo_sync_fpv.core +++ b/vendor/lowrisc_ip/ip/prim/fpv/prim_fifo_sync_fpv.core @@ -25,3 +25,6 @@ targets: formal: <<: *default_target + + lint: + <<: *default_target diff --git a/vendor/lowrisc_ip/ip/prim/fpv/prim_keccak_fpv.core b/vendor/lowrisc_ip/ip/prim/fpv/prim_keccak_fpv.core index 348342f5a0..13a45416e1 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/prim_keccak_fpv.core +++ b/vendor/lowrisc_ip/ip/prim/fpv/prim_keccak_fpv.core @@ -13,7 +13,7 @@ filesets: file_type: systemVerilogSource targets: - default: + default: &default_target # note, this setting is just used # to generate a file list for jg default_tool: icarus @@ -21,3 +21,6 @@ targets: - files_fpv toplevel: - prim_keccak_fpv + + lint: + <<: *default_target diff --git a/vendor/lowrisc_ip/ip/prim/fpv/prim_lfsr_fpv.core b/vendor/lowrisc_ip/ip/prim/fpv/prim_lfsr_fpv.core index 3bdba9e528..394d30666d 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/prim_lfsr_fpv.core +++ b/vendor/lowrisc_ip/ip/prim/fpv/prim_lfsr_fpv.core @@ -24,3 +24,6 @@ targets: formal: <<: *default_target + + lint: + <<: *default_target diff --git a/vendor/lowrisc_ip/ip/prim/fpv/prim_packer_fpv.core b/vendor/lowrisc_ip/ip/prim/fpv/prim_packer_fpv.core new file mode 100644 index 0000000000..c1f882b2fc --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/prim_packer_fpv.core @@ -0,0 +1,30 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +name: "lowrisc:fpv:prim_packer_fpv" +description: "formal Testbench for prim_packer" +filesets: + files_formal: + depend: + - lowrisc:prim:all + files: + - ../rtl/prim_packer.sv + - tb/prim_packer_fpv.sv + file_type: systemVerilogSource + +targets: + default: &default_target + # note, this setting is just used + # to generate a file list for jg + default_tool: icarus + filesets: + - files_formal + toplevel: prim_packer_fpv + + formal: + <<: *default_target + + lint: + <<: *default_target diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_bind_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_bind_fpv.sv index 295da5d610..6e96ee6a2d 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_bind_fpv.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_bind_fpv.sv @@ -18,8 +18,9 @@ module prim_alert_rxtx_async_bind_fpv; .alert_err_pi, .alert_err_ni, .alert_skew_i, - .alert_i, - .ping_en_i, + .alert_req_i, + .alert_ack_o, + .ping_req_i, .ping_ok_o, .integ_fail_o, .alert_o diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_fpv.sv index f4bed9a96c..786345fd30 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_fpv.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_fpv.sv @@ -22,8 +22,9 @@ module prim_alert_rxtx_async_fpv input alert_err_ni, input [1:0] alert_skew_i, // normal I/Os - input alert_i, - input ping_en_i, + input alert_req_i, + input ping_req_i, + output logic alert_ack_o, output logic ping_ok_o, output logic integ_fail_o, output logic alert_o @@ -68,9 +69,10 @@ module prim_alert_rxtx_async_fpv prim_alert_sender #( .AsyncOn ( AsyncOn ) ) i_prim_alert_sender ( - .clk_i , - .rst_ni , - .alert_i , + .clk_i , + .rst_ni , + .alert_req_i, + .alert_ack_o, .alert_rx_i ( alert_rx_in ), .alert_tx_o ( alert_tx_out ) ); @@ -80,7 +82,7 @@ module prim_alert_rxtx_async_fpv ) i_prim_alert_receiver ( .clk_i , .rst_ni , - .ping_en_i , + .ping_req_i , .ping_ok_o , .integ_fail_o , .alert_o , diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_bind_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_bind_fpv.sv index 9158997007..18071d1b7b 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_bind_fpv.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_bind_fpv.sv @@ -15,8 +15,9 @@ module prim_alert_rxtx_bind_fpv; .ack_err_ni, .alert_err_pi, .alert_err_ni, - .alert_i, - .ping_en_i, + .alert_req_i, + .alert_ack_o, + .ping_req_i, .ping_ok_o, .integ_fail_o, .alert_o diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_fpv.sv index 98e9fe6c64..a202340018 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_fpv.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_fpv.sv @@ -19,8 +19,9 @@ module prim_alert_rxtx_fpv input alert_err_pi, input alert_err_ni, // normal I/Os - input alert_i, - input ping_en_i, + input alert_req_i, + input ping_req_i, + output logic alert_ack_o, output logic ping_ok_o, output logic integ_fail_o, output logic alert_o @@ -43,9 +44,10 @@ module prim_alert_rxtx_fpv prim_alert_sender #( .AsyncOn ( AsyncOn ) ) i_prim_alert_sender ( - .clk_i , - .rst_ni , - .alert_i , + .clk_i , + .rst_ni , + .alert_req_i, + .alert_ack_o, .alert_rx_i ( alert_rx_in ), .alert_tx_o ( alert_tx_out ) ); @@ -55,7 +57,7 @@ module prim_alert_rxtx_fpv ) i_prim_alert_receiver ( .clk_i , .rst_ni , - .ping_en_i , + .ping_req_i , .ping_ok_o , .integ_fail_o , .alert_o , diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_esc_rxtx_bind_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_esc_rxtx_bind_fpv.sv index def9f1f0b6..1657b8de35 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_esc_rxtx_bind_fpv.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_esc_rxtx_bind_fpv.sv @@ -13,8 +13,8 @@ module prim_esc_rxtx_bind_fpv; .resp_err_ni , .esc_err_pi , .esc_err_ni , - .esc_en_i , - .ping_en_i , + .esc_req_i , + .ping_req_i , .ping_ok_o , .integ_fail_o, .esc_en_o diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_esc_rxtx_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_esc_rxtx_fpv.sv index 492bac3687..11a9972f6a 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_esc_rxtx_fpv.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_esc_rxtx_fpv.sv @@ -17,8 +17,8 @@ module prim_esc_rxtx_fpv input esc_err_pi, input esc_err_ni, // normal I/Os - input esc_en_i, - input ping_en_i, + input esc_req_i, + input ping_req_i, output logic ping_ok_o, output logic integ_fail_o, output logic esc_en_o @@ -35,10 +35,10 @@ module prim_esc_rxtx_fpv prim_esc_sender i_prim_esc_sender ( .clk_i , .rst_ni , - .ping_en_i , + .ping_req_i , .ping_ok_o , .integ_fail_o , - .esc_en_i , + .esc_req_i , .esc_rx_i ( esc_rx_in ), .esc_tx_o ( esc_tx_out ) ); diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_packer_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_packer_fpv.sv new file mode 100644 index 0000000000..4753199f8e --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_packer_fpv.sv @@ -0,0 +1,63 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Testbench module for prim_packer. Intended to be used with a formal tool. +// To reduce the runtime for prim_packer, we limited the width parameter. + +module prim_packer_fpv #( + parameter int unsigned MaxInW = 64, + parameter int unsigned MaxOutW = 64 +) ( + input clk_i , + input rst_ni, + + input valid_i, + input [MaxInW-1:0] data_i, + input [MaxInW-1:0] mask_i, + output ready_o, + + output logic valid_o, + output logic [MaxOutW-1:0] data_o, + output logic [MaxOutW-1:0] mask_o, + input ready_i, + + input flush_i, + output logic flush_done_o +); + + for (genvar k = 1; k <= 16; k++) begin : gen_prim_packer + prim_packer #(.InW(k), .OutW(17-k) + ) i_prim_packer ( + .clk_i, + .rst_ni, + .valid_i, + .data_i (data_i[k-1:0]), + .mask_i (mask_i[k-1:0]), + .ready_o, + .valid_o, + .data_o (data_o[16-k:0]), + .mask_o (mask_o[16-k:0]), + .ready_i, + .flush_i, + .flush_done_o + ); + end + + prim_packer #(.InW(MaxInW), .OutW(MaxOutW) + ) i_prim_packer_max ( + .clk_i, + .rst_ni, + .valid_i, + .data_i (data_i), + .mask_i (mask_i), + .ready_o, + .valid_o, + .data_o (data_o), + .mask_o (mask_o), + .ready_i, + .flush_i, + .flush_done_o + ); + +endmodule : prim_packer_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_alert_rxtx_assert_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_alert_rxtx_assert_fpv.sv index f5684c305c..70cfd6a6cd 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_alert_rxtx_assert_fpv.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_alert_rxtx_assert_fpv.sv @@ -18,8 +18,9 @@ module prim_alert_rxtx_assert_fpv ( input alert_err_pi, input alert_err_ni, // normal I/Os - input alert_i, - input ping_en_i, + input alert_req_i, + input alert_ack_o, + input ping_req_i, input ping_ok_o, input integ_fail_o, input alert_o @@ -37,10 +38,10 @@ module prim_alert_rxtx_assert_fpv ( // ping will stay high until ping ok received, then it must be deasserted // TODO: this excludes the case where no ping ok will be returned due to an error - `ASSUME_FPV(PingDeassert_M, ping_en_i && ping_ok_o |=> !ping_en_i, clk_i, !rst_ni) - `ASSUME_FPV(PingEnStaysAsserted0_M, ping_en_i |=> (ping_en_i && !ping_ok_o) or - (ping_en_i && ping_ok_o ##1 $fell(ping_en_i)), clk_i, !rst_ni || error_present) - + `ASSUME_FPV(PingDeassert_M, ping_req_i && ping_ok_o |=> !ping_req_i, clk_i, !rst_ni) + `ASSUME_FPV(PingEn_M, $rose(ping_req_i) |-> ping_req_i throughout + (ping_ok_o || error_present)[->1] ##1 $fell(ping_req_i), + clk_i, !rst_ni) sequence FullHandshake_S; $rose(prim_alert_rxtx_fpv.alert_tx_out.alert_p) ##1 $rose(prim_alert_rxtx_fpv.alert_rx_out.ack_p) && @@ -55,27 +56,37 @@ module prim_alert_rxtx_assert_fpv ( // only take place if both FSMs are in a sane state `ASSERT(PingHs_A, ##1 $changed(prim_alert_rxtx_fpv.alert_rx_out.ping_p) && (prim_alert_rxtx_fpv.i_prim_alert_sender.state_q == - prim_alert_rxtx_fpv.i_prim_alert_sender.Idle ) && + prim_alert_rxtx_fpv.i_prim_alert_sender.Idle) && (prim_alert_rxtx_fpv.i_prim_alert_receiver.state_q == - prim_alert_rxtx_fpv.i_prim_alert_receiver.Idle )|=> FullHandshake_S, + prim_alert_rxtx_fpv.i_prim_alert_receiver.Idle)|=> FullHandshake_S, clk_i, !rst_ni || error_present) - `ASSERT(AlertHs_A, alert_i && + `ASSERT(AlertHs_A, alert_req_i && (prim_alert_rxtx_fpv.i_prim_alert_sender.state_q == prim_alert_rxtx_fpv.i_prim_alert_sender.Idle) && (prim_alert_rxtx_fpv.i_prim_alert_receiver.state_q == prim_alert_rxtx_fpv.i_prim_alert_receiver.Idle) |=> - FullHandshake_S, clk_i, !rst_ni || error_present) + FullHandshake_S |-> alert_ack_o, clk_i, !rst_ni || error_present) // transmission of pings - `ASSERT(AlertPing_A, !error_present ##1 $rose(ping_en_i) |-> + // note: the complete transmission of pings only happen when no ping handshake is in progress + `ASSERT(AlertPingOk_A, !(prim_alert_rxtx_fpv.i_prim_alert_sender.state_q inside { + prim_alert_rxtx_fpv.i_prim_alert_sender.PingHsPhase1, + prim_alert_rxtx_fpv.i_prim_alert_sender.PingHsPhase2}) && $rose(ping_req_i) |-> ##[1:9] ping_ok_o, clk_i, !rst_ni || error_present) + `ASSERT(AlertPingIgnored_A, (prim_alert_rxtx_fpv.i_prim_alert_sender.state_q inside { + prim_alert_rxtx_fpv.i_prim_alert_sender.PingHsPhase1, + prim_alert_rxtx_fpv.i_prim_alert_sender.PingHsPhase2}) && $rose(ping_req_i) |-> + ping_ok_o == 0 throughout ping_req_i [->1], clk_i, !rst_ni || error_present) // transmission of alerts in case of no collision with ping enable - `ASSERT(AlertCheck0_A, !ping_en_i [*3] ##0 $rose(alert_i) && + `ASSERT(AlertCheck0_A, !ping_req_i [*3] ##0 $rose(alert_req_i) && (prim_alert_rxtx_fpv.i_prim_alert_sender.state_q == prim_alert_rxtx_fpv.i_prim_alert_sender.Idle) |=> - alert_o, clk_i, !rst_ni || error_present || ping_en_i) - // transmission of alerts in the general case which can include ping collisions - `ASSERT(AlertCheck1_A, alert_i |-> ##[1:9] alert_o, clk_i, !rst_ni || error_present) + alert_o, clk_i, !rst_ni || error_present || ping_req_i) + // transmission of alerts in the general case which can include continous ping collisions + `ASSERT(AlertCheck1_A, alert_req_i |=> + strong(##[1:$] ((prim_alert_rxtx_fpv.i_prim_alert_sender.state_q == + prim_alert_rxtx_fpv.i_prim_alert_sender.Idle) && !ping_req_i) ##1 alert_o), + clk_i, !rst_ni || error_present || alert_ack_o) // basic liveness of FSMs in case no errors are present `ASSERT(FsmLivenessSender_A, diff --git a/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_alert_rxtx_async_assert_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_alert_rxtx_async_assert_fpv.sv index 5f4b3df085..c1cf3942aa 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_alert_rxtx_async_assert_fpv.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_alert_rxtx_async_assert_fpv.sv @@ -21,8 +21,9 @@ module prim_alert_rxtx_async_assert_fpv ( input alert_err_ni, input [1:0] alert_skew_i, // normal I/Os - input alert_i, - input ping_en_i, + input alert_req_i, + input alert_ack_o, + input ping_req_i, input ping_ok_o, input integ_fail_o, input alert_o @@ -56,11 +57,10 @@ module prim_alert_rxtx_async_assert_fpv ( // ping will stay high until ping ok received, then it must be deasserted // TODO: this excludes the case where no ping ok will be returned due to an error - `ASSUME_FPV(PingDeassert_M, ping_en_i && ping_ok_o |=> !ping_en_i, clk_i, !rst_ni) - `ASSUME_FPV(PingEnStaysAsserted0_M, ping_en_i |=> - (ping_en_i && !ping_ok_o) or - (ping_en_i && ping_ok_o ##1 $fell(ping_en_i)), - clk_i, !rst_ni || error_present) + `ASSUME_FPV(PingDeassert_M, ping_req_i && ping_ok_o |=> !ping_req_i, clk_i, !rst_ni) + `ASSUME_FPV(PingEn_M, $rose(ping_req_i) |-> ping_req_i throughout + (ping_ok_o || error_present)[->1] ##1 $fell(ping_req_i), + clk_i, !rst_ni) // Note: the sequence lengths of the handshake and the following properties needs to // be parameterized accordingly if different clock ratios are to be used here. @@ -83,26 +83,37 @@ module prim_alert_rxtx_async_assert_fpv ( (prim_alert_rxtx_async_fpv.i_prim_alert_receiver.state_q == prim_alert_rxtx_async_fpv.i_prim_alert_receiver.Idle) |-> ##[0:5] FullHandshake_S, clk_i, !rst_ni || error_setreg_q) - `ASSERT(AlertHs_A, alert_i && + `ASSERT(AlertHs_A, alert_req_i && (prim_alert_rxtx_async_fpv.i_prim_alert_sender.state_q == prim_alert_rxtx_async_fpv.i_prim_alert_sender.Idle) && (prim_alert_rxtx_async_fpv.i_prim_alert_receiver.state_q == - prim_alert_rxtx_async_fpv.i_prim_alert_receiver.Idle) |-> ##[0:5] FullHandshake_S, + prim_alert_rxtx_async_fpv.i_prim_alert_receiver.Idle) |-> ##[0:5] FullHandshake_S + ##[0:5] alert_ack_o, clk_i, !rst_ni || error_setreg_q) // transmission of pings // this bound is relatively large as in the worst case, we need to resolve // staggered differential signal patterns on all three differential channels - `ASSERT(AlertPing_A, $rose(ping_en_i) |-> ##[1:23] ping_ok_o, - clk_i, !rst_ni || error_setreg_q) + // note: the complete transmission of pings only happen when no ping handshake is in progress + `ASSERT(AlertPingOk_A, !(prim_alert_rxtx_async_fpv.i_prim_alert_sender.state_q inside { + prim_alert_rxtx_async_fpv.i_prim_alert_sender.PingHsPhase1, + prim_alert_rxtx_async_fpv.i_prim_alert_sender.PingHsPhase2}) && $rose(ping_req_i) |-> + ##[1:23] ping_ok_o, clk_i, !rst_ni || error_setreg_q) + `ASSERT(AlertPingIgnored_A, (prim_alert_rxtx_async_fpv.i_prim_alert_sender.state_q inside { + prim_alert_rxtx_async_fpv.i_prim_alert_sender.PingHsPhase1, + prim_alert_rxtx_async_fpv.i_prim_alert_sender.PingHsPhase2}) && $rose(ping_req_i) |-> + ping_ok_o == 0 throughout ping_req_i[->1], clk_i, !rst_ni || error_setreg_q) // transmission of first alert assertion (no ping collision) - `ASSERT(AlertCheck0_A, !ping_en_i [*10] ##1 $rose(alert_i) && + `ASSERT(AlertCheck0_A, !ping_req_i [*10] ##1 $rose(alert_req_i) && (prim_alert_rxtx_async_fpv.i_prim_alert_sender.state_q == prim_alert_rxtx_async_fpv.i_prim_alert_sender.Idle) |-> - ##[3:5] alert_o, clk_i, !rst_ni || ping_en_i || error_setreg_q) - // eventual transmission of alerts in the general case which can include ping collisions - `ASSERT(AlertCheck1_A, alert_i |-> ##[1:25] alert_o, - clk_i, !rst_ni || error_setreg_q) + ##[3:5] alert_o, clk_i, !rst_ni || ping_req_i || error_setreg_q) + // eventual transmission of alerts in the general case which can include continous ping + // collisions + `ASSERT(AlertCheck1_A, alert_req_i |-> + strong(##[1:$] (prim_alert_rxtx_async_fpv.i_prim_alert_sender.state_q == + prim_alert_rxtx_async_fpv.i_prim_alert_sender.Idle && !ping_req_i) ##[3:5] alert_o), + clk_i, !rst_ni || error_setreg_q || alert_ack_o) // basic liveness of FSMs in case no errors are present `ASSERT(FsmLivenessSender_A, !error_present [*2] ##1 !error_present && diff --git a/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_esc_rxtx_assert_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_esc_rxtx_assert_fpv.sv index 4f55520131..3c0b659d81 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_esc_rxtx_assert_fpv.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_esc_rxtx_assert_fpv.sv @@ -16,8 +16,8 @@ module prim_esc_rxtx_assert_fpv ( input esc_err_pi, input esc_err_ni, // normal I/Os - input esc_en_i, - input ping_en_i, + input esc_req_i, + input ping_req_i, input ping_ok_o, input integ_fail_o, input esc_en_o @@ -29,27 +29,27 @@ module prim_esc_rxtx_assert_fpv ( // ping will stay high until ping ok received, then it must be deasserted // TODO: this escludes the case where no ping ok will be returned due to an error - `ASSUME_FPV(PingDeassert_M, ping_en_i && ping_ok_o |=> ping_en_i, clk_i, !rst_ni) - `ASSUME_FPV(PingEnStaysAsserted0_M, ping_en_i |=> - (ping_en_i && !ping_ok_o) or (ping_en_i && ping_ok_o ##1 $fell(ping_en_i)), + `ASSUME_FPV(PingDeassert_M, ping_req_i && ping_ok_o |=> ping_req_i, clk_i, !rst_ni) + `ASSUME_FPV(PingEnStaysAsserted0_M, ping_req_i |=> + (ping_req_i && !ping_ok_o) or (ping_req_i && ping_ok_o ##1 $fell(ping_req_i)), clk_i, !rst_ni || error_present) // assume that the ping enable and escalation enable signals will eventually be deasserted (and // esc will stay low for more than 2 cycles) - `ASSUME_FPV(FiniteEsc_M, esc_en_i |-> strong(##[1:$] !esc_en_i [*2])) - `ASSUME_FPV(FinitePing_M, ping_en_i |-> strong(##[1:$] !ping_en_i)) + `ASSUME_FPV(FiniteEsc_M, esc_req_i |-> strong(##[1:$] !esc_req_i [*2])) + `ASSUME_FPV(FinitePing_M, ping_req_i |-> strong(##[1:$] !ping_req_i)) // ping response mus occur within 4 cycles (given that no // error occured within the previous cycles) - `ASSERT(PingRespCheck_A, !error_present [*4] ##1 $rose(ping_en_i) |-> + `ASSERT(PingRespCheck_A, !error_present [*4] ##1 $rose(ping_req_i) |-> ##[0:4] ping_ok_o, clk_i, !rst_ni || error_present) // be more specific (i.e. use throughout) - `ASSERT(EscRespCheck_A, ##1 esc_en_i |-> ##[0:1] prim_esc_rxtx_fpv.esc_rx_out.resp_p ##1 + `ASSERT(EscRespCheck_A, ##1 esc_req_i |-> ##[0:1] prim_esc_rxtx_fpv.esc_rx_out.resp_p ##1 !prim_esc_rxtx_fpv.esc_rx_out.resp_p, clk_i, !rst_ni || error_present) // check correct transmission of escalation within 0-1 cycles - `ASSERT(EscCheck_A, ##1 esc_en_i |-> ##[0:1] esc_en_o, clk_i, !rst_ni || error_present) + `ASSERT(EscCheck_A, ##1 esc_req_i |-> ##[0:1] esc_en_o, clk_i, !rst_ni || error_present) // check that a single error on the diffpairs is detected `ASSERT(SingleSigIntDetected0_A, {esc_err_pi, esc_err_ni} == '0 ##1 diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim.waiver index 89d86bdfd3..1e887a98e2 100644 --- a/vendor/lowrisc_ip/ip/prim/lint/prim.waiver +++ b/vendor/lowrisc_ip/ip/prim/lint/prim.waiver @@ -59,3 +59,11 @@ waive -rules {HIER_BRANCH_NOT_READ} -location {tlul_fifo_sync.sv} -regexp {Conne # #waive -rules NOT_READ -location {prim_ram_*_wrapper*} -regexp {(a|b)_rdata_(q|d)\[38} \ # -comment "Syndrome is not going out to the interface" + +# prim_arbiter_fixed +waive -rules {HIER_BRANCH_NOT_READ INPUT_NOT_READ} -location {prim_arbiter_fixed.sv} -regexp {.*'(clk_i|rst_ni)' is not read from in module 'prim_arbiter_fixed'.*} \ + -comment "clk_ and rst_ni are only used for assertions in this module." + +waive -rules {INTEGER} -location {prim_cipher_pkg.sv} -msg {'k' of type int used as a non-constant} \ + -comment "We need to use the iterator value in the keyschedule function, hence this is ok." + diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_clock_buf.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_clock_buf.waiver new file mode 100644 index 0000000000..9e030adb1a --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_clock_buf.waiver @@ -0,0 +1,8 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# waiver file for prim_clock_buf + +waive -rules {STAR_PORT_CONN_USE} -location {prim_clock_buf.sv} -regexp {.*wild card port connection encountered on instance.*} \ + -comment "Generated prims may have wildcard connections." diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_clock_div.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_clock_div.waiver new file mode 100644 index 0000000000..bd70fff8d9 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_clock_div.waiver @@ -0,0 +1,5 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# waiver file for prim_clock_div diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_clock_gating.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_clock_gating.waiver new file mode 100644 index 0000000000..0e10939d29 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_clock_gating.waiver @@ -0,0 +1,8 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# waiver file for prim_clock_gating + +waive -rules {STAR_PORT_CONN_USE} -location {prim_clock_gating.sv} -regexp {.*wild card port connection encountered on instance.*} \ + -comment "Generated prims may have wildcard connections." diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_clock_inv.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_clock_inv.waiver new file mode 100644 index 0000000000..0893e78622 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_clock_inv.waiver @@ -0,0 +1,8 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# waiver file for prim_clock_inv + +waive -rules {STAR_PORT_CONN_USE} -location {prim_clock_inv.sv} -regexp {.*wild card port connection encountered on instance.*} \ + -comment "Generated prims may have wildcard connections." diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_clock_mux2.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_clock_mux2.waiver new file mode 100644 index 0000000000..6a82aaa62c --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_clock_mux2.waiver @@ -0,0 +1,8 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# waiver file for prim_clock_mux2 + +waive -rules {STAR_PORT_CONN_USE} -location {prim_clock_mux2.sv} -regexp {.*wild card port connection encountered on instance.*} \ + -comment "Generated prims may have wildcard connections." diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_flash.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_flash.waiver new file mode 100644 index 0000000000..3833a524fc --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_flash.waiver @@ -0,0 +1,8 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# waiver file for prim_flash + +waive -rules {STAR_PORT_CONN_USE} -location {prim_flash.sv} -regexp {.*wild card port connection encountered on instance.*} \ + -comment "Generated prims may have wildcard connections." diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_flop.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_flop.waiver new file mode 100644 index 0000000000..8659dddb6e --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_flop.waiver @@ -0,0 +1,8 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# waiver file for prim_flop + +waive -rules {STAR_PORT_CONN_USE} -location {prim_flop.sv} -regexp {.*wild card port connection encountered on instance.*} \ + -comment "Generated prims may have wildcard connections." diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_flop_2sync.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_flop_2sync.waiver new file mode 100644 index 0000000000..95bc23fb20 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_flop_2sync.waiver @@ -0,0 +1,8 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# waiver file for prim_flop_2sync + +waive -rules {STAR_PORT_CONN_USE} -location {prim_flop_2sync.sv} -regexp {.*wild card port connection encountered on instance.*} \ + -comment "Generated prims may have wildcard connections." diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_otp.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_otp.waiver new file mode 100644 index 0000000000..593bbc53de --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_otp.waiver @@ -0,0 +1,8 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# waiver file for prim_otp + +waive -rules {STAR_PORT_CONN_USE} -location {prim_otp.sv} -regexp {.*wild card port connection encountered on instance.*} \ + -comment "Generated prims may have wildcard connections." diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_pad_wrapper.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_pad_wrapper.waiver new file mode 100644 index 0000000000..c03e039055 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_pad_wrapper.waiver @@ -0,0 +1,8 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# waiver file for prim_pad_wrapper + +waive -rules {STAR_PORT_CONN_USE} -location {prim_pad_wrapper.sv} -regexp {.*wild card port connection encountered on instance.*} \ + -comment "Generated prims may have wildcard connections." diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_ram_1p.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_ram_1p.waiver new file mode 100644 index 0000000000..5e3de12fbe --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_ram_1p.waiver @@ -0,0 +1,8 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# waiver file for prim_ram_1p + +waive -rules {STAR_PORT_CONN_USE} -location {prim_ram_1p.sv} -regexp {.*wild card port connection encountered on instance.*} \ + -comment "Generated prims may have wildcard connections." diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_ram_1p_adv.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_ram_1p_adv.waiver new file mode 100644 index 0000000000..6e49dff4c5 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_ram_1p_adv.waiver @@ -0,0 +1,8 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# waiver file for prim_ram_1p_adv + +waive -rules {CONST_FF} -location {prim_ram_1p_adv.sv} -regexp {.*Flip-flop 'wmask_q' is driven by constant ones.*EnableECC=1'h1.*} \ + -comment "This particular instance is ok since we do not use the wmask when ECC is enabled." diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_ram_2p.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_ram_2p.waiver new file mode 100644 index 0000000000..474975e478 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_ram_2p.waiver @@ -0,0 +1,8 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# waiver file for prim_ram_2p + +waive -rules {STAR_PORT_CONN_USE} -location {prim_ram_2p.sv} -regexp {.*wild card port connection encountered on instance.*} \ + -comment "Generated prims may have wildcard connections." diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_rom.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_rom.waiver new file mode 100644 index 0000000000..5b588b41d4 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_rom.waiver @@ -0,0 +1,8 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# waiver file for prim_rom + +waive -rules {STAR_PORT_CONN_USE} -location {prim_rom.sv} -regexp {.*wild card port connection encountered on instance.*} \ + -comment "Generated prims may have wildcard connections." diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_usb_diff_rx.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_usb_diff_rx.waiver new file mode 100644 index 0000000000..30c0bdbc6d --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_usb_diff_rx.waiver @@ -0,0 +1,8 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# waiver file for prim_usb_diff_rx + +waive -rules {STAR_PORT_CONN_USE} -location {prim_usb_diff_rx.sv} -regexp {.*wild card port connection encountered on instance.*} \ + -comment "Generated prims may have wildcard connections." diff --git a/vendor/lowrisc_ip/ip/prim/pre_dv/prim_sync_reqack/cpp/prim_sync_reqack_tb.cc b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_sync_reqack/cpp/prim_sync_reqack_tb.cc index 4b93a4cc1b..e575d33ffe 100644 --- a/vendor/lowrisc_ip/ip/prim/pre_dv/prim_sync_reqack/cpp/prim_sync_reqack_tb.cc +++ b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_sync_reqack/cpp/prim_sync_reqack_tb.cc @@ -6,9 +6,9 @@ #include "verilated_toplevel.h" #include "verilator_sim_ctrl.h" -#include #include #include +#include #include "sim_ctrl_extension.h" diff --git a/vendor/lowrisc_ip/ip/prim/prim.core b/vendor/lowrisc_ip/ip/prim/prim.core index 5c83f063cf..5e4698252e 100644 --- a/vendor/lowrisc_ip/ip/prim/prim.core +++ b/vendor/lowrisc_ip/ip/prim/prim.core @@ -24,7 +24,6 @@ filesets: - rtl/prim_alert_sender.sv - rtl/prim_arbiter_ppc.sv - rtl/prim_arbiter_tree.sv - - rtl/prim_dom_and_2share.sv - rtl/prim_arbiter_fixed.sv - rtl/prim_esc_pkg.sv - rtl/prim_esc_receiver.sv @@ -32,9 +31,11 @@ filesets: - rtl/prim_sram_arbiter.sv - rtl/prim_fifo_async.sv - rtl/prim_fifo_sync.sv + - rtl/prim_slicer.sv - rtl/prim_sync_reqack.sv - rtl/prim_keccak.sv - rtl/prim_packer.sv + - rtl/prim_packer_fifo.sv - rtl/prim_cipher_pkg.sv - rtl/prim_present.sv - rtl/prim_prince.sv diff --git a/vendor/lowrisc_ip/ip/prim/prim_clock_buf.core b/vendor/lowrisc_ip/ip/prim/prim_clock_buf.core index 724a29e57a..7cab5c3720 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_clock_buf.core +++ b/vendor/lowrisc_ip/ip/prim/prim_clock_buf.core @@ -11,6 +11,28 @@ filesets: - lowrisc:prim:prim_pkg - lowrisc:prim:primgen + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + file_type: vlt + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + - lint/prim_clock_buf.waiver + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + - lowrisc:lint:comportable + generate: impl: generator: primgen @@ -20,6 +42,9 @@ generate: targets: default: filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) - primgen_dep generate: - impl diff --git a/vendor/lowrisc_ip/ip/prim/prim_clock_div.core b/vendor/lowrisc_ip/ip/prim/prim_clock_div.core new file mode 100644 index 0000000000..7bd9bfbf0f --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/prim_clock_div.core @@ -0,0 +1,22 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +name: "lowrisc:prim:clock_div" +description: "Generic clock divide" +filesets: + files_rtl: + depend: + - lowrisc:prim:prim_pkg + - lowrisc:prim:flop + - lowrisc:prim:clock_inv + - lowrisc:prim:clock_buf + files: + - rtl/prim_clock_div.sv + file_type: systemVerilogSource + +targets: + default: + filesets: + - files_rtl diff --git a/vendor/lowrisc_ip/ip/prim/prim_clock_gating.core b/vendor/lowrisc_ip/ip/prim/prim_clock_gating.core index 1ed587c994..91b46737ca 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_clock_gating.core +++ b/vendor/lowrisc_ip/ip/prim/prim_clock_gating.core @@ -11,6 +11,28 @@ filesets: - lowrisc:prim:prim_pkg - lowrisc:prim:primgen + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + file_type: vlt + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + - lint/prim_clock_gating.waiver + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + - lowrisc:lint:comportable + generate: impl: generator: primgen @@ -20,6 +42,9 @@ generate: targets: default: filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) - primgen_dep generate: - impl diff --git a/vendor/lowrisc_ip/ip/prim/prim_clock_inv.core b/vendor/lowrisc_ip/ip/prim/prim_clock_inv.core index 96227eb9d9..8620ba2844 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_clock_inv.core +++ b/vendor/lowrisc_ip/ip/prim/prim_clock_inv.core @@ -11,6 +11,28 @@ filesets: - lowrisc:prim:prim_pkg - lowrisc:prim:primgen + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + file_type: vlt + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + - lint/prim_clock_inv.waiver + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + - lowrisc:lint:comportable + generate: impl: generator: primgen @@ -20,6 +42,9 @@ generate: targets: default: filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) - primgen_dep generate: - impl diff --git a/vendor/lowrisc_ip/ip/prim/prim_clock_mux2.core b/vendor/lowrisc_ip/ip/prim/prim_clock_mux2.core index c925624593..e29234e64b 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_clock_mux2.core +++ b/vendor/lowrisc_ip/ip/prim/prim_clock_mux2.core @@ -11,6 +11,28 @@ filesets: - lowrisc:prim:prim_pkg - lowrisc:prim:primgen + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + file_type: vlt + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + - lint/prim_clock_mux2.waiver + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + - lowrisc:lint:comportable + generate: impl: generator: primgen @@ -20,6 +42,9 @@ generate: targets: default: filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) - primgen_dep generate: - impl diff --git a/vendor/lowrisc_ip/ip/prim/prim_flash.core b/vendor/lowrisc_ip/ip/prim/prim_flash.core index c7d1aa3a3c..fcf26d7f41 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_flash.core +++ b/vendor/lowrisc_ip/ip/prim/prim_flash.core @@ -14,6 +14,28 @@ filesets: # However, the generator for the prim:ram1p does not kick in, causing compile errors. - lowrisc:prim:ram_1p + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + file_type: vlt + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + - lint/prim_flash.waiver + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + - lowrisc:lint:comportable + generate: impl: generator: primgen @@ -23,6 +45,9 @@ generate: targets: default: filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) - primgen_dep generate: - impl diff --git a/vendor/lowrisc_ip/ip/prim/prim_flop.core b/vendor/lowrisc_ip/ip/prim/prim_flop.core index e007e9fa46..bcc7dc61e7 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_flop.core +++ b/vendor/lowrisc_ip/ip/prim/prim_flop.core @@ -11,6 +11,27 @@ filesets: - lowrisc:prim:prim_pkg - lowrisc:prim:primgen + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + file_type: vlt + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + - lint/prim_flop.waiver + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + - lowrisc:lint:comportable + generate: impl: generator: primgen @@ -20,6 +41,9 @@ generate: targets: default: filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) - primgen_dep generate: - impl diff --git a/vendor/lowrisc_ip/ip/prim/prim_flop_2sync.core b/vendor/lowrisc_ip/ip/prim/prim_flop_2sync.core index b814a78147..6d11bdea6e 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_flop_2sync.core +++ b/vendor/lowrisc_ip/ip/prim/prim_flop_2sync.core @@ -11,6 +11,28 @@ filesets: - lowrisc:prim:prim_pkg - lowrisc:prim:primgen + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + file_type: vlt + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + - lint/prim_flop_2sync.waiver + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + - lowrisc:lint:comportable + + generate: impl: generator: primgen @@ -20,6 +42,10 @@ generate: targets: default: filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) - primgen_dep generate: - impl + diff --git a/vendor/lowrisc_ip/ip/prim/prim_lc_sync.core b/vendor/lowrisc_ip/ip/prim/prim_lc_sync.core new file mode 100644 index 0000000000..f96ea44a54 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/prim_lc_sync.core @@ -0,0 +1,61 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +name: "lowrisc:prim:lc_sync:0.1" +description: "Two-stage synchronizer for life cycle control signals." +filesets: + files_rtl: + depend: + - lowrisc:prim:assert + - lowrisc:prim:flop_2sync + - lowrisc:prim:clock_buf + - lowrisc:ip:lc_ctrl_pkg + files: + - rtl/prim_lc_sync.sv + file_type: systemVerilogSource + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + file_type: vlt + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + # - lint/prim_lc_sync.waiver + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + - lowrisc:lint:comportable + +targets: + default: &default_target + filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) + - files_rtl + + lint: + <<: *default_target + default_tool: verilator + parameters: + - SYNTHESIS=true + tools: + ascentlint: + ascentlint_options: + - "-wait_license" + - "-stop_on_error" + verilator: + mode: lint-only + verilator_options: + - "-Wall" diff --git a/vendor/lowrisc_ip/ip/prim/prim_lfsr.core b/vendor/lowrisc_ip/ip/prim/prim_lfsr.core index 0e65cd31bb..2362e73f92 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_lfsr.core +++ b/vendor/lowrisc_ip/ip/prim/prim_lfsr.core @@ -13,7 +13,46 @@ filesets: - rtl/prim_lfsr.sv file_type: systemVerilogSource + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + file_type: vlt + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + # - lint/prim_lfsr.waiver + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + - lowrisc:lint:comportable + targets: - default: + default: &default_target filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) - files_rtl + + lint: + <<: *default_target + default_tool: verilator + parameters: + - SYNTHESIS=true + tools: + ascentlint: + ascentlint_options: + - "-wait_license" + - "-stop_on_error" + verilator: + mode: lint-only + verilator_options: + - "-Wall" diff --git a/vendor/lowrisc_ip/ip/prim/prim_multibit_sync.core b/vendor/lowrisc_ip/ip/prim/prim_multibit_sync.core new file mode 100644 index 0000000000..9ce56ee387 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/prim_multibit_sync.core @@ -0,0 +1,20 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +name: "lowrisc:prim:multibit_sync:0.1" +description: "Synchronizer with consistency check for multi-bit signals." +filesets: + files_rtl: + depend: + - lowrisc:prim:assert + - lowrisc:prim:flop_2sync + files: + - rtl/prim_multibit_sync.sv + file_type: systemVerilogSource + +targets: + default: + filesets: + - files_rtl diff --git a/vendor/lowrisc_ip/ip/prim/prim_otp.core b/vendor/lowrisc_ip/ip/prim/prim_otp.core index e1ff6f000e..4c1d474f52 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_otp.core +++ b/vendor/lowrisc_ip/ip/prim/prim_otp.core @@ -10,6 +10,28 @@ filesets: depend: - lowrisc:prim:prim_pkg - lowrisc:prim:primgen + - lowrisc:ip:otp_ctrl_pkg + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + file_type: vlt + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + - lint/prim_otp.waiver + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + - lowrisc:lint:comportable generate: impl: @@ -20,6 +42,9 @@ generate: targets: default: filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) - primgen_dep generate: - impl diff --git a/vendor/lowrisc_ip/ip/prim/prim_pad_wrapper.core b/vendor/lowrisc_ip/ip/prim/prim_pad_wrapper.core index 1454e74a1d..c74355deaf 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_pad_wrapper.core +++ b/vendor/lowrisc_ip/ip/prim/prim_pad_wrapper.core @@ -11,6 +11,28 @@ filesets: - lowrisc:prim:prim_pkg - lowrisc:prim:primgen + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + file_type: vlt + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + - lint/prim_pad_wrapper.waiver + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + - lowrisc:lint:comportable + generate: impl: generator: primgen @@ -20,6 +42,9 @@ generate: targets: default: filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) - primgen_dep generate: - impl diff --git a/vendor/lowrisc_ip/ip/prim/prim_ram_1p.core b/vendor/lowrisc_ip/ip/prim/prim_ram_1p.core index 68f8452e5f..387eaf9b3b 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_ram_1p.core +++ b/vendor/lowrisc_ip/ip/prim/prim_ram_1p.core @@ -11,6 +11,28 @@ filesets: - lowrisc:prim:prim_pkg - lowrisc:prim:primgen + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + file_type: vlt + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + - lint/prim_ram_1p.waiver + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + - lowrisc:lint:comportable + generate: impl: generator: primgen @@ -20,6 +42,9 @@ generate: targets: default: filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) - primgen_dep generate: - impl diff --git a/vendor/lowrisc_ip/ip/prim/prim_ram_1p_adv.core b/vendor/lowrisc_ip/ip/prim/prim_ram_1p_adv.core index 5c3b419946..bb109ba769 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_ram_1p_adv.core +++ b/vendor/lowrisc_ip/ip/prim/prim_ram_1p_adv.core @@ -4,7 +4,6 @@ CAPI=2: # SPDX-License-Identifier: Apache-2.0 name: "lowrisc:prim:ram_1p_adv:0.1" -description: "Single-port RAM primitive with advanced features" filesets: files_rtl: depend: @@ -16,7 +15,31 @@ filesets: - rtl/prim_ram_1p_adv.sv file_type: systemVerilogSource + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + file_type: vlt + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + - lint/prim_ram_1p_adv.waiver + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + - lowrisc:lint:comportable + targets: default: filesets: - files_rtl + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) diff --git a/vendor/lowrisc_ip/ip/prim/prim_ram_2p.core b/vendor/lowrisc_ip/ip/prim/prim_ram_2p.core index af887f0744..91003228d8 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_ram_2p.core +++ b/vendor/lowrisc_ip/ip/prim/prim_ram_2p.core @@ -11,6 +11,28 @@ filesets: - lowrisc:prim:prim_pkg - lowrisc:prim:primgen + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + file_type: vlt + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + - lint/prim_ram_2p.waiver + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + - lowrisc:lint:comportable + generate: impl: generator: primgen @@ -20,6 +42,9 @@ generate: targets: default: filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) - primgen_dep generate: - impl diff --git a/vendor/lowrisc_ip/ip/prim/prim_rom.core b/vendor/lowrisc_ip/ip/prim/prim_rom.core index a5a489e7ea..9f78826af2 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_rom.core +++ b/vendor/lowrisc_ip/ip/prim/prim_rom.core @@ -11,6 +11,28 @@ filesets: - lowrisc:prim:prim_pkg - lowrisc:prim:primgen + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + file_type: vlt + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + - lint/prim_rom.waiver + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + - lowrisc:lint:comportable + generate: impl: generator: primgen @@ -20,6 +42,9 @@ generate: targets: default: filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) - primgen_dep generate: - impl diff --git a/vendor/lowrisc_ip/ip/prim/prim_secded.core b/vendor/lowrisc_ip/ip/prim/prim_secded.core index 8c22ecddd9..ed82bf4fb1 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_secded.core +++ b/vendor/lowrisc_ip/ip/prim/prim_secded.core @@ -8,6 +8,8 @@ description: "SECDED ECC primitives" filesets: files_rtl: files: + - rtl/prim_secded_22_16_dec.sv + - rtl/prim_secded_22_16_enc.sv - rtl/prim_secded_28_22_dec.sv - rtl/prim_secded_28_22_enc.sv - rtl/prim_secded_39_32_dec.sv diff --git a/vendor/lowrisc_ip/ip/prim/prim_usb_diff_rx.core b/vendor/lowrisc_ip/ip/prim/prim_usb_diff_rx.core new file mode 100644 index 0000000000..1284b08826 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/prim_usb_diff_rx.core @@ -0,0 +1,50 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +name: "lowrisc:prim:usb_diff_rx" +description: "Differential receiver for USB." +filesets: + primgen_dep: + depend: + - lowrisc:prim:prim_pkg + - lowrisc:prim:primgen + + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + file_type: vlt + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + - lint/prim_usb_diff_rx.waiver + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + - lowrisc:lint:comportable + +generate: + impl: + generator: primgen + parameters: + prim_name: usb_diff_rx + +targets: + default: + filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) + - primgen_dep + generate: + - impl diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_alert_sender.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_alert_sender.sv index faa242a9c1..8403619f66 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_alert_sender.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_alert_sender.sv @@ -4,10 +4,14 @@ // // The alert sender primitive module differentially encodes and transmits an // alert signal to the prim_alert_receiver module. An alert will be signalled -// by a full handshake on alert_p/n and ack_p/n. The alert_i signal may +// by a full handshake on alert_p/n and ack_p/n. The alert_req_i signal may // be continuously asserted, in which case the alert signalling handshake // will be repeatedly initiated. // +// The alert_req_i signal may also be used as part of req/ack. The parent module +// can keep alert_req_i asserted until it has been ack'd (transferred to the alert +// receiver). The parent module is not required to use this. +// // Further, this module supports in-band ping testing, which means that a level // change on the ping_p/n diff pair will result in a full-handshake response // on alert_p/n and ack_p/n. @@ -35,7 +39,8 @@ module prim_alert_sender input clk_i, input rst_ni, // native alert from the peripheral - input alert_i, + input alert_req_i, + output logic alert_ack_o, // ping input diff pair and ack diff pair input alert_rx_t alert_rx_i, // alert output diff pair @@ -82,7 +87,16 @@ module prim_alert_sender /////////////////////////////////////////////////// // main protocol FSM that drives the diff output // /////////////////////////////////////////////////// - typedef enum logic [2:0] {Idle, HsPhase1, HsPhase2, SigInt, Pause0, Pause1} state_e; + typedef enum logic [2:0] { + Idle, + AlertHsPhase1, + AlertHsPhase2, + PingHsPhase1, + PingHsPhase2, + SigInt, + Pause0, + Pause1 + } state_e; state_e state_d, state_q; logic alert_pq, alert_nq, alert_pd, alert_nd; logic sigint_detected; @@ -96,9 +110,14 @@ module prim_alert_sender // alert and ping set regs logic alert_set_d, alert_set_q, alert_clr; logic ping_set_d, ping_set_q, ping_clr; - assign alert_set_d = (alert_clr) ? 1'b0 : (alert_set_q | alert_i); + + // if handshake is ongoing, capture additional alert requests + assign alert_set_d = (alert_clr) ? 1'b0 : (alert_set_q | alert_req_i); assign ping_set_d = (ping_clr) ? 1'b0 : (ping_set_q | ping_event); + // alert event acknowledge + assign alert_ack_o = alert_clr; + // this FSM performs a full four phase handshake upon a ping or alert trigger. // note that the latency of the alert_p/n diff pair is at least one cycle // until it enters the receiver FSM. the same holds for the ack_* diff pair @@ -116,35 +135,54 @@ module prim_alert_sender unique case (state_q) Idle: begin // alert always takes precedence - if (alert_i || alert_set_q || ping_event || ping_set_q) begin - state_d = HsPhase1; + if (alert_req_i || alert_set_q || ping_event || ping_set_q) begin + state_d = (alert_req_i || alert_set_q) ? AlertHsPhase1 : PingHsPhase1; alert_pd = 1'b1; alert_nd = 1'b0; - if (ping_event || ping_set_q) begin - ping_clr = 1'b1; - end else begin - alert_clr = 1'b1; - end end end // waiting for ack from receiver - HsPhase1: begin + AlertHsPhase1: begin if (ack_level) begin - state_d = HsPhase2; + state_d = AlertHsPhase2; end else begin alert_pd = 1'b1; alert_nd = 1'b0; end end // wait for deassertion of ack - HsPhase2: begin + AlertHsPhase2: begin if (!ack_level) begin state_d = Pause0; + alert_clr = 1'b1; + end + end + // waiting for ack from receiver + PingHsPhase1: begin + if (ack_level) begin + state_d = PingHsPhase2; + end else begin + alert_pd = 1'b1; + alert_nd = 1'b0; + end + end + // wait for deassertion of ack + PingHsPhase2: begin + if (!ack_level) begin + ping_clr = 1'b1; + state_d = Pause0; end end // pause cycles between back-to-back handshakes - Pause0: state_d = Pause1; - Pause1: state_d = Idle; + Pause0: begin + state_d = Pause1; + end + + // clear and ack alert request if it was set + Pause1: begin + state_d = Idle; + end + // we have a signal integrity issue at one of // the incoming diff pairs. this condition is // signalled by setting the output diffpair @@ -229,8 +267,8 @@ module prim_alert_sender $rose(alert_tx_o.alert_p), clk_i, !rst_ni || (alert_tx_o.alert_p == alert_tx_o.alert_n)) end - // if alert_i is true, handshakes should be continuously repeated - `ASSERT(AlertHs_A, alert_i && state_q == Idle |=> $rose(alert_tx_o.alert_p), + // if alert_req_i is true, handshakes should be continuously repeated + `ASSERT(AlertHs_A, alert_req_i && state_q == Idle |=> $rose(alert_tx_o.alert_p), clk_i, !rst_ni || (alert_tx_o.alert_p == alert_tx_o.alert_n)) endmodule : prim_alert_sender diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_arbiter_fixed.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_arbiter_fixed.sv index 9fff2175ce..d9677dd24b 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_arbiter_fixed.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_arbiter_fixed.sv @@ -53,7 +53,6 @@ module prim_arbiter_fixed #( // align to powers of 2 for simplicity // a full binary tree with N levels has 2**N + 2**N-1 nodes logic [2**(IdxW+1)-2:0] req_tree; - logic [2**(IdxW+1)-2:0] rdy_tree; logic [2**(IdxW+1)-2:0] gnt_tree; logic [2**(IdxW+1)-2:0][IdxW-1:0] idx_tree; logic [2**(IdxW+1)-2:0][DW-1:0] data_tree; @@ -94,6 +93,8 @@ module prim_arbiter_fixed #( assign req_tree[Pa] = '0; assign idx_tree[Pa] = '0; assign data_tree[Pa] = '0; + logic unused_sigs; + assign unused_sigs = gnt_tree[Pa]; end // this creates the node assignments end else begin : gen_nodes @@ -119,8 +120,8 @@ module prim_arbiter_fixed #( if (EnDataPort) begin : gen_data_port assign data_o = data_tree[0]; end else begin : gen_no_dataport - logic [DW-1:0] unused_data [N]; - assign unused_data = data_i; + logic [DW-1:0] unused_data; + assign unused_data = data_tree[0]; assign data_o = '1; end diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_arbiter_tree.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_arbiter_tree.sv index ca39805546..992bc2ff46 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_arbiter_tree.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_arbiter_tree.sv @@ -75,12 +75,11 @@ module prim_arbiter_tree #( // a full binary tree with N levels has 2**N + 2**N-1 nodes logic [2**(IdxW+1)-2:0] req_tree; logic [2**(IdxW+1)-2:0] prio_tree; - logic [2**(IdxW+1)-2:0] rdy_tree; logic [2**(IdxW+1)-2:0] sel_tree; logic [2**(IdxW+1)-2:0] mask_tree; logic [2**(IdxW+1)-2:0][IdxW-1:0] idx_tree; logic [2**(IdxW+1)-2:0][DW-1:0] data_tree; - logic [2**IdxW-1:0] prio_mask_d, prio_mask_q; + logic [N-1:0] prio_mask_d, prio_mask_q; for (genvar level = 0; level < IdxW+1; level++) begin : gen_tree // @@ -130,9 +129,12 @@ module prim_arbiter_tree #( end else begin : gen_tie_off // forward path assign req_tree[Pa] = '0; + assign prio_tree[Pa] = '0; assign idx_tree[Pa] = '0; assign data_tree[Pa] = '0; - assign prio_mask_d[offset] = '0; + logic unused_sigs; + assign unused_sigs = ^{mask_tree[Pa], + sel_tree[Pa]}; end // this creates the node assignments end else begin : gen_nodes @@ -165,11 +167,15 @@ module prim_arbiter_tree #( if (EnDataPort) begin : gen_data_port assign data_o = data_tree[0]; end else begin : gen_no_dataport - logic [DW-1:0] unused_data [N]; - assign unused_data = data_i; + logic [DW-1:0] unused_data; + assign unused_data = data_tree[0]; assign data_o = '1; end + // This index is unused. + logic unused_prio_tree; + assign unused_prio_tree = prio_tree[0]; + assign idx_o = idx_tree[0]; assign valid_o = req_tree[0]; diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_assert.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_assert.sv index ddfc76a680..1e484e50cb 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_assert.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_assert.sv @@ -9,17 +9,6 @@ `ifndef PRIM_ASSERT_SV `define PRIM_ASSERT_SV -`ifdef UVM - // report assertion error with UVM if compiled - package assert_rpt_pkg; - import uvm_pkg::*; - `include "uvm_macros.svh" - function void assert_rpt(string msg); - `uvm_error("ASSERT FAILED", msg) - endfunction - endpackage -`endif - /////////////////// // Helper macros // /////////////////// @@ -31,6 +20,19 @@ // Converts an arbitrary block of code into a Verilog string `define PRIM_STRINGIFY(__x) `"__x`" +// ASSERT_ERROR logs an error message with either `uvm_error or with $error. +// +// This somewhat duplicates `DV_ERROR macro defined in hw/dv/sv/dv_utils/dv_macros.svh. The reason +// for redefining it here is to avoid creating a dependency. +`define ASSERT_ERROR(__name) \ +`ifdef UVM \ + uvm_pkg::uvm_report_error("ASSERT FAILED", `PRIM_STRINGIFY(__name), uvm_pkg::UVM_NONE, \ + `__FILE__, `__LINE__, "", 1); \ +`else \ + $error("%0t: (%0s:%0d) [%m] [ASSERT FAILED] %0s", $time, `__FILE__, `__LINE__, \ + `PRIM_STRINGIFY(__name)); \ +`endif + // The basic helper macros are actually defined in "implementation headers". The macros should do // the same thing in each case (except for the dummy flavour), but in a way that the respective // tools support. diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_assert_standard_macros.svh b/vendor/lowrisc_ip/ip/prim/rtl/prim_assert_standard_macros.svh index 7990379879..b6f3e980ee 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_assert_standard_macros.svh +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_assert_standard_macros.svh @@ -5,47 +5,38 @@ // Macro bodies included by prim_assert.sv for tools that support full SystemVerilog and SVA syntax. // See prim_assert.sv for documentation for each of the macros. -// ASSERT_RPT is available to change the reporting mechanism when an assert fails -`define ASSERT_RPT(__name) \ -`ifdef UVM \ - assert_rpt_pkg::assert_rpt($sformatf("[%m] %s (%s:%0d)", \ - __name, `__FILE__, `__LINE__)); \ -`else \ - $error("[ASSERT FAILED] [%m] %s (%s:%0d)", __name, `__FILE__, `__LINE__); \ -`endif - -`define ASSERT_I(__name, __prop) \ - __name: assert (__prop) \ - else begin \ - `ASSERT_RPT(`PRIM_STRINGIFY(__name)) \ +`define ASSERT_I(__name, __prop) \ + __name: assert (__prop) \ + else begin \ + `ASSERT_ERROR(__name) \ end -`define ASSERT_INIT(__name, __prop) \ - initial begin \ - __name: assert (__prop) \ - else begin \ - `ASSERT_RPT(`PRIM_STRINGIFY(__name)) \ - end \ +`define ASSERT_INIT(__name, __prop) \ + initial begin \ + __name: assert (__prop) \ + else begin \ + `ASSERT_ERROR(__name) \ + end \ end `define ASSERT_FINAL(__name, __prop) \ final begin \ __name: assert (__prop || $test$plusargs("disable_assert_final_checks")) \ else begin \ - `ASSERT_RPT(`PRIM_STRINGIFY(__name)) \ + `ASSERT_ERROR(__name) \ end \ end `define ASSERT(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ __name: assert property (@(posedge __clk) disable iff ((__rst) !== '0) (__prop)) \ else begin \ - `ASSERT_RPT(`PRIM_STRINGIFY(__name)) \ + `ASSERT_ERROR(__name) \ end `define ASSERT_NEVER(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ __name: assert property (@(posedge __clk) disable iff ((__rst) !== '0) not (__prop)) \ else begin \ - `ASSERT_RPT(`PRIM_STRINGIFY(__name)) \ + `ASSERT_ERROR(__name) \ end `define ASSERT_KNOWN(__name, __sig, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ @@ -57,11 +48,11 @@ `define ASSUME(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ __name: assume property (@(posedge __clk) disable iff ((__rst) !== '0) (__prop)) \ else begin \ - `ASSERT_RPT(`PRIM_STRINGIFY(__name)) \ + `ASSERT_ERROR(__name) \ end -`define ASSUME_I(__name, __prop) \ - __name: assume (__prop) \ - else begin \ - `ASSERT_RPT(`PRIM_STRINGIFY(__name)) \ +`define ASSUME_I(__name, __prop) \ + __name: assume (__prop) \ + else begin \ + `ASSERT_ERROR(__name) \ end diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_cipher_pkg.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_cipher_pkg.sv index 80929d1003..742c925363 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_cipher_pkg.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_cipher_pkg.sv @@ -208,7 +208,7 @@ package prim_cipher_pkg; logic [4:0] round_idx); logic [63:0] key_out; // rotate by 61 to the left - key_out = 64'(key_in << 61) | 64'(key_in >> (64-61)); + key_out = {key_in[63-61:0], key_in[63:64-61]}; // sbox on uppermost 4 bits key_out[63 -: 4] = PRESENT_SBOX4[key_out[63 -: 4]]; // xor in round counter on bits 19 to 15 @@ -220,7 +220,7 @@ package prim_cipher_pkg; logic [4:0] round_idx); logic [79:0] key_out; // rotate by 61 to the left - key_out = 80'(key_in << 61) | 80'(key_in >> (80-61)); + key_out = {key_in[79-61:0], key_in[79:80-61]}; // sbox on uppermost 4 bits key_out[79 -: 4] = PRESENT_SBOX4[key_out[79 -: 4]]; // xor in round counter on bits 19 to 15 @@ -232,7 +232,7 @@ package prim_cipher_pkg; logic [4:0] round_idx); logic [127:0] key_out; // rotate by 61 to the left - key_out = 128'(key_in << 61) | 128'(key_in >> (128-61)); + key_out = {key_in[127-61:0], key_in[127:128-61]}; // sbox on uppermost 4 bits key_out[127 -: 4] = PRESENT_SBOX4[key_out[127 -: 4]]; // sbox on second nibble from top @@ -245,46 +245,40 @@ package prim_cipher_pkg; // inverse key schedule function automatic logic [63:0] present_inv_update_key64(logic [63:0] key_in, - logic [4:0] round_idx, - // total number of rounds employed - logic [4:0] round_cnt); + logic [4:0] round_idx); logic [63:0] key_out = key_in; // xor in round counter on bits 19 to 15 - key_out[19:15] ^= round_cnt + 1 - round_idx; + key_out[19:15] ^= round_idx; // sbox on uppermost 4 bits key_out[63 -: 4] = PRESENT_SBOX4_INV[key_out[63 -: 4]]; // rotate by 61 to the right - key_out = 64'(key_out >> 61) | 64'(key_out << (64-61)); + key_out = {key_out[60:0], key_out[63:61]}; return key_out; endfunction : present_inv_update_key64 function automatic logic [79:0] present_inv_update_key80(logic [79:0] key_in, - logic [4:0] round_idx, - // total number of rounds employed - logic [4:0] round_cnt); + logic [4:0] round_idx); logic [79:0] key_out = key_in; // xor in round counter on bits 19 to 15 - key_out[19:15] ^= round_cnt + 1 - round_idx; + key_out[19:15] ^= round_idx; // sbox on uppermost 4 bits key_out[79 -: 4] = PRESENT_SBOX4_INV[key_out[79 -: 4]]; // rotate by 61 to the right - key_out = 80'(key_out >> 61) | 80'(key_out << (80-61)); + key_out = {key_out[60:0], key_out[79:61]}; return key_out; endfunction : present_inv_update_key80 function automatic logic [127:0] present_inv_update_key128(logic [127:0] key_in, - logic [4:0] round_idx, - // total number of rounds employed - logic [4:0] round_cnt); + logic [4:0] round_idx); logic [127:0] key_out = key_in; // xor in round counter on bits 66 to 62 - key_out[66:62] ^= round_cnt + 1 - round_idx; + key_out[66:62] ^= round_idx; // sbox on second highest nibble key_out[123 -: 4] = PRESENT_SBOX4_INV[key_out[123 -: 4]]; // sbox on uppermost 4 bits key_out[127 -: 4] = PRESENT_SBOX4_INV[key_out[127 -: 4]]; // rotate by 61 to the right - key_out = 128'(key_out >> 61) | 128'(key_out << (128-61)); + key_out = {key_out[60:0], key_out[127:61]}; return key_out; endfunction : present_inv_update_key128 @@ -296,7 +290,7 @@ package prim_cipher_pkg; logic [4:0] round_cnt); logic [63:0] key_out; key_out = key_in; - for (int k = 0; k < round_cnt; k++) begin + for (int unsigned k = 0; k < round_cnt; k++) begin key_out = present_update_key64(key_out, 5'(k + 1)); end return key_out; @@ -307,7 +301,7 @@ package prim_cipher_pkg; logic [4:0] round_cnt); logic [79:0] key_out; key_out = key_in; - for (int k = 0; k < round_cnt; k++) begin + for (int unsigned k = 0; k < round_cnt; k++) begin key_out = present_update_key80(key_out, 5'(k + 1)); end return key_out; @@ -318,7 +312,7 @@ package prim_cipher_pkg; logic [4:0] round_cnt); logic [127:0] key_out; key_out = key_in; - for (int k = 0; k < round_cnt; k++) begin + for (int unsigned k = 0; k < round_cnt; k++) begin key_out = present_update_key128(key_out, 5'(k + 1)); end return key_out; diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_clock_div.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_clock_div.sv new file mode 100644 index 0000000000..35dbbba773 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_clock_div.sv @@ -0,0 +1,84 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`include "prim_assert.sv" + +module prim_clock_div #( + parameter int Divisor = 2, + parameter logic ResetValue = 0 +) ( + input clk_i, + input rst_ni, + input test_en_i, + output logic clk_o +); + + + logic clk_int; + + if (Divisor == 2) begin : gen_div2 + logic q_p, q_n; + + prim_flop # ( + .Width(1), + .ResetValue(ResetValue) + ) u_div2 ( + .clk_i, + .rst_ni, + .d_i(q_n), + .q_o(q_p) + ); + + prim_clock_inv # ( + .HasScanMode(1'b0) + ) u_inv ( + .clk_i(q_p), + .scanmode_i('0), + .clk_no(q_n) + ); + + assign clk_int = q_p; + + end else begin : gen_div + // Only even divide is supported at the moment + // For odd divide we need to introduce more parameters to control duty cycle + `ASSERT_INIT(DivEven_A, (Divisor % 2) == 0) + + localparam int ToggleCnt = Divisor / 2; + localparam int CntWidth = $clog2(ToggleCnt); + logic [CntWidth-1:0] cnt; + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + cnt <= '0; + clk_int <= ResetValue; + end else if (cnt == ToggleCnt-1) begin + cnt <= '0; + clk_int <= ~clk_o; + end else begin + cnt <= cnt + 1'b1; + end + end + end + + // when in scanmode, bypass the dividers completely + // also anchor point for constraints + logic clk_muxed; + + prim_clock_mux2 #( + .NoFpgaBufG(1'b1) + ) u_clk_mux ( + .clk0_i(clk_int), + .clk1_i(clk_i), + .sel_i(test_en_i), + .clk_o(clk_muxed) + ); + + // anchor point for constraints + prim_clock_buf u_clk_div_buf ( + .clk_i(clk_muxed), + .clk_o + ); + +endmodule diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_dom_and_2share.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_dom_and_2share.sv index 391bc2f328..ec2f001926 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_dom_and_2share.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_dom_and_2share.sv @@ -30,11 +30,13 @@ module prim_dom_and_2share #( parameter int EnNegedge = 0 // Enable negedge of clk for register ) ( input clk_i, + input rst_ni, input [DW-1:0] a0_i, // share0 of a input [DW-1:0] a1_i, // share1 of a input [DW-1:0] b0_i, // share0 of b input [DW-1:0] b1_i, // share1 of b + input c_valid_i, // random number input validity input [DW-1:0] c0_i, // share0 of random number input [DW-1:0] c1_i, // share1 of random number @@ -56,14 +58,25 @@ module prim_dom_and_2share #( assign t1_d = t_a1b0 ^ c1_i; if (EnNegedge == 1) begin: gen_negreg - always_ff @(negedge clk_i) begin - t0_q <= t0_d; - t1_q <= t1_d; + // TODO: Make inverted clock and use. + always_ff @(negedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + t0_q <= '0; + t1_q <= '0; + end else if (c_valid_i) begin + t0_q <= t0_d; + t1_q <= t1_d; + end end end else begin: gen_posreg - always_ff @(posedge clk_i) begin - t0_q <= t0_d; - t1_q <= t1_d; + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + t0_q <= '0; + t1_q <= '0; + end else if (c_valid_i) begin + t0_q <= t0_d; + t1_q <= t1_d; + end end end @@ -72,10 +85,30 @@ module prim_dom_and_2share #( assign q0_o = t_a0b0 ^ t0_q; assign q1_o = t_a1b1 ^ t1_q; + // Negative Edge isn't yet supported. Need inverted clock and use + // inside always_ff not `negedge clk_i`. + `ASSERT_INIT(NegedgeNotSupported_A, EnNegedge == 0) + // DOM AND should be same as unmasked computation - if ( !(EnNegedge == 0)) begin: gen_andchk - `ASSERT(UnmaskedValue_A, q0_o ^ q1_o == (a0_i ^ a1_i) & (b0_i & b1_i), clk_i, 1'b0) - end + // TODO: Put assumption that input need to be stable for at least two cycles + // The correct test sequence will be: + // 1. inputs are changed + // 2. check if c_valid_i, + // 3. at the next cycle, inputs are still stable (assumption) + // 4. and results Q == A & B (assertion) + + // To speed up the FPV process, random value is ready in less than or + // equal to two cycles. + `ASSUME_FPV(RandomReadyInShortTime_A, + $changed(a0_i) || $changed(a1_i) || $changed(b0_i) || $changed(b1_i) + |-> ##[0:2] c_valid_i, + clk_i, !rst_ni) + `ASSERT(UnmaskedAndMatched_A, + $changed(a0_i) || $changed(a1_i) || $changed(b0_i) || $changed(b1_i) + |-> ##[0:$] c_valid_i + |=> $stable(a0_i) && $stable(a1_i) && $stable(b0_i) && $stable(b1_i) + |-> (q0_o ^ q1_o) == ((a0_i ^ a1_i) & (b0_i ^ b1_i)), + clk_i, !rst_ni) endmodule diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async.sv index 82b427f4db..3a7e8c15b5 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async.sv @@ -180,7 +180,7 @@ module prim_fifo_async #( logic [PTR_WIDTH-2:0] decval_in; logic unused_decval_msb; - decval_sub = Depth - {1'b0,decval[PTR_WIDTH-2:0]} - 1'b1; + decval_sub = (PTR_WIDTH)'(Depth) - {1'b0, decval[PTR_WIDTH-2:0]} - 1'b1; {unused_decval_msb, decval_in} = decval[PTR_WIDTH-1] ? decval_sub : decval; // Was done in two assigns for low bits and top bit @@ -196,7 +196,7 @@ module prim_fifo_async #( dec_tmp[PTR_WIDTH-2] = grayval[PTR_WIDTH-2]; for (int i = PTR_WIDTH-3; i >= 0; i--) dec_tmp[i] = dec_tmp[i+1]^grayval[i]; - {unused_decsub_msb, dec_tmp_sub} = Depth - {1'b0,dec_tmp} - 1'b1; + {unused_decsub_msb, dec_tmp_sub} = (PTR_WIDTH-1)'(Depth) - {1'b0, dec_tmp} - 1'b1; if (grayval[PTR_WIDTH-1]) gray2dec = {1'b1,dec_tmp_sub}; else diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_sync.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_sync.sv index c8e0aba09f..af559ace7d 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_sync.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_sync.sv @@ -83,7 +83,7 @@ module prim_fifo_sync #( end else if (clr_i) begin fifo_wptr <= {(PTR_WIDTH){1'b0}}; end else if (fifo_incr_wptr) begin - if (fifo_wptr[PTR_WIDTH-2:0] == (Depth-1)) begin + if (fifo_wptr[PTR_WIDTH-2:0] == (PTR_WIDTH-1)'(Depth-1)) begin fifo_wptr <= {~fifo_wptr[PTR_WIDTH-1],{(PTR_WIDTH-1){1'b0}}}; end else begin fifo_wptr <= fifo_wptr + {{(PTR_WIDTH-1){1'b0}},1'b1}; @@ -97,7 +97,7 @@ module prim_fifo_sync #( end else if (clr_i) begin fifo_rptr <= {(PTR_WIDTH){1'b0}}; end else if (fifo_incr_rptr) begin - if (fifo_rptr[PTR_WIDTH-2:0] == (Depth-1)) begin + if (fifo_rptr[PTR_WIDTH-2:0] == (PTR_WIDTH-1)'(Depth-1)) begin fifo_rptr <= {~fifo_rptr[PTR_WIDTH-1],{(PTR_WIDTH-1){1'b0}}}; end else begin fifo_rptr <= fifo_rptr + {{(PTR_WIDTH-1){1'b0}},1'b1}; diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_intr_hw.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_intr_hw.sv index 6198b31829..599179b85c 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_intr_hw.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_intr_hw.sv @@ -7,8 +7,13 @@ // This module can be instantiated once per interrupt field, or // "bussified" with all fields of the interrupt vector. -module prim_intr_hw #(parameter int unsigned Width = 1) ( +module prim_intr_hw # ( + parameter int unsigned Width = 1, + parameter bit FlopOutput = 1 +) ( // event + input clk_i, + input rst_ni, input [Width-1:0] event_intr_i, // register interface @@ -20,7 +25,7 @@ module prim_intr_hw #(parameter int unsigned Width = 1) ( output [Width-1:0] hw2reg_intr_state_d_o, // outgoing interrupt - output [Width-1:0] intr_o + output logic [Width-1:0] intr_o ); logic [Width-1:0] new_event; @@ -30,7 +35,24 @@ module prim_intr_hw #(parameter int unsigned Width = 1) ( // for scalar interrupts, this resolves to '1' with new event // for vector interrupts, new events are OR'd in to existing interrupt state assign hw2reg_intr_state_d_o = new_event | reg2hw_intr_state_q_i; - assign intr_o = reg2hw_intr_state_q_i & reg2hw_intr_enable_q_i; -endmodule + if (FlopOutput == 1) begin : gen_flop_intr_output + // flop the interrupt output + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + intr_o <= 1'b0; + end else begin + intr_o <= reg2hw_intr_state_q_i & reg2hw_intr_enable_q_i; + end + end + + end else begin : gen_intr_passthrough_output + logic unused_clk; + logic unused_rst_n; + assign unused_clk = clk_i; + assign unused_rst_n = rst_ni; + assign intr_o = reg2hw_intr_state_q_i & reg2hw_intr_enable_q_i; + end + +endmodule diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_keccak.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_keccak.sv index d247078fdd..7d4e0ae748 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_keccak.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_keccak.sv @@ -11,7 +11,7 @@ module prim_keccak #( localparam int W = Width/25, localparam int L = $clog2(W), localparam int MaxRound = 12 + 2*L, // Keccak-f only - localparam int RndW = $clog2(MaxRound) // Representing up to MaxRound-1 + localparam int RndW = $clog2(MaxRound+1) // Representing up to MaxRound ) ( input [RndW-1:0] rnd_i, // Current Round input [Width-1:0] s_i, diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sync.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sync.sv new file mode 100644 index 0000000000..516e2cb467 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sync.sv @@ -0,0 +1,58 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Double-synchronizer flop for life cycle control signals with additional +// output buffers and life-cycle specific assertions. +// +// Should be used exactly as recommended in the life cycle controller spec: +// https://docs.opentitan.org/hw/ip/lc_ctrl/doc/index.html#control-signal-propagation + +`include "prim_assert.sv" + +module prim_lc_sync #( + // Number of separately buffered output signals. + // The buffer cells have a don't touch constraint + // on them such that synthesis tools won't collapse + // all copies into one signal. + parameter int NumCopies = 1 +) ( + input clk_i, + input rst_ni, + input lc_ctrl_pkg::lc_tx_t lc_en_i, + output lc_ctrl_pkg::lc_tx_t [NumCopies-1:0] lc_en_o +); + + `ASSERT_INIT(NumCopiesMustBeGreaterZero_A, NumCopies > 0) + + logic [lc_ctrl_pkg::TxWidth-1:0] lc_en; + prim_flop_2sync #( + .Width(lc_ctrl_pkg::TxWidth), + .ResetValue(lc_ctrl_pkg::TxWidth'(lc_ctrl_pkg::Off)) + ) u_prim_flop_2sync ( + .clk_i, + .rst_ni, + .d_i(lc_en_i), + .q_o(lc_en) + ); + + logic [NumCopies-1:0][lc_ctrl_pkg::TxWidth-1:0] lc_en_copies; + for (genvar j = 0; j < NumCopies; j++) begin : gen_buffs + for (genvar k = 0; k < lc_ctrl_pkg::TxWidth; k++) begin : gen_bits + // TODO: replace this with a normal buffer primitive, once available. + prim_clock_buf u_prim_clock_buf ( + .clk_i(lc_en[k]), + .clk_o(lc_en_copies[j][k]) + ); + end + end + + assign lc_en_o = lc_en_copies; + + //////////////// + // Assertions // + //////////////// + + // TODO: add more assertions + +endmodule : prim_lc_sync diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_lfsr.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_lfsr.sv index cf356422bc..b78f4b8cb4 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_lfsr.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_lfsr.sv @@ -39,6 +39,10 @@ module prim_lfsr #( parameter logic [LfsrDw-1:0] DefaultSeed = LfsrDw'(1), // Custom polynomial coeffs parameter logic [LfsrDw-1:0] CustomCoeffs = '0, + // If StatePermEn is set to 1, the custom permutation specified via StatePerm is applied + // to the state output, in order to break linear shifting patterns of the LFSR. + parameter bit StatePermEn = 1'b0, + parameter logic [LfsrDw-1:0][$clog2(LfsrDw)-1:0] StatePerm = '0, // Enable this for DV, disable this for long LFSRs in FPV parameter bit MaxLenSVA = 1'b1, // Can be disabled in cases where seed and entropy @@ -363,7 +367,13 @@ module prim_lfsr #( (lfsr_en_i) ? next_lfsr_state : lfsr_q; - assign state_o = lfsr_q[StateOutDw-1:0]; + if (StatePermEn) begin : gen_state_perm + for (genvar k = 0; k < StateOutDw; k++) begin : gen_perm_loop + assign state_o[k] = lfsr_q[StatePerm[k]]; + end + end else begin : gen_no_state_perm + assign state_o = lfsr_q[StateOutDw-1:0]; + end always_ff @(posedge clk_i or negedge rst_ni) begin : p_reg if (!rst_ni) begin @@ -418,6 +428,21 @@ module prim_lfsr #( // check whether next state is computed correctly `ASSERT(NextStateCheck_A, lfsr_en_i && !seed_en_i |=> lfsr_q == compute_next_state(coeffs, $past(entropy_i,1), $past(lfsr_q,1))) + + // Only check this if enabled. + if (StatePermEn) begin : gen_perm_check + // Check that the supplied permutation is valid. + logic [LfsrDw-1:0] lfsr_perm_test; + initial begin : p_perm_check + lfsr_perm_test = '0; + for (int k = 0; k < LfsrDw; k++) begin + lfsr_perm_test[StatePerm[k]] = 1'b1; + end + // All bit positions must be marked with 1. + `ASSERT_I(PermutationCheck_A, &lfsr_perm_test) + end + end + `endif `ASSERT_INIT(InputWidth_A, LfsrDw >= EntropyDw) @@ -428,8 +453,9 @@ module prim_lfsr #( // output check `ASSERT_KNOWN(OutputKnown_A, state_o) - `ASSERT(OutputCheck_A, state_o == StateOutDw'(lfsr_q)) - + if (!StatePermEn) begin : gen_output_sva + `ASSERT(OutputCheck_A, state_o == StateOutDw'(lfsr_q)) + end // if no external input changes the lfsr state, a lockup must not occur (by design) //`ASSERT(NoLockups_A, (!entropy_i) && (!seed_en_i) |=> !lockup, clk_i, !rst_ni) `ASSERT(NoLockups_A, lfsr_en_i && !entropy_i && !seed_en_i |=> !lockup) diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_multibit_sync.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_multibit_sync.sv new file mode 100644 index 0000000000..99d3b74635 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_multibit_sync.sv @@ -0,0 +1,103 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// WARNING: DO NOT USE THIS MODULE IF YOU DO NOT HAVE A GOOD REASON TO DO SO. +// +// This module is only meant to be used in special cases where a handshake synchronizer +// is not viable (this is for instance the case for the multibit life cycle signals). +// For handshake-based synchronization, consider using prim_sync_reqack. +// +// +// Description: +// +// This module implements a multibit synchronizer that employs a data consistency check to +// decide whether the synchronized multibit signal is stable and can be output or not. +// +// The number of consistency checkers can be controlled via NumChecks. Each check adds another +// delay register after the 2-flop synchronizer, and corresponding comparator that checks whether +// the register input is equal to the output of the last register in the chain. If all checks are +// successful, the output register is enabled such that the data can propagate to the output. +// +// This is illustrated bellow for NumChecks = 1: +// +// /--------\ /--------\ /--------\ +// | | | | | | +// data_i --/--> | flop | --x--> | flop | --x--> | flop | --/--> data_o +// Width | 2 sync | | | | | | | +// | | | | | | | en | +// \--------/ | \--------/ | \--------/ +// | v ^ +// | /----\ | +// \-------------> | == | ----/ +// \----/ +// +// Note: CDC tools will likely flag this module due to re-convergent logic. +// + +`include "prim_assert.sv" + +module prim_multibit_sync #( + // Width of the multibit signal. + parameter int Width = 8, + // Number of cycles the synchronized multi-bit signal needs to + // be stable until it is relased to the output. Each check adds + // a comparator and an additional delay register. + parameter int NumChecks = 1, + // Reset value of the multibit signal. + parameter logic [Width-1:0] ResetValue = '0 +) ( + input clk_i, + input rst_ni, + input logic [Width-1:0] data_i, + output logic [Width-1:0] data_o +); + + `ASSERT_INIT(NumChecks_A, NumChecks >= 1) + + // First, synchronize the input data to this clock domain. + logic [NumChecks:0][Width-1:0] data_check_d; + logic [NumChecks-1:0][Width-1:0] data_check_q; + + prim_generic_flop_2sync #( + .Width(Width), + .ResetValue(ResetValue) + ) i_prim_generic_flop_2sync ( + .clk_i, + .rst_ni, + .d_i(data_i), + .q_o(data_check_d[0]) + ); + + // Shift register. + assign data_check_d[NumChecks:1] = data_check_q[NumChecks-1:0]; + + // Consistency check. Always compare to the output of the last register. + logic [NumChecks-1:0] checks; + for (genvar k = 0; k < NumChecks; k++) begin : gen_checks + assign checks[k] = (data_check_d[k] == data_check_d[NumChecks]); + // Output is only allowed to change when all checks have passed. + `ASSERT(StableCheck_A, + data_o != $past(data_o) + |-> + $past(data_check_d[k]) == $past(data_check_d[NumChecks])) + end : gen_checks + + // Only propagate to output register if all checks have passed. + logic [Width-1:0] data_synced_d, data_synced_q; + assign data_synced_d = (&checks) ? data_check_d[NumChecks] : data_synced_q; + assign data_o = data_synced_q; + + always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs + if (!rst_ni) begin + data_synced_q <= ResetValue; + data_check_q <= {NumChecks{ResetValue}}; + end else begin + data_synced_q <= data_synced_d; + data_check_q <= data_check_d[NumChecks-1:0]; + end + end + + `ASSERT_KNOWN(DataKnown_A, data_o) + +endmodule : prim_multibit_sync diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_packer.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_packer.sv index 8ddee7d8c0..676d2b6530 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_packer.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_packer.sv @@ -30,7 +30,6 @@ module prim_packer #( localparam int Width = InW + OutW; // storage width localparam int ConcatW = Width + InW; // Input concatenated width localparam int PtrW = $clog2(ConcatW+1); - localparam int MaxW = (InW > OutW) ? InW : OutW; localparam int IdxW = $clog2(InW) + ~|$clog2(InW); logic valid_next, ready_next; @@ -87,7 +86,7 @@ module prim_packer #( lod_idx = 0; for (int i = InW-1; i >= 0 ; i--) begin if (mask_i[i] == 1'b1) begin - lod_idx = i; + lod_idx = $unsigned(i); end end end @@ -236,11 +235,6 @@ module prim_packer #( valid_i |-> $countones(mask_i ^ {mask_i[InW-2:0],1'b0}) <= 2) end - // Assume data pattern to reduce FPV test time - //`ASSUME_FPV(FpvDataWithin_M, - // data_i inside {'0, '1, 32'hDEAD_BEEF}, - // clk_i, !rst_ni) - // Flush and Write Enable cannot be asserted same time `ASSUME(ExFlushValid_M, flush_i |-> !valid_i) @@ -252,8 +246,6 @@ module prim_packer #( `ASSUME(DataIStable_M, ##1 valid_i && $past(valid_i) && !$past(ready_o) |-> $stable(data_i) && $stable(mask_i)) - `ASSUME(ValidIPairedWithReadyO_M, - valid_i && !ready_o |=> valid_i) `ASSERT(FlushFollowedByDone_A, ##1 $rose(flush_i) && !flush_done_o |-> !flush_done_o [*0:$] ##1 flush_done_o) diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_packer_fifo.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_packer_fifo.sv new file mode 100755 index 0000000000..f76f779e60 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_packer_fifo.sv @@ -0,0 +1,165 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Supports packed and unpacked modes +// Uses FIFO timing on the control signals +// No masking or flush functions supported + +// Timings - case where InW < OutW +// clk_i __|~~|__~~|__|~~|__~~|__|~~|__~~|__|~~|__~~|__|~~|__~~|__|~~|__ +// wvalid_i _____|~~~~|_____|~~~~|_____|~~~~|_____|~~~~|___________________ +// wdata_i Val N |Val N+1 |Val N+2 |Val N+3 |------------------- +// wready_o ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|__________|~~~~~~~~ +// rvalid_o ___________________________________________|~~~~~~~~~~|________ +// rdata_o -------------------------------------------|Val |-------- +// rready_i _________________________________________________|~~~~|________ +// depth_o 0000000000|1111111111|2222222222|3333333333|4444444444|00000000 + + +// Timings - case where InW > OutW +// clk_i __|~~|__~~|__|~~|__~~|__|~~|__~~|__|~~|__~~|__|~~|__~~|__|~~|__ +// wvalid_i _____|~~~~|____________________________________________________ +// wdata_i -----|Val |---------------------------------------------------- +// wready_o ~~~~~~~~~~|___________________________________________|~~~~~~~~ +// rvalid_o __________|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|________ +// rdata_o ----------|Val N |Val N+1 |Val N+2 |Val N+3 |-------- +// rready_i ________________|~~~~|_____|~~~~|_____|~~~~|_____|~~~~|________ +// depth_o 0000000000|4444444444|3333333333|2222222222|1111111111|00000000 + + +// Timings - case where InW = OutW +// clk_i __|~~|__~~|__|~~|__~~|__|~~|__~~|__|~~|__~~|__|~~|__~~|__|~~|__ +// wvalid_i _____|~~~~|____________________________________________________ +// wdata_i -----|Val |---------------------------------------------------- +// wready_o ~~~~~~~~~~|__________|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// rvalid_o __________|~~~~~~~~~~|_________________________________________ +// rdata_o ----------|Val |----------------------------------------- +// rready_i ________________|~~~~|_________________________________________ +// depth_o 0000000000|1111111111|00000000000000000000000000000000000000000 + + +`include "prim_assert.sv" + +module prim_packer_fifo #( + parameter int InW = 32, + parameter int OutW = 8, + // derived parameters + localparam int MaxW = (InW > OutW) ? InW : OutW, + localparam int MinW = (InW < OutW) ? InW : OutW, +// localparam int DepthW = $clog2(MaxW/MinW) + ~|$clog2(MaxW/MinW) + localparam int DepthW = $clog2(MaxW/MinW) +) ( + input logic clk_i , + input logic rst_ni, + + input logic clr_i, + input logic wvalid_i, + input logic [InW-1:0] wdata_i, + output logic wready_o, + + output logic rvalid_o, + output logic [OutW-1:0] rdata_o, + input logic rready_i, + output logic [DepthW:0] depth_o +); + + + // signals + logic load_data; + logic clear_data; + + // flops + logic [DepthW:0] depth_q, depth_d; + logic [MaxW-1:0] data_q, data_d; + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + depth_q <= '0; + data_q <= '0; + end else begin + depth_q <= depth_d; + data_q <= data_d; + end + end + + assign depth_o = depth_q; + + if (InW < OutW) begin : gen_pack_mode + logic [MaxW-1:0] wdata_shifted; + + assign wdata_shifted = wdata_i << (depth_q*InW); + assign clear_data = (rready_i && rvalid_o) || clr_i; + assign load_data = wvalid_i && wready_o; + + assign depth_d = clear_data ? '0 : + load_data ? depth_q+1 : + depth_q; + + assign data_d = clear_data ? '0 : + load_data ? (data_q | wdata_shifted) : + data_q; + + // set outputs + assign wready_o = !(depth_q == (MaxW/MinW)); + assign rdata_o = data_q; + assign rvalid_o = (depth_q == (MaxW/MinW)); + + end else begin : gen_unpack_mode + logic [MaxW-1:0] rdata_shifted; // ri lint_check_waive NOT_READ + logic pull_data; + logic [DepthW:0] ptr_q, ptr_d; + logic [DepthW:0] lsb_is_one; + logic [DepthW:0] max_value; + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + ptr_q <= '0; + end else begin + ptr_q <= ptr_d; + end + end + + assign lsb_is_one = {{DepthW{1'b0}},1'b1}; // ri lint_check_waive ZERO_REP + assign max_value = (MaxW/MinW); + assign rdata_shifted = data_q >> ptr_q*OutW; + assign clear_data = (rready_i && (depth_q == lsb_is_one)) || clr_i; + assign load_data = wvalid_i && wready_o; + assign pull_data = rvalid_o && rready_i; + + assign depth_d = clear_data ? '0 : + load_data ? max_value : + pull_data ? depth_q-1 : + depth_q; + + assign ptr_d = clear_data ? '0 : + pull_data ? ptr_q+1 : + ptr_q; + + assign data_d = clear_data ? '0 : + load_data ? wdata_i : + data_q; + + // set outputs + assign wready_o = (depth_q == '0); + assign rdata_o = rdata_shifted[OutW-1:0]; + assign rvalid_o = !(depth_q == '0); + + end + + + ////////////////////////////////////////////// + // Assertions, Assumptions, and Coverpoints // + ////////////////////////////////////////////// + + // If not acked, valid_o should keep asserting + `ASSERT(ValidOPairedWidthReadyI_A, + rvalid_o && !rready_i |=> rvalid_o) + + // If output port doesn't accept the data, the data should be stable + `ASSERT(DataOStableWhenPending_A, + ##1 rvalid_o && $past(rvalid_o) + && !$past(rready_i) |-> $stable(rdata_o)) + + +endmodule diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_present.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_present.sv index 6727914050..52adb3b896 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_present.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_present.sv @@ -18,44 +18,60 @@ // - https://en.wikipedia.org/wiki/Prince_(cipher) // - http://www.lightweightcrypto.org/present/present_ches2007.pdf // - https://eprint.iacr.org/2012/529.pdf -// - https://csrc.nist.gov/csrc/media/events/lightweight-cryptography-workshop-2015/documents/papers/session7-maene-paper.pdf +// - https://csrc.nist.gov/csrc/media/events/lightweight-cryptography-workshop-2015/ +// documents/papers/session7-maene-paper.pdf -// TODO: this module has not been verified yet, and has only been used in -// synthesis experiments. `include "prim_assert.sv" module prim_present #( parameter int DataWidth = 64, // {32, 64} parameter int KeyWidth = 128, // {64, 80, 128} - parameter int NumRounds = 31, // > 0 + // Number of rounds to perform in total (>0) + parameter int NumRounds = 31, + // Number of physically instantiated PRESENT rounds. + // This can be used to construct e.g. an iterative + // full-round implementation that only has one physical + // round instance by setting NumRounds = 31 and NumPhysRounds = 1. + // Note that NumPhysRounds needs to divide NumRounds. + parameter int NumPhysRounds = NumRounds, // Note that the decryption pass needs a modified key, // to be calculated by performing NumRounds key updates parameter bit Decrypt = 0 // 0: encrypt, 1: decrypt ) ( input [DataWidth-1:0] data_i, input [KeyWidth-1:0] key_i, + // Starting round index for keyschedule [1 ... 31]. + // Set this to 5'd1 for a fully unrolled encryption, and 5'd31 for a fully unrolled decryption. + input [4:0] idx_i, output logic [DataWidth-1:0] data_o, - output logic [KeyWidth-1:0] key_o + output logic [KeyWidth-1:0] key_o, + // Next round index for keyschedule + // (Enc: idx_i + NumPhysRounds, Dec: idx_i - NumPhysRounds) + // Can be ignored for a fully unrolled implementation. + output logic [4:0] idx_o ); ////////////// // datapath // ////////////// - logic [NumRounds:0][DataWidth-1:0] data_state; - logic [NumRounds:0][KeyWidth-1:0] round_key; + logic [NumPhysRounds:0][DataWidth-1:0] data_state; + logic [NumPhysRounds:0][KeyWidth-1:0] round_key; + logic [NumPhysRounds:0][4:0] round_idx; // initialize assign data_state[0] = data_i; assign round_key[0] = key_i; + assign round_idx[0] = idx_i; - for (genvar k = 0; k < NumRounds; k++) begin : gen_round + for (genvar k = 0; k < NumPhysRounds; k++) begin : gen_round logic [DataWidth-1:0] data_state_xor, data_state_sbox; // cipher layers assign data_state_xor = data_state[k] ^ round_key[k][KeyWidth-1 : KeyWidth-DataWidth]; - //////////////////////////////// // decryption pass, performs inverse permutation, sbox and keyschedule if (Decrypt) begin : gen_dec + // Decrement round count. + assign round_idx[k+1] = round_idx[k] - 1'b1; // original 64bit variant if (DataWidth == 64) begin : gen_d64 assign data_state_sbox = prim_cipher_pkg::perm_64bit(data_state_xor, @@ -73,22 +89,21 @@ module prim_present #( // original 128bit key variant if (KeyWidth == 128) begin : gen_k128 assign round_key[k+1] = prim_cipher_pkg::present_inv_update_key128(round_key[k], - 5'(k + 1), - 5'(NumRounds)); + round_idx[k]); // original 80bit key variant end else if (KeyWidth == 80) begin : gen_k80 assign round_key[k+1] = prim_cipher_pkg::present_inv_update_key80(round_key[k], - 5'(k + 1), - 5'(NumRounds)); + round_idx[k]); // reduced 64bit key variant end else begin : gen_k64 assign round_key[k+1] = prim_cipher_pkg::present_inv_update_key64(round_key[k], - 5'(k + 1), - 5'(NumRounds)); + round_idx[k]); end //////////////////////////////// // encryption pass end else begin : gen_enc + // Increment round count. + assign round_idx[k+1] = round_idx[k] + 1'b1; // original 64bit variant if (DataWidth == 64) begin : gen_d64 assign data_state_sbox = prim_cipher_pkg::sbox4_64bit(data_state_xor, @@ -105,21 +120,29 @@ module prim_present #( // update round key, count goes from 1 to 31 (max) // original 128bit key variant if (KeyWidth == 128) begin : gen_k128 - assign round_key[k+1] = prim_cipher_pkg::present_update_key128(round_key[k], 5'(k + 1)); + assign round_key[k+1] = prim_cipher_pkg::present_update_key128(round_key[k], round_idx[k]); // original 80bit key variant end else if (KeyWidth == 80) begin : gen_k80 - assign round_key[k+1] = prim_cipher_pkg::present_update_key80(round_key[k], 5'(k + 1)); + assign round_key[k+1] = prim_cipher_pkg::present_update_key80(round_key[k], round_idx[k]); // reduced 64bit key variant end else begin : gen_k64 - assign round_key[k+1] = prim_cipher_pkg::present_update_key64(round_key[k], 5'(k + 1)); + assign round_key[k+1] = prim_cipher_pkg::present_update_key64(round_key[k], round_idx[k]); end end // gen_enc //////////////////////////////// end // gen_round - // finalize - assign data_o = data_state[NumRounds] ^ round_key[NumRounds][KeyWidth-1 : KeyWidth-DataWidth]; - assign key_o = round_key[NumRounds]; + // This only needs to be applied after the last round. + // Note that for a full-round implementation the output index + // will be 0 for enc/dec for the last round (either due to wraparound or subtraction). + localparam int LastRoundIdx = (Decrypt != 0 || NumRounds == 31) ? 0 : NumRounds+1; + assign data_o = (idx_o == LastRoundIdx) ? + data_state[NumPhysRounds] ^ + round_key[NumPhysRounds][KeyWidth-1 : KeyWidth-DataWidth] : + data_state[NumPhysRounds]; + + assign key_o = round_key[NumPhysRounds]; + assign idx_o = round_idx[NumPhysRounds]; //////////////// // assertions // @@ -128,5 +151,8 @@ module prim_present #( `ASSERT_INIT(SupportedWidths_A, (DataWidth == 64 && KeyWidth inside {80, 128}) || (DataWidth == 32 && KeyWidth == 64)) `ASSERT_INIT(SupportedNumRounds_A, NumRounds > 0 && NumRounds <= 31) + `ASSERT_INIT(SupportedNumPhysRounds0_A, NumPhysRounds > 0 && NumPhysRounds <= NumRounds) + // Currently we do not support other arrangements + `ASSERT_INIT(SupportedNumPhysRounds1_A, (NumRounds % NumPhysRounds) == 0) endmodule : prim_present diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_prince.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_prince.sv index 423a7ca217..97b075d5a4 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_prince.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_prince.sv @@ -16,14 +16,12 @@ // References: - https://en.wikipedia.org/wiki/PRESENT // - https://en.wikipedia.org/wiki/Prince_(cipher) // - http://www.lightweightcrypto.org/present/present_ches2007.pdf -// - https://csrc.nist.gov/csrc/media/events/lightweight-cryptography-workshop-2015/documents/papers/session7-maene-paper.pdf +// - https://csrc.nist.gov/csrc/media/events/lightweight-cryptography-workshop-2015/ +// documents/papers/session7-maene-paper.pdf // - https://eprint.iacr.org/2012/529.pdf // - https://eprint.iacr.org/2015/372.pdf // - https://eprint.iacr.org/2014/656.pdf - -// TODO: this module has not been verified yet, and has only been used in -// synthesis experiments. `include "prim_assert.sv" module prim_prince #( parameter int DataWidth = 64, @@ -68,10 +66,18 @@ module prim_prince #( end if (UseOldKeySched) begin : gen_legacy_keyschedule + // In this case we constantly use k1. assign k0_new_d = k1_d; end else begin : gen_new_keyschedule - // improved keyschedule proposed by https://eprint.iacr.org/2014/656.pdf - assign k0_new_d = k0; + // Imroved keyschedule proposed by https://eprint.iacr.org/2014/656.pdf + // In this case we alternate between k1 and k0. + always_comb begin : p_new_keyschedule_k0_alpha + k0_new_d = key_i[DataWidth-1:0]; + // We need to apply the alpha constant here as well, just as for k1 in decryption mode. + if (dec_i) begin + k0_new_d ^= prim_cipher_pkg::PRINCE_ALPHA_CONST[DataWidth-1:0]; + end + end end if (HalfwayKeyReg) begin : gen_key_reg @@ -133,8 +139,11 @@ module prim_prince #( assign data_state_xor = data_state_round ^ prim_cipher_pkg::PRINCE_ROUND_CONST[k][DataWidth-1:0]; // improved keyschedule proposed by https://eprint.iacr.org/2014/656.pdf - if (k % 2 == 1) assign data_state[k] = data_state_xor ^ k0_new_d; - else assign data_state[k] = data_state_xor ^ k1_d; + if (k % 2 == 1) begin : gen_fwd_key_odd + assign data_state[k] = data_state_xor ^ k0_new_d; + end else begin : gen_fwd_key_even + assign data_state[k] = data_state_xor ^ k1_d; + end end // middle part @@ -183,8 +192,11 @@ module prim_prince #( for (genvar k = 1; k <= NumRoundsHalf; k++) begin : gen_bwd_pass logic [DataWidth-1:0] data_state_xor0, data_state_xor1; // improved keyschedule proposed by https://eprint.iacr.org/2014/656.pdf - if (k % 2 == 1) assign data_state_xor0 = data_state[NumRoundsHalf+k] ^ k0_new_q; - else assign data_state_xor0 = data_state[NumRoundsHalf+k] ^ k1_q; + if ((NumRoundsHalf + k + 1) % 2 == 1) begin : gen_bkwd_key_odd + assign data_state_xor0 = data_state[NumRoundsHalf+k] ^ k0_new_q; + end else begin : gen_bkwd_key_even + assign data_state_xor0 = data_state[NumRoundsHalf+k] ^ k1_q; + end // the construction is reflective, hence the subtraction with NumRoundsHalf assign data_state_xor1 = data_state_xor0 ^ prim_cipher_pkg::PRINCE_ROUND_CONST[10-NumRoundsHalf+k][DataWidth-1:0]; diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1p_adv.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1p_adv.sv index e11ca9d2de..51c7a313a5 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1p_adv.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1p_adv.sv @@ -46,7 +46,8 @@ module prim_ram_1p_adv #( input [CfgW-1:0] cfg_i ); - logic [CfgW-1:0] unused_cfg = cfg_i; + logic [CfgW-1:0] unused_cfg; + assign unused_cfg = cfg_i; `ASSERT_INIT(CannotHaveEccAndParity_A, !(EnableParity && EnableECC)) @@ -116,17 +117,27 @@ module prim_ram_1p_adv #( ///////////////////////////// if (EnableParity == 0 && EnableECC) begin : gen_secded + logic unused_wmask; + assign unused_wmask = ^wmask_i; // check supported widths - `ASSERT_INIT(SecDecWidth_A, Width inside {32}) + `ASSERT_INIT(SecDecWidth_A, Width inside {16, 32}) // the wmask is constantly set to 1 in this case `ASSERT(OnlyWordWritePossibleWithEccPortA_A, req_i |-> - wmask_i == {TotalWidth{1'b1}}) + wmask_i == {Width{1'b1}}) assign wmask_d = {TotalWidth{1'b1}}; - if (Width == 32) begin : gen_secded_39_32 + if (Width == 16) begin : gen_secded_22_16 + prim_secded_22_16_enc u_enc (.in(wdata_i), .out(wdata_d)); + prim_secded_22_16_dec u_dec ( + .in (rdata_sram), + .d_o (rdata_d[0+:Width]), + .syndrome_o ( ), + .err_o (rerror_d) + ); + end else if (Width == 32) begin : gen_secded_39_32 prim_secded_39_32_enc u_enc (.in(wdata_i), .out(wdata_d)); prim_secded_39_32_dec u_dec ( .in (rdata_sram), @@ -135,6 +146,7 @@ module prim_ram_1p_adv #( .err_o (rerror_d) ); end + end else if (EnableParity) begin : gen_byte_parity `ASSERT_INIT(WidthNeedsToBeByteAligned_A, Width % 8 == 0) diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1p_scr.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1p_scr.sv index e08b919a1e..39a646e128 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1p_scr.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1p_scr.sv @@ -19,9 +19,6 @@ // that nonce, the address mapping is not fully baked into RTL and can be changed at runtime as // well. // -// Note that this design is not final nor tested, and its main purpose is to be instantiated in -// Bronze for area and timing estimates. -// // See also: prim_cipher_pkg, prim_prince `include "prim_assert.sv" @@ -30,7 +27,7 @@ module prim_ram_1p_scr #( parameter int Depth = 512, // Needs to be a power of 2 if NumAddrScrRounds > 0. parameter int Width = 256, // Needs to be Byte aligned for parity parameter int DataBitsPerMask = 8, // Currently only 8 is supported - parameter int CfgW = 8, // WTC, RTC, etc + parameter int CfgWidth = 8, // WTC, RTC, etc // Scrambling parameters. Note that this needs to be low-latency, hence we have to keep the // amount of cipher rounds low. PRINCE has 5 half rounds in its original form, which corresponds @@ -54,16 +51,16 @@ module prim_ram_1p_scr #( // This is given by the PRINCE cipher primitive. All parallel cipher modules // use the same key, but they use a different IV localparam int DataKeyWidth = 128, - // Each scrambling primitive requires a 64bit IV composed of {nonce, address} - localparam int DataNonceWidth = (64-AddrWidth) * NumParScr + // Each 64 bit scrambling primitive requires a 64bit IV + localparam int NonceWidth = 64 * NumParScr ) ( input clk_i, input rst_ni, input [DataKeyWidth-1:0] key_i, - input [DataNonceWidth-1:0] data_nonce_i, - input [AddrWidth-1:0] addr_nonce_i, + input [NonceWidth-1:0] nonce_i, + // Interface to TL-UL SRAM adapter input req_i, input write_i, input [AddrWidth-1:0] addr_i, @@ -72,9 +69,10 @@ module prim_ram_1p_scr #( output logic [Width-1:0] rdata_o, output logic rvalid_o, // Read response (rdata_o) is valid output logic [1:0] rerror_o, // Bit1: Uncorrectable, Bit0: Correctable + output logic [AddrWidth-1:0] raddr_o, // Read address for error reporting. // config - input [CfgW-1:0] cfg_i + input [CfgWidth-1:0] cfg_i ); ////////////////////// @@ -83,8 +81,6 @@ module prim_ram_1p_scr #( // The depth needs to be a power of 2 in case address scrambling is turned on `ASSERT_INIT(DepthPow2Check_A, NumAddrScrRounds <= '0 || 2**$clog2(Depth) == Depth) - // The address nonce should be set to 0 if address scrambling is disabled - `ASSERT(AddrNonceCheck_A, NumAddrScrRounds <= '0 |-> addr_nonce_i == '0) ///////////////////////////////////////// // Pending Write and Address Registers // @@ -131,15 +127,28 @@ module prim_ram_1p_scr #( // This creates a bijective address mapping using a substitution / permutation network. logic [AddrWidth-1:0] addr_scr; - prim_subst_perm #( - .DataWidth ( AddrWidth ), - .NumRounds ( NumAddrScrRounds ), - .Decrypt ( 0 ) - ) i_prim_subst_perm ( - .data_i ( addr_mux ), - .key_i ( addr_nonce_i ), - .data_o ( addr_scr ) - ); + if (NumAddrScrRounds > 0) begin : gen_addr_scr + prim_subst_perm #( + .DataWidth ( AddrWidth ), + .NumRounds ( NumAddrScrRounds ), + .Decrypt ( 0 ) + ) i_prim_subst_perm ( + .data_i ( addr_mux ), + // Since the counter mode concatenates {nonce_i[NonceWidth-1-AddrWidth:0], addr_i} to form + // the IV, the upper AddrWidth bits of the nonce are not used and can be used for address + // scrambling. In cases where N parallel PRINCE blocks are used due to a data + // width > 64bit, N*AddrWidth nonce bits are left dangling. + .key_i ( nonce_i[NonceWidth - 1 : NonceWidth - AddrWidth] ), + .data_o ( addr_scr ) + ); + end else begin : gen_no_addr_scr + assign addr_scr = addr_mux; + end + + // We latch the non-scrambled address for error reporting. + logic [AddrWidth-1:0] raddr_d, raddr_q; + assign raddr_d = addr_mux; + assign raddr_o = raddr_q; ////////////////////////////////////////////// // Keystream Generation for Data Scrambling // @@ -162,7 +171,7 @@ module prim_ram_1p_scr #( .rst_ni, .valid_i ( req_i ), // The IV is composed of a nonce and the row address - .data_i ( {data_nonce_i[k * (64 - AddrWidth) +: (64 - AddrWidth)], addr_i} ), + .data_i ( {nonce_i[k * (64 - AddrWidth) +: (64 - AddrWidth)], addr_i} ), // All parallel scramblers use the same key .key_i, // Since we operate in counter mode, this can always be set to encryption mode @@ -171,6 +180,13 @@ module prim_ram_1p_scr #( .data_o ( keystream[k * 64 +: 64] ), .valid_o ( ) ); + + // Unread unused bits from keystream + if (k == NumParKeystr-1 && (Width % 64) > 0) begin : gen_unread_last + localparam int UnusedWidth = 64 - (Width % 64); + logic [UnusedWidth-1:0] unused_keystream; + assign unused_keystream = keystream[(k+1) * 64 - 1 -: UnusedWidth]; + end end // Replicate keystream if needed @@ -192,7 +208,7 @@ module prim_ram_1p_scr #( // Write path. Note that since this does not fan out into the interconnect, the write path is not // as critical as the read path below in terms of timing. - logic [Width-1:0] wdata_scr_d, wdata_scr_q; + logic [Width-1:0] wdata_scr_d, wdata_scr_q, wdata_q; for (genvar k = 0; k < Width/8; k++) begin : gen_diffuse_wdata // Apply the keystream first logic [7:0] wdata_xor; @@ -272,7 +288,6 @@ module prim_ram_1p_scr #( // Registers // /////////////// - logic [Width-1:0] wdata_q; logic [Width-1:0] wmask_q; always_ff @(posedge clk_i or negedge rst_ni) begin : p_wdata_buf if (!rst_ni) begin @@ -284,11 +299,13 @@ module prim_ram_1p_scr #( wdata_q <= '0; wdata_scr_q <= '0; wmask_q <= '0; + raddr_q <= '0; end else begin write_scr_pending_q <= write_scr_pending_d; write_pending_q <= write_pending_d; collision_q <= collision_d; rvalid_q <= read_en; + raddr_q <= raddr_d; if (write_en) begin waddr_q <= addr_i; wmask_q <= wmask_i; @@ -308,7 +325,7 @@ module prim_ram_1p_scr #( .Depth(Depth), .Width(Width), .DataBitsPerMask(DataBitsPerMask), - .CfgW(CfgW), + .CfgW(CfgWidth), .EnableECC(1'b0), .EnableParity(1'b1), // We are using Byte parity .EnableInputPipeline(1'b0), diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_2p_async_adv.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_2p_async_adv.sv index 8436345d7a..dc23f95dbc 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_2p_async_adv.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_2p_async_adv.sv @@ -57,7 +57,8 @@ module prim_ram_2p_async_adv #( input [CfgW-1:0] cfg_i ); - logic [CfgW-1:0] unused_cfg = cfg_i; + logic [CfgW-1:0] unused_cfg; + assign unused_cfg = cfg_i; `ASSERT_INIT(CannotHaveEccAndParity_A, !(EnableParity && EnableECC)) @@ -165,9 +166,9 @@ module prim_ram_2p_async_adv #( // the wmask is constantly set to 1 in this case `ASSERT(OnlyWordWritePossibleWithEccPortA_A, a_req_i |-> - a_wmask_i == {TotalWidth{1'b1}}, clk_a_i, rst_a_ni) + a_wmask_i == {Width{1'b1}}, clk_a_i, rst_a_ni) `ASSERT(OnlyWordWritePossibleWithEccPortB_A, b_req_i |-> - b_wmask_i == {TotalWidth{1'b1}}, clk_b_i, rst_b_ni) + b_wmask_i == {Width{1'b1}}, clk_b_i, rst_b_ni) assign a_wmask_d = {TotalWidth{1'b1}}; assign b_wmask_d = {TotalWidth{1'b1}}; diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_22_16_dec.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_22_16_dec.sv new file mode 100644 index 0000000000..4a12a6da39 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_22_16_dec.sv @@ -0,0 +1,48 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED Decoder generated by secded_gen.py + +module prim_secded_22_16_dec ( + input [21:0] in, + output logic [15:0] d_o, + output logic [5:0] syndrome_o, + output logic [1:0] err_o +); + + logic single_error; + + // Syndrome calculation + assign syndrome_o[0] = in[16] ^ in[0] ^ in[1] ^ in[5] ^ in[8] ^ in[9] ^ in[10] ^ in[11] ^ in[15]; + assign syndrome_o[1] = in[17] ^ in[0] ^ in[4] ^ in[5] ^ in[6] ^ in[8] ^ in[12] ^ in[13] ^ in[14]; + assign syndrome_o[2] = in[18] ^ in[1] ^ in[3] ^ in[4] ^ in[6] ^ in[7] ^ in[8] ^ in[10] ^ in[13]; + assign syndrome_o[3] = in[19] ^ in[1] ^ in[2] ^ in[3] ^ in[11] ^ in[12] ^ in[13] ^ in[14] ^ + in[15]; + assign syndrome_o[4] = in[20] ^ in[2] ^ in[3] ^ in[5] ^ in[6] ^ in[7] ^ in[9] ^ in[11] ^ in[12]; + assign syndrome_o[5] = in[21] ^ in[0] ^ in[2] ^ in[4] ^ in[7] ^ in[9] ^ in[10] ^ in[14] ^ in[15]; + + // Corrected output calculation + assign d_o[0] = (syndrome_o == 6'h23) ^ in[0]; + assign d_o[1] = (syndrome_o == 6'hd) ^ in[1]; + assign d_o[2] = (syndrome_o == 6'h38) ^ in[2]; + assign d_o[3] = (syndrome_o == 6'h1c) ^ in[3]; + assign d_o[4] = (syndrome_o == 6'h26) ^ in[4]; + assign d_o[5] = (syndrome_o == 6'h13) ^ in[5]; + assign d_o[6] = (syndrome_o == 6'h16) ^ in[6]; + assign d_o[7] = (syndrome_o == 6'h34) ^ in[7]; + assign d_o[8] = (syndrome_o == 6'h7) ^ in[8]; + assign d_o[9] = (syndrome_o == 6'h31) ^ in[9]; + assign d_o[10] = (syndrome_o == 6'h25) ^ in[10]; + assign d_o[11] = (syndrome_o == 6'h19) ^ in[11]; + assign d_o[12] = (syndrome_o == 6'h1a) ^ in[12]; + assign d_o[13] = (syndrome_o == 6'he) ^ in[13]; + assign d_o[14] = (syndrome_o == 6'h2a) ^ in[14]; + assign d_o[15] = (syndrome_o == 6'h29) ^ in[15]; + + // err_o calc. bit0: single error, bit1: double error + assign single_error = ^syndrome_o; + assign err_o[0] = single_error; + assign err_o[1] = ~single_error & (|syndrome_o); +endmodule + diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_22_16_enc.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_22_16_enc.sv new file mode 100644 index 0000000000..5e3256b1f4 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_22_16_enc.sv @@ -0,0 +1,35 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED Encoder generated by secded_gen.py + +module prim_secded_22_16_enc ( + input [15:0] in, + output logic [21:0] out +); + + assign out[0] = in[0] ; + assign out[1] = in[1] ; + assign out[2] = in[2] ; + assign out[3] = in[3] ; + assign out[4] = in[4] ; + assign out[5] = in[5] ; + assign out[6] = in[6] ; + assign out[7] = in[7] ; + assign out[8] = in[8] ; + assign out[9] = in[9] ; + assign out[10] = in[10] ; + assign out[11] = in[11] ; + assign out[12] = in[12] ; + assign out[13] = in[13] ; + assign out[14] = in[14] ; + assign out[15] = in[15] ; + assign out[16] = in[0] ^ in[1] ^ in[5] ^ in[8] ^ in[9] ^ in[10] ^ in[11] ^ in[15]; + assign out[17] = in[0] ^ in[4] ^ in[5] ^ in[6] ^ in[8] ^ in[12] ^ in[13] ^ in[14]; + assign out[18] = in[1] ^ in[3] ^ in[4] ^ in[6] ^ in[7] ^ in[8] ^ in[10] ^ in[13]; + assign out[19] = in[1] ^ in[2] ^ in[3] ^ in[11] ^ in[12] ^ in[13] ^ in[14] ^ in[15]; + assign out[20] = in[2] ^ in[3] ^ in[5] ^ in[6] ^ in[7] ^ in[9] ^ in[11] ^ in[12]; + assign out[21] = in[0] ^ in[2] ^ in[4] ^ in[7] ^ in[9] ^ in[10] ^ in[14] ^ in[15]; +endmodule + diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_72_64_dec.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_72_64_dec.sv index 02b18224b1..eb4ad3ed16 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_72_64_dec.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_72_64_dec.sv @@ -16,36 +16,36 @@ module prim_secded_72_64_dec ( // Syndrome calculation assign syndrome_o[0] = in[64] ^ in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4] ^ in[5] ^ in[6] ^ in[7] ^ in[8] ^ in[9] ^ in[10] ^ in[11] ^ in[12] ^ in[13] ^ in[14] ^ in[15] - ^ in[16] ^ in[17] ^ in[18] ^ in[19] ^ in[20] ^ in[57] ^ in[58] ^ in[61] - ^ in[62] ^ in[63]; + ^ in[16] ^ in[17] ^ in[18] ^ in[19] ^ in[20] ^ in[57] ^ in[59] ^ in[60] + ^ in[61] ^ in[62]; assign syndrome_o[1] = in[65] ^ in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4] ^ in[5] ^ in[21] ^ in[22] ^ in[23] ^ in[24] ^ in[25] ^ in[26] ^ in[27] ^ in[28] ^ in[29] ^ in[30] - ^ in[31] ^ in[32] ^ in[33] ^ in[34] ^ in[35] ^ in[58] ^ in[59] ^ in[60] + ^ in[31] ^ in[32] ^ in[33] ^ in[34] ^ in[35] ^ in[56] ^ in[57] ^ in[60] ^ in[62] ^ in[63]; assign syndrome_o[2] = in[66] ^ in[0] ^ in[6] ^ in[7] ^ in[8] ^ in[9] ^ in[10] ^ in[21] ^ in[22] ^ in[23] ^ in[24] ^ in[25] ^ in[36] ^ in[37] ^ in[38] ^ in[39] ^ in[40] - ^ in[41] ^ in[42] ^ in[43] ^ in[44] ^ in[45] ^ in[56] ^ in[57] ^ in[59] - ^ in[60] ^ in[63]; + ^ in[41] ^ in[42] ^ in[43] ^ in[44] ^ in[45] ^ in[56] ^ in[57] ^ in[58] + ^ in[61] ^ in[62]; assign syndrome_o[3] = in[67] ^ in[1] ^ in[6] ^ in[11] ^ in[12] ^ in[13] ^ in[14] ^ in[21] ^ in[26] ^ in[27] ^ in[28] ^ in[29] ^ in[36] ^ in[37] ^ in[38] ^ in[39] - ^ in[46] ^ in[47] ^ in[48] ^ in[49] ^ in[50] ^ in[51] ^ in[56] ^ in[57] - ^ in[58] ^ in[61] ^ in[63]; + ^ in[46] ^ in[47] ^ in[48] ^ in[49] ^ in[50] ^ in[51] ^ in[56] ^ in[58] + ^ in[59] ^ in[62] ^ in[63]; assign syndrome_o[4] = in[68] ^ in[2] ^ in[7] ^ in[11] ^ in[15] ^ in[16] ^ in[17] ^ in[22] ^ in[26] ^ in[30] ^ in[31] ^ in[32] ^ in[36] ^ in[40] ^ in[41] ^ in[42] - ^ in[46] ^ in[47] ^ in[48] ^ in[52] ^ in[53] ^ in[54] ^ in[56] ^ in[58] - ^ in[59] ^ in[61] ^ in[62]; + ^ in[46] ^ in[47] ^ in[48] ^ in[52] ^ in[53] ^ in[54] ^ in[58] ^ in[59] + ^ in[60] ^ in[61] ^ in[63]; assign syndrome_o[5] = in[69] ^ in[3] ^ in[8] ^ in[12] ^ in[15] ^ in[18] ^ in[19] ^ in[23] ^ in[27] ^ in[30] ^ in[33] ^ in[34] ^ in[37] ^ in[40] ^ in[43] ^ in[44] ^ in[46] ^ in[49] ^ in[50] ^ in[52] ^ in[53] ^ in[55] ^ in[56] ^ in[57] - ^ in[59] ^ in[60] ^ in[61]; + ^ in[58] ^ in[60] ^ in[63]; assign syndrome_o[6] = in[70] ^ in[4] ^ in[9] ^ in[13] ^ in[16] ^ in[18] ^ in[20] ^ in[24] ^ in[28] ^ in[31] ^ in[33] ^ in[35] ^ in[38] ^ in[41] ^ in[43] ^ in[45] - ^ in[47] ^ in[49] ^ in[51] ^ in[52] ^ in[54] ^ in[55] ^ in[56] ^ in[59] - ^ in[60] ^ in[61] ^ in[62]; + ^ in[47] ^ in[49] ^ in[51] ^ in[52] ^ in[54] ^ in[55] ^ in[56] ^ in[57] + ^ in[59] ^ in[61] ^ in[63]; assign syndrome_o[7] = in[71] ^ in[5] ^ in[10] ^ in[14] ^ in[17] ^ in[19] ^ in[20] ^ in[25] ^ in[29] ^ in[32] ^ in[34] ^ in[35] ^ in[39] ^ in[42] ^ in[44] ^ in[45] - ^ in[48] ^ in[50] ^ in[51] ^ in[53] ^ in[54] ^ in[55] ^ in[57] ^ in[58] - ^ in[60] ^ in[62] ^ in[63]; + ^ in[48] ^ in[50] ^ in[51] ^ in[53] ^ in[54] ^ in[55] ^ in[58] ^ in[59] + ^ in[60] ^ in[61] ^ in[62]; // Corrected output calculation assign d_o[0] = (syndrome_o == 8'h7) ^ in[0]; @@ -104,14 +104,14 @@ module prim_secded_72_64_dec ( assign d_o[53] = (syndrome_o == 8'hb0) ^ in[53]; assign d_o[54] = (syndrome_o == 8'hd0) ^ in[54]; assign d_o[55] = (syndrome_o == 8'he0) ^ in[55]; - assign d_o[56] = (syndrome_o == 8'h7c) ^ in[56]; - assign d_o[57] = (syndrome_o == 8'had) ^ in[57]; - assign d_o[58] = (syndrome_o == 8'h9b) ^ in[58]; - assign d_o[59] = (syndrome_o == 8'h76) ^ in[59]; - assign d_o[60] = (syndrome_o == 8'he6) ^ in[60]; - assign d_o[61] = (syndrome_o == 8'h79) ^ in[61]; - assign d_o[62] = (syndrome_o == 8'hd3) ^ in[62]; - assign d_o[63] = (syndrome_o == 8'h8f) ^ in[63]; + assign d_o[56] = (syndrome_o == 8'h6e) ^ in[56]; + assign d_o[57] = (syndrome_o == 8'h67) ^ in[57]; + assign d_o[58] = (syndrome_o == 8'hbc) ^ in[58]; + assign d_o[59] = (syndrome_o == 8'hd9) ^ in[59]; + assign d_o[60] = (syndrome_o == 8'hb3) ^ in[60]; + assign d_o[61] = (syndrome_o == 8'hd5) ^ in[61]; + assign d_o[62] = (syndrome_o == 8'h8f) ^ in[62]; + assign d_o[63] = (syndrome_o == 8'h7a) ^ in[63]; // err_o calc. bit0: single error, bit1: double error assign single_error = ^syndrome_o; diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_72_64_enc.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_72_64_enc.sv index 207c45ca8e..cf89f379db 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_72_64_enc.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_72_64_enc.sv @@ -75,27 +75,27 @@ module prim_secded_72_64_enc ( assign out[63] = in[63] ; assign out[64] = in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4] ^ in[5] ^ in[6] ^ in[7] ^ in[8] ^ in[9] ^ in[10] ^ in[11] ^ in[12] ^ in[13] ^ in[14] ^ in[15] ^ in[16] ^ in[17] ^ in[18] - ^ in[19] ^ in[20] ^ in[57] ^ in[58] ^ in[61] ^ in[62] ^ in[63]; + ^ in[19] ^ in[20] ^ in[57] ^ in[59] ^ in[60] ^ in[61] ^ in[62]; assign out[65] = in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4] ^ in[5] ^ in[21] ^ in[22] ^ in[23] ^ in[24] ^ in[25] ^ in[26] ^ in[27] ^ in[28] ^ in[29] ^ in[30] ^ in[31] ^ in[32] ^ in[33] - ^ in[34] ^ in[35] ^ in[58] ^ in[59] ^ in[60] ^ in[62] ^ in[63]; + ^ in[34] ^ in[35] ^ in[56] ^ in[57] ^ in[60] ^ in[62] ^ in[63]; assign out[66] = in[0] ^ in[6] ^ in[7] ^ in[8] ^ in[9] ^ in[10] ^ in[21] ^ in[22] ^ in[23] ^ in[24] ^ in[25] ^ in[36] ^ in[37] ^ in[38] ^ in[39] ^ in[40] ^ in[41] ^ in[42] - ^ in[43] ^ in[44] ^ in[45] ^ in[56] ^ in[57] ^ in[59] ^ in[60] ^ in[63]; + ^ in[43] ^ in[44] ^ in[45] ^ in[56] ^ in[57] ^ in[58] ^ in[61] ^ in[62]; assign out[67] = in[1] ^ in[6] ^ in[11] ^ in[12] ^ in[13] ^ in[14] ^ in[21] ^ in[26] ^ in[27] ^ in[28] ^ in[29] ^ in[36] ^ in[37] ^ in[38] ^ in[39] ^ in[46] ^ in[47] ^ in[48] - ^ in[49] ^ in[50] ^ in[51] ^ in[56] ^ in[57] ^ in[58] ^ in[61] ^ in[63]; + ^ in[49] ^ in[50] ^ in[51] ^ in[56] ^ in[58] ^ in[59] ^ in[62] ^ in[63]; assign out[68] = in[2] ^ in[7] ^ in[11] ^ in[15] ^ in[16] ^ in[17] ^ in[22] ^ in[26] ^ in[30] ^ in[31] ^ in[32] ^ in[36] ^ in[40] ^ in[41] ^ in[42] ^ in[46] ^ in[47] ^ in[48] - ^ in[52] ^ in[53] ^ in[54] ^ in[56] ^ in[58] ^ in[59] ^ in[61] ^ in[62]; + ^ in[52] ^ in[53] ^ in[54] ^ in[58] ^ in[59] ^ in[60] ^ in[61] ^ in[63]; assign out[69] = in[3] ^ in[8] ^ in[12] ^ in[15] ^ in[18] ^ in[19] ^ in[23] ^ in[27] ^ in[30] ^ in[33] ^ in[34] ^ in[37] ^ in[40] ^ in[43] ^ in[44] ^ in[46] ^ in[49] ^ in[50] - ^ in[52] ^ in[53] ^ in[55] ^ in[56] ^ in[57] ^ in[59] ^ in[60] ^ in[61]; + ^ in[52] ^ in[53] ^ in[55] ^ in[56] ^ in[57] ^ in[58] ^ in[60] ^ in[63]; assign out[70] = in[4] ^ in[9] ^ in[13] ^ in[16] ^ in[18] ^ in[20] ^ in[24] ^ in[28] ^ in[31] ^ in[33] ^ in[35] ^ in[38] ^ in[41] ^ in[43] ^ in[45] ^ in[47] ^ in[49] ^ in[51] - ^ in[52] ^ in[54] ^ in[55] ^ in[56] ^ in[59] ^ in[60] ^ in[61] ^ in[62]; + ^ in[52] ^ in[54] ^ in[55] ^ in[56] ^ in[57] ^ in[59] ^ in[61] ^ in[63]; assign out[71] = in[5] ^ in[10] ^ in[14] ^ in[17] ^ in[19] ^ in[20] ^ in[25] ^ in[29] ^ in[32] ^ in[34] ^ in[35] ^ in[39] ^ in[42] ^ in[44] ^ in[45] ^ in[48] ^ in[50] ^ in[51] - ^ in[53] ^ in[54] ^ in[55] ^ in[57] ^ in[58] ^ in[60] ^ in[62] ^ in[63]; + ^ in[53] ^ in[54] ^ in[55] ^ in[58] ^ in[59] ^ in[60] ^ in[61] ^ in[62]; endmodule diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_slicer.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_slicer.sv new file mode 100644 index 0000000000..3c61669ef4 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_slicer.sv @@ -0,0 +1,32 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Slicer chops the incoming bitstring into OutW granularity. +// It supports fractional InW/OutW which fills 0 at the end of message. + +`include "prim_assert.sv" + +module prim_slicer #( + parameter int InW = 64, + parameter int OutW = 8, + + parameter int IndexW = 4 +) ( + input [IndexW-1:0] sel_i, + input [InW-1:0] data_i, + output logic [OutW-1:0] data_o +); + + localparam int UnrollW = OutW*(2**IndexW); + + logic [UnrollW-1:0] unrolled_data; + + assign unrolled_data = UnrollW'(data_i); + + assign data_o = unrolled_data[sel_i*OutW+:OutW]; + + `ASSERT_INIT(ValidWidth_A, InW <= OutW*(2**IndexW)) + +endmodule + diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_subst_perm.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_subst_perm.sv index a882dff030..5f96f3a03a 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_subst_perm.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_subst_perm.sv @@ -42,7 +42,7 @@ module prim_subst_perm #( end // Flip vector for (int k = 0; k < DataWidth; k++) begin - data_state_flipped[DataWidth - 1 - k] = data_state_sbox[k]; + data_state_sbox[DataWidth - 1 - k] = data_state_flipped[k]; end // Inverse SBox layer for (int k = 0; k < DataWidth/4; k++) begin @@ -66,7 +66,7 @@ module prim_subst_perm #( data_state_flipped[DataWidth - 1 - k] = data_state_sbox[k]; end // Regroup bits such that all even indices are stacked up first, followed by all odd - // indices, and then flip the vector. Note that if the Width is odd, this is still ok, since + // indices. Note that if the Width is odd, this is still ok, since // the uppermost bit just stays in place in that case. for (int k = 0; k < DataWidth/2; k++) begin data_state_sbox[k] = data_state_flipped[k * 2]; diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_util_memload.svh b/vendor/lowrisc_ip/ip/prim/rtl/prim_util_memload.svh index c5c808c91e..2141c7c09d 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_util_memload.svh +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_util_memload.svh @@ -16,21 +16,20 @@ * the memory if not empty. */ -`ifdef VERILATOR +`ifndef SYNTHESIS // Task for loading 'mem' with SystemVerilog system task $readmemh() - export "DPI-C" task simutil_verilator_memload; + export "DPI-C" task simutil_memload; - task simutil_verilator_memload; + task simutil_memload; input string file; $readmemh(file, mem); endtask // Function for setting a specific element in |mem| // Returns 1 (true) for success, 0 (false) for errors. - export "DPI-C" function simutil_verilator_set_mem; + export "DPI-C" function simutil_set_mem; - function int simutil_verilator_set_mem(input int index, - input bit [255:0] val); + function int simutil_set_mem(input int index, input bit [255:0] val); // Function will only work for memories <= 256 bits if (Width > 256) begin @@ -46,10 +45,9 @@ endfunction // Function for getting a specific element in |mem| - export "DPI-C" function simutil_verilator_get_mem; + export "DPI-C" function simutil_get_mem; - function int simutil_verilator_get_mem(input int index, - output bit [255:0] val); + function int simutil_get_mem(input int index, output bit [255:0] val); // Function will only work for memories <= 256 bits if (Width > 256) begin diff --git a/vendor/lowrisc_ip/ip/prim/util/gen-lfsr-seed.py b/vendor/lowrisc_ip/ip/prim/util/gen-lfsr-seed.py new file mode 100755 index 0000000000..f287c8ffe7 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/util/gen-lfsr-seed.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python3 +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +r"""This script generates random seeds and state permutations for LFSRs +and outputs them them as a packed SV logic vectors suitable for use with +prim_lfsr.sv. +""" +import argparse +import random +import textwrap +import logging as log +from math import ceil, log2 + + +SV_INSTRUCTIONS = """ +------------------------------------------------ +| COPY PASTE THE CODE TEMPLATE BELOW INTO YOUR | +| RTL CODE, INLUDING THE COMMENT IN ORDER TO | +| EASE AUDITABILITY AND REPRODUCIBILITY. | +------------------------------------------------ +""" + + +def _as_snake_case_prefix(name): + """ Convert PascalCase name into snake_case name""" + outname = "" + for c in name: + if c.isupper() and len(outname) > 0: + outname += '_' + outname += c.lower() + return outname + ('_' if name else '') + + +def _get_random_data_hex_literal(width): + """ Fetch 'width' random bits and return them as hex literal""" + width = int(width) + literal_str = hex(random.getrandbits(width)) + literal_str = str(width) + "'h" + literal_str[2:] + return literal_str + + +def _get_random_perm_hex_literal(numel): + """ Compute a random permutation of 'numel' elements and + return as packed hex literal""" + num_elements = int(numel) + width = int(ceil(log2(num_elements))) + idx = [x for x in range(num_elements)] + random.shuffle(idx) + literal_str = "" + for k in idx: + literal_str += format(k, '0' + str(width) + 'b') + # convert to hex for space efficiency + literal_str = hex(int(literal_str, 2)) + literal_str = str(width * numel) + "'h" + literal_str[2:] + return literal_str + + +def _wrapped_docstring(): + '''Return a text-wrapped version of the module docstring''' + paras = [] + para = [] + for line in __doc__.strip().split('\n'): + line = line.strip() + if not line: + if para: + paras.append('\n'.join(para)) + para = [] + else: + para.append(line) + if para: + paras.append('\n'.join(para)) + + return '\n\n'.join(textwrap.fill(p) for p in paras) + + +def main(): + log.basicConfig(level=log.INFO, + format="%(asctime)s - %(message)s", + datefmt="%Y-%m-%d %H:%M") + + parser = argparse.ArgumentParser( + prog="gen-lfsre-perm", + description=_wrapped_docstring(), + formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument('-w', + '--width', + type=int, + default=32, + metavar='<#bitwidth>', + help='LFSR width.') + parser.add_argument('-s', + '--seed', + type=int, + metavar='', + help='Custom seed for RNG.') + parser.add_argument('-p', + '--prefix', + type=str, + metavar='name', + default="", + help='Optional prefix to add to ' + 'types and parameters. ' + 'Make sure this is PascalCase.') + + args = parser.parse_args() + + if args.width <= 0: + log.error("LFSR width must be nonzero") + exit(1) + + if args.seed is None: + random.seed() + args.seed = random.getrandbits(32) + + random.seed(args.seed) + + print(SV_INSTRUCTIONS) + + type_prefix = _as_snake_case_prefix(args.prefix) + + outstr = ''' +// These LFSR parameters have been generated with +// $ hw/ip/prim/util/gen-lfsr-seed.py --width {} --seed {} --prefix "{}" +parameter int {}LfsrWidth = {}; +typedef logic [{}LfsrWidth-1:0] {}lfsr_seed_t; +typedef logic [{}LfsrWidth-1:0][$clog2({}LfsrWidth)-1:0] {}lfsr_perm_t; +parameter {}lfsr_seed_t RndCnst{}LfsrSeedDefault = {}; +parameter {}lfsr_perm_t RndCnst{}LfsrPermDefault = + {}; +'''.format(args.width, args.seed, args.prefix, + args.prefix, args.width, + args.prefix, type_prefix, + args.prefix, args.prefix, type_prefix, + type_prefix, args.prefix, _get_random_data_hex_literal(args.width), + type_prefix, args.prefix, _get_random_perm_hex_literal(args.width)) + + print(outstr) + + +if __name__ == "__main__": + main() diff --git a/vendor/lowrisc_ip/ip/prim/util/primgen.py b/vendor/lowrisc_ip/ip/prim/util/primgen.py index f601d503e8..6a9f1d67a7 100755 --- a/vendor/lowrisc_ip/ip/prim/util/primgen.py +++ b/vendor/lowrisc_ip/ip/prim/util/primgen.py @@ -330,6 +330,7 @@ def _generate_abstract_impl(gapi): module_header_imports=generic_hdr['package_import_declaration'], module_header_params=generic_hdr['parameter_port_list'], module_header_ports=generic_hdr['ports'], + num_techlibs= len(techlibs), # Creating the code to instantiate the primitives in the Mako templating # language is tricky to do; do it in Python instead. instances=_create_instances(prim_name, techlibs, diff --git a/vendor/lowrisc_ip/ip/prim/util/primgen/abstract_prim.sv.tpl b/vendor/lowrisc_ip/ip/prim/util/primgen/abstract_prim.sv.tpl index 6a2bbd979d..4a8f92cd27 100644 --- a/vendor/lowrisc_ip/ip/prim/util/primgen/abstract_prim.sv.tpl +++ b/vendor/lowrisc_ip/ip/prim/util/primgen/abstract_prim.sv.tpl @@ -4,10 +4,17 @@ // This file is auto-generated. +% if num_techlibs > 1: `ifndef PRIM_DEFAULT_IMPL `define PRIM_DEFAULT_IMPL prim_pkg::ImplGeneric `endif +% endif +// This is to prevent AscentLint warnings in the generated +// abstract prim wrapper. These warnings occur due to the .* +// use. TODO: we may want to move these inline waivers +// into a separate, generated waiver file for consistency. +//ri lint_check_off OUTPUT_NOT_DRIVEN INPUT_NOT_READ module prim_${prim_name} ${module_header_imports} #( @@ -15,8 +22,11 @@ ${module_header_params} ) ( ${module_header_ports} ); +% if num_techlibs > 1: parameter prim_pkg::impl_e Impl = `PRIM_DEFAULT_IMPL; +% endif ${instances} endmodule +//ri lint_check_on OUTPUT_NOT_DRIVEN INPUT_NOT_READ diff --git a/vendor/lowrisc_ip/ip/prim/util/sparse-fsm-encode.py b/vendor/lowrisc_ip/ip/prim/util/sparse-fsm-encode.py new file mode 100755 index 0000000000..5ac574e29e --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/util/sparse-fsm-encode.py @@ -0,0 +1,333 @@ +#!/usr/bin/env python3 +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +r"""This script generates sparse FSM encodings that fulfill a minimum +Hamming distance requirement. It uses a heuristic that incrementally +draws random state encodings until a solution has been found. + +Depending on the parameterization, the script may not find a solution right +away. In such cases, the script should be rerun after tweaking the d/m/n +parameters. E.g. in order to increase the chances for success, the state +space can be made more sparse by increasing n, or the Hamming distance +threshold d can be lowered. + +Note however that the Hamming distance d should be set to 3 at minimum. +It is recommended to set this value to 4-5 for security critical FSMs. + +The custom seed s can be used to make subsequent runs of the script +deterministic. If not specified, the script randomly picks a seed. + +""" +import argparse +import logging +import math +import random +import textwrap +import sys + +MAX_DRAWS = 10000 +MAX_RESTARTS = 10000 + + +SV_INSTRUCTIONS = """ +------------------------------------------------------ +| COPY PASTE THE CODE TEMPLATE BELOW INTO YOUR RTL | +| IMPLEMENTATION, INLUDING THE COMMENT AND PRIM_FLOP | +| IN ORDER TO EASE AUDITABILITY AND REPRODUCIBILITY. | +------------------------------------------------------ +""" + +C_INSTRUCTIONS = """ +------------------------------------------------ +| COPY PASTE THE CODE TEMPLATE BELOW INTO YOUR | +| C HEADER, INLUDING THE COMMENT IN ORDER TO | +| EASE AUDITABILITY AND REPRODUCIBILITY. | +------------------------------------------------ +""" + +RUST_INSTRUCTIONS = """ +------------------------------------------------ +| COPY PASTE THE CODE TEMPLATE BELOW INTO YOUR | +| RUST FILE, INLUDING THE COMMENT IN ORDER TO | +| EASE AUDITABILITY AND REPRODUCIBILITY. | +------------------------------------------------ +""" + + +def _wrapped_docstring(): + '''Return a text-wrapped version of the module docstring''' + paras = [] + para = [] + for line in __doc__.strip().split('\n'): + line = line.strip() + if not line: + if para: + paras.append('\n'.join(para)) + para = [] + else: + para.append(line) + if para: + paras.append('\n'.join(para)) + + return '\n\n'.join(textwrap.fill(p) for p in paras) + + +def _hist_to_bars(hist, m): + '''Convert histogramm list into ASCII bar plot''' + bars = [] + for i, j in enumerate(hist): + bar_prefix = "{:2}: ".format(i) + spaces = len(str(m)) - len(bar_prefix) + hist_bar = bar_prefix + (" " * spaces) + for k in range(j * 20 // max(hist)): + hist_bar += "|" + hist_bar += " ({:.2f}%)".format(100.0 * j / sum(hist)) if j else "--" + bars += [hist_bar] + return bars + + +def main(): + logging.basicConfig(level=logging.INFO, + format="%(asctime)s - %(message)s", + datefmt="%Y-%m-%d %H:%M") + + parser = argparse.ArgumentParser( + prog="sparse-fsm-encode", + description=_wrapped_docstring(), + formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument('-d', + type=int, + default=5, + metavar='', + help='Minimum Hamming distance between encoded states.') + parser.add_argument('-m', + type=int, + default=7, + metavar='<#states>', + help='Number of states to encode.') + parser.add_argument('-n', + type=int, + default=10, + metavar='<#nbits>', + help='Encoding length [bit].') + parser.add_argument('-s', + type=int, + metavar='', + help='Custom seed for RNG.') + parser.add_argument('--language', + choices=['sv', 'c', 'rust'], + default='sv', + help='Choose the language of the generated enum.') + + args = parser.parse_args() + + if args.language in ['c', 'rust']: + if args.n not in [8, 16, 32]: + logging.error("When using C or Rust, widths must be a power-of-two " + "at least a byte (8 bits) wide. You chose %d." % (args.n,)) + sys.exit(1) + + if args.m > 2**args.n: + logging.error( + 'Statespace 2^%d not large enough to accommodate %d states.' % + (args.n, args.m)) + sys.exit(1) + + if args.d >= args.n: + logging.error( + 'State is only %d bits wide, which is not enough to fulfill a ' + 'minimum Hamming distance constraint of %d. ' % + (args.n, args.d)) + sys.exit(1) + + if args.d <= 0: + logging.error( + 'Hamming distance must be > 0.') + sys.exit(1) + + if args.d < 3: + logging.warning( + 'A value of 4-5 is recommended for the minimum Hamming distance ' + 'constraint. At a minimum, this should be set to 3.') + + # If no seed has been provided, we choose a seed and print it + # into the generated output later on such that this run can be + # reproduced. + if args.s is None: + random.seed() + args.s = random.getrandbits(32) + + random.seed(args.s) + + # This is a heuristic that opportunistically draws random + # state encodings and check whether they fulfill the minimum + # Hamming distance constraint. + # Other solutions that use a brute-force approach would be + # possible as well (see e.g. https://math.stackexchange.com/ + # questions/891528/generating-a-binary-code-with-maximized-hamming-distance). + # However, due to the sparse nature of the state space, this + # probabilistic heuristic works pretty well for most practical + # cases, and it scales favorably to large N. + num_draws = 0 + num_restarts = 0 + encodings = [random.getrandbits(args.n)] + while len(encodings) < args.m: + # if we iterate for too long, start over. + if num_draws >= MAX_DRAWS: + num_draws = 0 + num_restarts += 1 + encodings = [random.getrandbits(args.n)] + # if we restarted for too many times, abort. + if num_restarts >= MAX_RESTARTS: + logging.error( + 'Did not find a solution after restarting {} times. This is ' + 'an indicator that not many (or even no) solutions exist for ' + 'the current parameterization. Rerun the script and/or adjust ' + 'the d/m/n parameters. E.g. make the state space more sparse by ' + 'increasing n, or lower the minimum Hamming distance threshold d.' + .format(num_restarts)) + sys.exit(1) + num_draws += 1 + # draw a candidate and check whether it fulfills the minimum + # distance requirement with respect to other encodings. + c = random.getrandbits(args.n) + # disallow all-zero and all-one states + pop_cnt = bin(c).count('1') + if pop_cnt < args.n and pop_cnt > 0: + for k in encodings: + # disallow candidates that are the complement of other states + if c == ~k: + break + # disallow candidates that are too close to other states + if bin(c ^ k).count('1') < args.d: + break + else: + encodings.append(c) + + # build Hamming distance histogram + minimum = args.n + maximum = 0 + hist = [0] * (args.n + 1) + for i, j in enumerate(encodings): + if i < len(encodings) - 1: + for k in encodings[i + 1:]: + dist = bin(j ^ k).count('1') + hist[dist] += 1 + minimum = min(dist, minimum) + maximum = max(dist, maximum) + + bars = _hist_to_bars(hist, args.m) + + if args.language == "sv": + print(SV_INSTRUCTIONS) + print( + "// Encoding generated with:\n" + "// $ ./sparse-fsm-encode.py -d {} -m {} -n {} \\\n" + "// -s {} --language=sv\n" + "//\n" + "// Hamming distance histogram:\n" + "//".format(args.d, args.m, args.n, args.s)) + for bar in _hist_to_bars(hist, args.m): + print('// ' + bar) + print("//\n" + "// Minimum Hamming distance: {}\n" + "// Maximum Hamming distance: {}\n" + "//\n" + "localparam int StateWidth = {};\n" + "typedef enum logic [StateWidth-1:0] {{".format(minimum, maximum, args.n)) + fmt_str = " State{0:} {1:}= {2:}'b{3:0" + str(args.n) + "b}" + state_str = "" + for j, k in enumerate(encodings): + pad = "" + for i in range(len(str(args.m)) - len(str(j))): + pad += " " + comma = "," if j < len(encodings) - 1 else "" + print(fmt_str.format(j, pad, args.n, k) + comma) + state_str += " State{}: ;\n".format(j) + + # print FSM template + print('''}} state_e; + +state_e state_d, state_q; + +always_comb begin : p_fsm + // Default assignments + state_d = state_q; + + unique case (state_q) +{} default: ; // Consider triggering an error or alert in this case. + endcase +end + +// This primitive is used to place a size-only constraint on the +// flops in order to prevent FSM state encoding optimizations. +logic [StateWidth-1:0] state_raw_q; +assign state_q = state_e'(state_raw_q); +prim_flop #( + .Width(StateWidth), + .ResetValue(StateWidth'(State0)) +) u_state_regs ( + .clk_i, + .rst_ni, + .d_i ( state_d ), + .q_o ( state_raw_q ) +); +'''.format(state_str)) + + elif args.language == "c": + print(C_INSTRUCTIONS) + print("/*\n" + " * Encoding generated with\n" + " * $ ./sparse-fsm-encode.py -d {} -m {} -n {} \\\n" + " * -s {} --language=c\n" + " *\n" + " * Hamming distance histogram:\n" + " *".format(args.d, args.m, args.n, args.s)) + for hist_bar in bars: + print(" * " + hist_bar) + print(" *\n" + " * Minimum Hamming distance: {}\n" + " * Maximum Hamming distance: {}\n" + " */\n" + "typedef enum my_state {{".format(minimum, maximum)) + fmt_str = " kMyState{0:} {1:}= 0x{3:0" + str(math.ceil(args.n / 4)) + "x}" + for j, k in enumerate(encodings): + pad = "" + for i in range(len(str(args.m)) - len(str(j))): + pad += " " + print(fmt_str.format(j, pad, args.n, k) + ",") + + # print FSM template + print("} my_state_t;") + elif args.language == 'rust': + print(RUST_INSTRUCTIONS) + print("///```text\n" + "/// Encoding generated with\n" + "/// $ ./sparse-fsm-encode.py -d {} -m {} -n {} \\\n" + "/// -s {} --language=rust\n" + "///\n" + "/// Hamming distance histogram:\n" + "///".format(args.d, args.m, args.n, args.s)) + for hist_bar in bars: + print("/// " + hist_bar) + print("///\n" + "/// Minimum Hamming distance: {}\n" + "/// Maximum Hamming distance: {}\n" + "///```\n" + "#[derive(Clone,Copy,Eq,PartialEq,Ord,ParitalOrd,Hash,Debug)]\n" + "#[repr(transparent)]\n" + "struct MyState(u{});\n" + "\n" + "impl MyState {{".format(minimum, maximum, args.n)) + fmt_str = " const MY_STATE{0:}: MyState {1:}= MyState(0x{3:0" + str(math.ceil(args.n / 4)) + "x})" + for j, k in enumerate(encodings): + pad = "" + for i in range(len(str(args.m)) - len(str(j))): + pad += " " + print(fmt_str.format(j, pad, args.n, k) + ";") + print("}") + + +if __name__ == "__main__": + main() diff --git a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_mux2.waiver b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_mux2.waiver index 0815756a74..d69c7f74b5 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_mux2.waiver +++ b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_mux2.waiver @@ -3,3 +3,6 @@ # SPDX-License-Identifier: Apache-2.0 # # waiver file for prim_clock_mux2 + +waive -rules PARAM_NOT_USED -location {prim_generic_clock_mux2.sv} -regexp {.*Parameter 'NoFpgaBufG' not used in.*} \ + -comment "This parameter serves no function in the generic model" diff --git a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_otp.waiver b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_otp.waiver index 08eeadef2d..341732af84 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_otp.waiver +++ b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_otp.waiver @@ -3,3 +3,6 @@ # SPDX-License-Identifier: Apache-2.0 # +waive -rules {CONST_FF} -location {prim_generic_otp.sv} -msg {Flip-flop 'err_q[3]' is driven by constant zero} \ + -comment "Due to the error encoding, this bit is always constant in this module." + diff --git a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_ram_1p.waiver b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_ram_1p.waiver index d800ceecdc..e68718451b 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_ram_1p.waiver +++ b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_ram_1p.waiver @@ -4,8 +4,6 @@ # # waiver file for prim_generic_ram_[1,2]p -waive -rules MULTI_PROC_ASSIGN -location {prim_generic_ram_2p.sv} -regexp {Assignment to 'storage' from more than one block} \ - -comment "That is the nature of a dual-port memory: both write ports can access the same storage simultaneously" waive -rules ALWAYS_SPEC -location {prim_generic_ram_*p.sv} -regexp {Edge triggered block may be more accurately modeled as always_ff} \ -comment "Vivado requires here an always instead of always_ff" waive -rules HIER_NET_NOT_READ -regexp {Connected net '(addr|wdata)_i' at prim_generic_ram_1p.sv.* is not read from in module 'prim_generic_ram_1p'} \ diff --git a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_ram_2p.vlt b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_ram_2p.vlt index 544a7b79b1..2654984e20 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_ram_2p.vlt +++ b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_ram_2p.vlt @@ -2,3 +2,8 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 // + +`verilator_config + +// That is the nature of a dual-port memory: both write ports can access the same storage simultaneously. +lint_off -rule MULTIDRIVEN -file "*/rtl/prim_generic_ram_2p.sv" -match "Signal has multiple driving blocks with different clocking: '*.mem'*" diff --git a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_ram_2p.waiver b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_ram_2p.waiver index d800ceecdc..0acf9192b6 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_ram_2p.waiver +++ b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_ram_2p.waiver @@ -4,7 +4,7 @@ # # waiver file for prim_generic_ram_[1,2]p -waive -rules MULTI_PROC_ASSIGN -location {prim_generic_ram_2p.sv} -regexp {Assignment to 'storage' from more than one block} \ +waive -rules MULTI_PROC_ASSIGN -location {prim_generic_ram_2p.sv} -regexp {Assignment to 'mem' from more than one block} \ -comment "That is the nature of a dual-port memory: both write ports can access the same storage simultaneously" waive -rules ALWAYS_SPEC -location {prim_generic_ram_*p.sv} -regexp {Edge triggered block may be more accurately modeled as always_ff} \ -comment "Vivado requires here an always instead of always_ff" diff --git a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flash.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flash.core index 5d2d0b9d20..b37299f88d 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flash.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flash.core @@ -11,6 +11,7 @@ filesets: - lowrisc:prim:ram_1p - lowrisc:ip:flash_ctrl_pkg files: + - rtl/prim_generic_flash_bank.sv - rtl/prim_generic_flash.sv file_type: systemVerilogSource diff --git a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_otp.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_otp.core index 3d50166023..e46a16bb68 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_otp.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_otp.core @@ -9,6 +9,8 @@ filesets: files_rtl: depend: - lowrisc:prim:all + - lowrisc:prim:util + - lowrisc:prim:ram_1p_adv files: - rtl/prim_generic_otp.sv file_type: systemVerilogSource diff --git a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_usb_diff_rx.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_usb_diff_rx.core new file mode 100644 index 0000000000..36c8f91cb4 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_usb_diff_rx.core @@ -0,0 +1,42 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +name: "lowrisc:prim_generic:usb_diff_rx" +description: "Generic differential USB receiver for emulation purposes" +filesets: + files_rtl: + files: + - rtl/prim_generic_usb_diff_rx.sv + file_type: systemVerilogSource + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + #- lint/prim_generic_usb_diff_rx.vlt + file_type: vlt + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + #- lint/prim_generic_usb_diff_rx.waiver + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + - lowrisc:lint:comportable + +targets: + default: + filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) + - files_rtl diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_gating.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_gating.sv index 376c38efcf..1cc05e68ba 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_gating.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_gating.sv @@ -4,7 +4,9 @@ // // Common Library: Clock Gating cell -module prim_generic_clock_gating ( +module prim_generic_clock_gating #( + parameter bit NoFpgaGate = 1'b0 // this parameter has no function in generic +) ( input clk_i, input en_i, input test_en_i, diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_mux2.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_mux2.sv index 668c832bb4..4c2c97c98b 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_mux2.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_mux2.sv @@ -4,7 +4,9 @@ `include "prim_assert.sv" -module prim_generic_clock_mux2 ( +module prim_generic_clock_mux2 #( + parameter bit NoFpgaBufG = 1'b0 // this parameter serves no function in the generic model +) ( input clk0_i, input clk1_i, input sel_i, diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash.sv index 29fbabc32d..b76ab8b8fe 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash.sv @@ -2,330 +2,86 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 // -// prim flash module - Emulated using memory +// Overall flash wrapper // module prim_generic_flash #( - parameter int InfosPerBank = 1, // info pages per bank - parameter int PagesPerBank = 256, // data pages per bank - parameter int WordsPerPage = 256, // words per page - parameter int DataWidth = 32, // bits per word - parameter bit SkipInit = 1, // this is an option to reset flash to all F's at reset - - // Derived parameters - localparam int PageW = $clog2(PagesPerBank), - localparam int WordW = $clog2(WordsPerPage), - localparam int AddrW = PageW + WordW + parameter int NumBanks = 2, // number of banks + parameter int InfosPerBank = 1, // info pages per bank + parameter int PagesPerBank = 256, // data pages per bank + parameter int WordsPerPage = 256, // words per page + parameter int DataWidth = 32, // bits per word + parameter int MetaDataWidth = 12, // metadata such as ECC + parameter int TestModeWidth = 2 ) ( - input clk_i, - input rst_ni, - input rd_i, - input prog_i, - input pg_erase_i, - input bk_erase_i, - input [AddrW-1:0] addr_i, - input flash_ctrl_pkg::flash_part_e part_i, - input [DataWidth-1:0] prog_data_i, - output logic ack_o, - output logic [DataWidth-1:0] rd_data_o, - output logic init_busy_o, - input tck_i, - input tdi_i, - input tms_i, - output logic tdo_o, - input scanmode_i, - input scan_reset_ni, - input flash_power_ready_hi, - input flash_power_down_hi, - inout [3:0] flash_test_mode_ai, - inout flash_test_voltage_hi + input clk_i, + input rst_ni, + input flash_phy_pkg::flash_phy_prim_flash_req_t [NumBanks-1:0] flash_req_i, + output flash_phy_pkg::flash_phy_prim_flash_rsp_t [NumBanks-1:0] flash_rsp_o, + output logic [flash_phy_pkg::ProgTypes-1:0] prog_type_avail_o, + output init_busy_o, + input tck_i, + input tdi_i, + input tms_i, + output logic tdo_o, + input scanmode_i, + input scan_rst_ni, + input flash_power_ready_h_i, + input flash_power_down_h_i, + input [TestModeWidth-1:0] flash_test_mode_a_i, + input flash_test_voltage_h_i ); - // Emulated flash macro values - localparam int ReadCycles = 1; - localparam int ProgCycles = 50; - localparam int PgEraseCycles = 200; - localparam int BkEraseCycles = 2000; - - // Locally derived values - localparam int WordsPerBank = PagesPerBank * WordsPerPage; - localparam int WordsPerInfoBank = InfosPerBank * WordsPerPage; - localparam int InfoAddrW = $clog2(WordsPerInfoBank); - - typedef enum logic [2:0] { - StReset = 'h0, - StInit = 'h1, - StIdle = 'h2, - StRead = 'h3, - StProg = 'h4, - StErase = 'h5 - } state_e; - - state_e st_q, st_d; - - logic [31:0] time_cnt; - logic [31:0] index_cnt; - logic time_cnt_inc ,time_cnt_clr, time_cnt_set1; - logic index_cnt_inc, index_cnt_clr; - logic [31:0] index_limit_q, index_limit_d; - logic [31:0] time_limit_q, time_limit_d; - logic prog_pend_q, prog_pend_d; - logic mem_req; - logic mem_wr; - logic [AddrW-1:0] mem_addr; - flash_ctrl_pkg::flash_part_e mem_part; - logic [DataWidth-1:0] held_rdata; - logic [DataWidth-1:0] held_wdata; - logic [DataWidth-1:0] mem_wdata; - logic hold_cmd; - logic [AddrW-1:0] held_addr; - flash_ctrl_pkg::flash_part_e held_part; - - // insert a fifo here to break the large fanout from inputs to memories on reads - logic rd_q; - logic [AddrW-1:0] addr_q; - flash_ctrl_pkg::flash_part_e part_q; - - prim_fifo_sync #( - .Width (AddrW + $bits(flash_ctrl_pkg::flash_part_e)), - .Pass (0), - .Depth (2) - ) i_slice ( - .clk_i, - .rst_ni, - .clr_i (1'b0), - .wvalid_i(rd_i), - .wready_o(), - .wdata_i ({part_i, addr_i}), - .depth_o (), - .rvalid_o(rd_q), - .rready_i(hold_cmd), //whenver command is held, pop - .rdata_o ({part_q, addr_q}) - ); - - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) st_q <= StReset; - else st_q <= st_d; - end - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - held_addr <= '0; - held_part <= flash_ctrl_pkg::FlashPartData; - held_wdata <= '0; - end else if (hold_cmd) begin - held_addr <= rd_q ? addr_q : addr_i; - held_part <= rd_q ? part_q : part_i; - held_wdata <= prog_data_i; - end - end - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - time_limit_q <= 32'h0; - index_limit_q <= 32'h0; - prog_pend_q <= 1'h0; - end else begin - time_limit_q <= time_limit_d; - index_limit_q <= index_limit_d; - prog_pend_q <= prog_pend_d; - end - end - - // prog_pend_q is necessary to emulate flash behavior that a bit written to 0 cannot be written - // back to 1 without an erase - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - time_cnt <= 32'h0; - index_cnt <= 32'h0; - held_rdata <= 'h0; - end else begin - if (time_cnt_inc) time_cnt <= time_cnt + 1'b1; - else if (time_cnt_set1) time_cnt <= 32'h1; - else if (time_cnt_clr) time_cnt <= 32'h0; - - if (index_cnt_inc) index_cnt <= index_cnt + 1'b1; - else if (index_cnt_clr) index_cnt <= 32'h0; - - if (prog_pend_q) held_rdata <= rd_data_o; - - end + logic [NumBanks-1:0] init_busy; + assign init_busy_o = |init_busy; + + // this represents the type of program operations that are supported + assign prog_type_avail_o[flash_ctrl_pkg::FlashProgNormal] = 1'b1; + assign prog_type_avail_o[flash_ctrl_pkg::FlashProgRepair] = 1'b1; + + for (genvar bank = 0; bank < NumBanks; bank++) begin : gen_prim_flash_banks + prim_generic_flash_bank #( + .InfosPerBank(InfosPerBank), + .PagesPerBank(PagesPerBank), + .WordsPerPage(WordsPerPage), + .DataWidth(DataWidth), + .MetaDataWidth(MetaDataWidth) + ) u_prim_flash_bank ( + .clk_i, + .rst_ni, + .rd_i(flash_req_i[bank].rd_req), + .prog_i(flash_req_i[bank].prog_req), + .prog_last_i(flash_req_i[bank].prog_last), + .prog_type_i(flash_req_i[bank].prog_type), + .pg_erase_i(flash_req_i[bank].pg_erase_req), + .bk_erase_i(flash_req_i[bank].bk_erase_req), + .addr_i(flash_req_i[bank].addr), + .part_i(flash_req_i[bank].part), + .prog_data_i(flash_req_i[bank].prog_full_data), + .ack_o(flash_rsp_o[bank].ack), + .done_o(flash_rsp_o[bank].done), + .rd_data_o(flash_rsp_o[bank].rdata), + .init_busy_o(init_busy[bank]), + .flash_power_ready_h_i, + .flash_power_down_h_i + ); end - - always_comb begin - // state - st_d = st_q; - - // internally consumed signals - index_limit_d = index_limit_q; - time_limit_d = time_limit_q; - prog_pend_d = prog_pend_q; - mem_req = 'h0; - mem_wr = 'h0; - mem_addr = 'h0; - mem_part = flash_ctrl_pkg::FlashPartData; - mem_wdata = 'h0; - time_cnt_inc = 1'h0; - time_cnt_clr = 1'h0; - time_cnt_set1 = 1'h0; - index_cnt_inc = 1'h0; - index_cnt_clr = 1'h0; - hold_cmd = 1'h0; - - // i/o - init_busy_o = 1'h0; - ack_o = 1'h0; - - unique case (st_q) - StReset: begin - init_busy_o = 1'h1; - st_d = StInit; - end - // Emulate flash power up to all 1's - // This implies this flash will not survive a reset - // Might need a different RESET for FPGA purposes - StInit: begin - init_busy_o = 1'h1; - if (index_cnt < WordsPerBank && !SkipInit) begin - st_d = StInit; - index_cnt_inc = 1'b1; - mem_req = 1'h0; - mem_wr = 1'h0; - mem_addr = index_cnt[AddrW-1:0]; - mem_wdata = {DataWidth{1'b1}}; - end else begin - st_d = StIdle; - index_cnt_clr = 1'b1; - end - end - StIdle: begin - if (rd_q) begin - // reads begin immediately - hold_cmd = 1'b1; - mem_addr = addr_q; - mem_part = part_q; - mem_req = 1'b1; - time_cnt_inc = 1'b1; - st_d = StRead; - end else if (prog_i) begin - hold_cmd = 1'b1; - st_d = StRead; - prog_pend_d = 1'b1; - end else if (pg_erase_i) begin - hold_cmd = 1'b1; - st_d = StErase; - index_limit_d = WordsPerPage; - time_limit_d = PgEraseCycles; - end else if (bk_erase_i) begin - hold_cmd = 1'b1; - st_d = StErase; - index_limit_d = WordsPerBank; - time_limit_d = BkEraseCycles; - end - end - StRead: begin - mem_addr = held_addr; - mem_part = held_part; - if (time_cnt < ReadCycles) begin - mem_req = 1'b1; - time_cnt_inc = 1'b1; - end else if (!prog_pend_q) begin - ack_o = 1'b1; //finish up transaction - - // if another request already pending - if (rd_q) begin - hold_cmd = 1'b1; - mem_addr = addr_q; - mem_part = part_q; - mem_req = 1'b1; - time_cnt_set1 = 1'b1; - st_d = StRead; - end else begin - time_cnt_clr = 1'b1; - st_d = StIdle; - end - end else if (prog_pend_q) begin - // this is the read performed before a program operation - prog_pend_d = 1'b0; - time_cnt_clr = 1'b1; - st_d = StProg; - end - end - StProg: begin - mem_addr = held_addr; - mem_part = held_part; - - // if data is already 0, cannot program to 1 without erase - mem_wdata = held_wdata & held_rdata; - if (time_cnt < ProgCycles) begin - mem_req = 1'b1; - mem_wr = 1'b1; - time_cnt_inc = 1'b1; - end else begin - st_d = StIdle; - ack_o = 1'b1; - time_cnt_clr = 1'b1; - end - end - StErase: begin - // Actual erasing of the page - if (index_cnt < index_limit_q || time_cnt < time_limit_q) begin - mem_req = 1'b1; - mem_wr = 1'b1; - mem_wdata = {DataWidth{1'b1}}; - - mem_addr = held_addr + index_cnt[AddrW-1:0]; - mem_part = held_part; - time_cnt_inc = (time_cnt < time_limit_q); - index_cnt_inc = (index_cnt < index_limit_q); - end else begin - st_d = StIdle; - ack_o = 1'b1; - time_cnt_clr = 1'b1; - index_cnt_clr = 1'b1; - end - end - default: begin - st_d = StIdle; - end - endcase // unique case (st_q) - end // always_comb - - logic [DataWidth-1:0] rd_data_main, rd_data_info; - - prim_ram_1p #( - .Width(DataWidth), - .Depth(WordsPerBank), - .DataBitsPerMask(DataWidth) - ) u_mem ( - .clk_i, - .req_i (mem_req & (mem_part == flash_ctrl_pkg::FlashPartData)), - .write_i (mem_wr), - .addr_i (mem_addr), - .wdata_i (mem_wdata), - .wmask_i ({DataWidth{1'b1}}), - .rdata_o (rd_data_main) - ); - - prim_ram_1p #( - .Width(DataWidth), - .Depth(WordsPerInfoBank), - .DataBitsPerMask(DataWidth) - ) u_info_mem ( - .clk_i, - .req_i (mem_req & (mem_part == flash_ctrl_pkg::FlashPartInfo)), - .write_i (mem_wr), - .addr_i (mem_addr[0 +: InfoAddrW]), - .wdata_i (mem_wdata), - .wmask_i ({DataWidth{1'b1}}), - .rdata_o (rd_data_info) - ); - - assign rd_data_o = held_part == flash_ctrl_pkg::FlashPartData ? rd_data_main : rd_data_info; - - // hard-wire assignment for now - assign tdo_o = 1'b0; + logic unused_scanmode; + logic unused_scan_rst_n; + logic [TestModeWidth-1:0] unused_flash_test_mode; + logic unused_flash_test_voltage; + logic unused_tck; + logic unused_tdi; + logic unused_tms; + + assign unused_scanmode = scanmode_i; + assign unused_scan_rst_n = scan_rst_ni; + assign unused_flash_test_mode = flash_test_mode_a_i; + assign unused_flash_test_voltage = flash_test_voltage_h_i; + assign unused_tck = tck_i; + assign unused_tdi = tdi_i; + assign unused_tms = tms_i; + assign tdo_o = '0; endmodule // prim_generic_flash diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash_bank.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash_bank.sv new file mode 100644 index 0000000000..8683f185d8 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash_bank.sv @@ -0,0 +1,415 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Emulate a single generic flash bank +// + +module prim_generic_flash_bank #( + parameter int InfosPerBank = 1, // info pages per bank + parameter int PagesPerBank = 256, // data pages per bank + parameter int WordsPerPage = 256, // words per page + parameter int DataWidth = 32, // bits per word + parameter int MetaDataWidth = 12, // this is a temporary parameter to work around ECC issues + + // Derived parameters + localparam int PageW = $clog2(PagesPerBank), + localparam int WordW = $clog2(WordsPerPage), + localparam int AddrW = PageW + WordW +) ( + input clk_i, + input rst_ni, + input rd_i, + input prog_i, + input prog_last_i, + // the generic model does not make use of program types + input flash_ctrl_pkg::flash_prog_e prog_type_i, + input pg_erase_i, + input bk_erase_i, + input [AddrW-1:0] addr_i, + input flash_ctrl_pkg::flash_part_e part_i, + input [DataWidth-1:0] prog_data_i, + output logic ack_o, + output logic done_o, + output logic [DataWidth-1:0] rd_data_o, + output logic init_busy_o, + input flash_power_ready_h_i, + input flash_power_down_h_i +); + + // Emulated flash macro values + localparam int ReadCycles = 1; + localparam int ProgCycles = 50; + localparam int PgEraseCycles = 200; + localparam int BkEraseCycles = 2000; + localparam int InitCycles = 100; + + // Locally derived values + localparam int WordsPerBank = PagesPerBank * WordsPerPage; + localparam int WordsPerInfoBank = InfosPerBank * WordsPerPage; + localparam int InfoAddrW = $clog2(WordsPerInfoBank); + + typedef enum logic [2:0] { + StReset = 'h0, + StInit = 'h1, + StIdle = 'h2, + StRead = 'h3, + StProg = 'h4, + StErase = 'h5 + } state_e; + + state_e st_q, st_d; + + logic [31:0] time_cnt; + logic [31:0] index_cnt; + logic time_cnt_inc ,time_cnt_clr, time_cnt_set1; + logic index_cnt_inc, index_cnt_clr; + logic [31:0] index_limit_q, index_limit_d; + logic [31:0] time_limit_q, time_limit_d; + logic prog_pend_q, prog_pend_d; + logic mem_req; + logic mem_wr; + logic [DataWidth-1:0] mem_wdata; + logic [AddrW-1:0] mem_addr; + flash_ctrl_pkg::flash_part_e mem_part; + + // insert a fifo here to break the large fanout from inputs to memories on reads + typedef struct packed { + logic rd; + logic prog; + logic prog_last; + flash_ctrl_pkg::flash_prog_e prog_type; + logic pg_erase; + logic bk_erase; + logic [AddrW-1:0] addr; + flash_ctrl_pkg::flash_part_e part; + logic [DataWidth-1:0] prog_data; + } cmd_payload_t; + + cmd_payload_t cmd_d, cmd_q; + logic cmd_valid; + logic pop_cmd; + logic mem_rd_q, mem_rd_d; + + assign cmd_d = '{ + rd : rd_i, + prog: prog_i, + prog_last: prog_last_i, + prog_type: prog_type_i, + pg_erase: pg_erase_i, + bk_erase: bk_erase_i, + addr: addr_i, + part: part_i, + prog_data: prog_data_i + }; + + // for read transactions, in order to reduce latency, the + // command fifo is popped early (before done_o). This is to ensure that when + // the current transaction is complete, during the same cycle + // a new read can be issued. As a result, the command is popped + // immediately after the read is issued, rather than waiting for + // the read to be completed. The same restrictions are not necessary + // for program / erase, which do not have the same performance + // requirements. + + // when the flash is going through init, do not accept any transactions + logic wvalid; + logic ack; + assign wvalid = (rd_i | prog_i | pg_erase_i | bk_erase_i) & !init_busy_o; + assign ack_o = ack & !init_busy_o; + + prim_fifo_sync #( + .Width ($bits(cmd_payload_t)), + .Pass (0), + .Depth (2) + ) u_cmd_fifo ( + .clk_i, + .rst_ni, + .clr_i (1'b0), + .wvalid_i(wvalid), + .wready_o(ack), + .wdata_i (cmd_d), + .depth_o (), + .rvalid_o(cmd_valid), + .rready_i(pop_cmd), + .rdata_o (cmd_q) + ); + + logic rd_req, prog_req, pg_erase_req, bk_erase_req; + assign rd_req = cmd_valid & cmd_q.rd; + assign prog_req = cmd_valid & cmd_q.prog; + assign pg_erase_req = cmd_valid & cmd_q.pg_erase; + assign bk_erase_req = cmd_valid & cmd_q.bk_erase; + + // for read / program operations, the index cnt should be 0 + assign mem_rd_d = mem_req & ~mem_wr; + assign mem_addr = cmd_q.addr + index_cnt[AddrW-1:0]; + assign mem_part = cmd_q.part; + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) st_q <= StReset; + else st_q <= st_d; + end + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + time_limit_q <= 'h0; + index_limit_q <= 'h0; + prog_pend_q <= 'h0; + mem_rd_q <= 'h0; + end else begin + time_limit_q <= time_limit_d; + index_limit_q <= index_limit_d; + prog_pend_q <= prog_pend_d; + mem_rd_q <= mem_rd_d; + end + end + + // latch read data from emulated memories the cycle after a read + logic [DataWidth-1:0] rd_data_q, rd_data_d; + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + rd_data_q <= '0; + end else if (mem_rd_q) begin + rd_data_q <= rd_data_d; + end + end + + // latch partiton being read since the command fifo is popped early + flash_ctrl_pkg::flash_part_e rd_part_q; + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + rd_part_q <= flash_ctrl_pkg::FlashPartData; + end else if (mem_rd_d) begin + rd_part_q <= cmd_q.part; + end + end + + // if read cycle is only 1, we can expose the unlatched data directly + if (ReadCycles == 1) begin : gen_fast_rd_data + assign rd_data_o = rd_data_d; + end else begin : gen_rd_data + assign rd_data_o = rd_data_q; + end + + // prog_pend_q is necessary to emulate flash behavior that a bit written to 0 cannot be written + // back to 1 without an erase + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + time_cnt <= 'h0; + index_cnt <= 'h0; + end else begin + if (time_cnt_inc) time_cnt <= time_cnt + 1'b1; + else if (time_cnt_set1) time_cnt <= 32'h1; + else if (time_cnt_clr) time_cnt <= 32'h0; + + if (index_cnt_inc) index_cnt <= index_cnt + 1'b1; + else if (index_cnt_clr) index_cnt <= 32'h0; + end + end + + + always_comb begin + // state + st_d = st_q; + + // internally consumed signals + index_limit_d = index_limit_q; + time_limit_d = time_limit_q; + prog_pend_d = prog_pend_q; + mem_req = '0; + mem_wr = '0; + mem_wdata = '0; + time_cnt_inc = '0; + time_cnt_clr = '0; + time_cnt_set1 = '0; + index_cnt_inc = '0; + index_cnt_clr = '0; + + // i/o + init_busy_o = '0; + pop_cmd = '0; + done_o = '0; + + unique case (st_q) + StReset: begin + init_busy_o = 1'b1; + if (flash_power_ready_h_i && !flash_power_down_h_i) begin + st_d = StInit; + end + end + + // Emulate flash initilaization with a wait timer + StInit: begin + init_busy_o = 1'h1; + if (index_cnt < InitCycles) begin + st_d = StInit; + index_cnt_inc = 1'b1; + end else begin + st_d = StIdle; + index_cnt_clr = 1'b1; + end + end + + StIdle: begin + if (rd_req) begin + pop_cmd = 1'b1; + mem_req = 1'b1; + time_cnt_inc = 1'b1; + st_d = StRead; + end else if (prog_req) begin + mem_req = 1'b1; + prog_pend_d = 1'b1; + st_d = StRead; + end else if (pg_erase_req) begin + st_d = StErase; + index_limit_d = WordsPerPage; + time_limit_d = PgEraseCycles; + end else if (bk_erase_req) begin + st_d = StErase; + index_limit_d = WordsPerBank; + time_limit_d = BkEraseCycles; + end + end + + StRead: begin + if (time_cnt < ReadCycles) begin + time_cnt_inc = 1'b1; + + end else if (!prog_pend_q) begin + done_o = 1'b1; + + // if another request already pending + if (rd_req) begin + pop_cmd = 1'b1; + mem_req = 1'b1; + time_cnt_set1 = 1'b1; + st_d = StRead; + end else begin + time_cnt_clr = 1'b1; + st_d = StIdle; + end + + end else if (prog_pend_q) begin + // this is the read performed before a program operation + prog_pend_d = 1'b0; + time_cnt_clr = 1'b1; + st_d = StProg; + end + end + + StProg: begin + // if data is already 0, cannot program to 1 without erase + mem_wdata = cmd_q.prog_data & rd_data_q; + if (time_cnt < ProgCycles) begin + mem_req = 1'b1; + mem_wr = 1'b1; + time_cnt_inc = 1'b1; + end else begin + st_d = StIdle; + pop_cmd = 1'b1; + done_o = cmd_q.prog_last; + time_cnt_clr = 1'b1; + end + end + + StErase: begin + // Actual erasing of the page + if (index_cnt < index_limit_q || time_cnt < time_limit_q) begin + mem_req = 1'b1; + mem_wr = 1'b1; + mem_wdata = {DataWidth{1'b1}}; + time_cnt_inc = (time_cnt < time_limit_q); + index_cnt_inc = (index_cnt < index_limit_q); + end else begin + st_d = StIdle; + pop_cmd = 1'b1; + done_o = 1'b1; + time_cnt_clr = 1'b1; + index_cnt_clr = 1'b1; + end + end + default: begin + st_d = StIdle; + end + + endcase // unique case (st_q) + + // Emulate power down and power loss behavior + if (!flash_power_ready_h_i || flash_power_down_h_i) begin + st_d = StReset; + end + + end // always_comb + + localparam int MemWidth = DataWidth - MetaDataWidth; + + logic [DataWidth-1:0] rd_data_main, rd_data_info; + logic [MemWidth-1:0] rd_nom_data_main, rd_nom_data_info; + logic [MetaDataWidth-1:0] rd_meta_data_main, rd_meta_data_info; + + prim_ram_1p #( + .Width(MemWidth), + .Depth(WordsPerBank), + .DataBitsPerMask(MemWidth) + ) u_mem ( + .clk_i, + .req_i (mem_req & (mem_part == flash_ctrl_pkg::FlashPartData)), + .write_i (mem_wr), + .addr_i (mem_addr), + .wdata_i (mem_wdata[MemWidth-1:0]), + .wmask_i ({MemWidth{1'b1}}), + .rdata_o (rd_nom_data_main) + ); + + prim_ram_1p #( + .Width(MetaDataWidth), + .Depth(WordsPerBank), + .DataBitsPerMask(MetaDataWidth) + ) u_mem_meta ( + .clk_i, + .req_i (mem_req & (mem_part == flash_ctrl_pkg::FlashPartData)), + .write_i (mem_wr), + .addr_i (mem_addr), + .wdata_i (mem_wdata[MemWidth +: MetaDataWidth]), + .wmask_i ({MetaDataWidth{1'b1}}), + .rdata_o (rd_meta_data_main) + ); + + prim_ram_1p #( + .Width(MemWidth), + .Depth(WordsPerInfoBank), + .DataBitsPerMask(MemWidth) + ) u_info_mem ( + .clk_i, + .req_i (mem_req & (mem_part == flash_ctrl_pkg::FlashPartInfo)), + .write_i (mem_wr), + .addr_i (mem_addr[0 +: InfoAddrW]), + .wdata_i (mem_wdata[MemWidth-1:0]), + .wmask_i ({MemWidth{1'b1}}), + .rdata_o (rd_nom_data_info) + ); + + prim_ram_1p #( + .Width(MetaDataWidth), + .Depth(WordsPerInfoBank), + .DataBitsPerMask(MetaDataWidth) + ) u_info_mem_meta ( + .clk_i, + .req_i (mem_req & (mem_part == flash_ctrl_pkg::FlashPartInfo)), + .write_i (mem_wr), + .addr_i (mem_addr[0 +: InfoAddrW]), + .wdata_i (mem_wdata[MemWidth +: MetaDataWidth]), + .wmask_i ({MetaDataWidth{1'b1}}), + .rdata_o (rd_meta_data_info) + ); + + assign rd_data_main = {rd_meta_data_main, rd_nom_data_main}; + assign rd_data_info = {rd_meta_data_info, rd_nom_data_info}; + assign rd_data_d = rd_part_q == flash_ctrl_pkg::FlashPartData ? rd_data_main : rd_data_info; + + flash_ctrl_pkg::flash_prog_e unused_prog_type; + assign unused_prog_type = cmd_q.prog_type; + + +endmodule // prim_generic_flash diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_otp.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_otp.sv index 4d3f3831c3..f22b00ae06 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_otp.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_otp.sv @@ -3,107 +3,339 @@ // SPDX-License-Identifier: Apache-2.0 module prim_generic_otp #( - parameter int Width = 8, - parameter int Depth = 1024, - parameter int ErrWidth = 8, - localparam int AddrWidth = $clog2(Depth) + // Native OTP word size. This determines the size_i granule. + parameter int Width = 16, + parameter int Depth = 1024, + parameter int CmdWidth = otp_ctrl_pkg::OtpCmdWidth, + // This determines the maximum number of native words that + // can be transferred accross the interface in one cycle. + parameter int SizeWidth = otp_ctrl_pkg::OtpSizeWidth, + // Width of the power sequencing signal. + parameter int PwrSeqWidth = otp_ctrl_pkg::OtpPwrSeqWidth, + // Number of Test TL-UL words + parameter int TlDepth = 16, + // Derived parameters + localparam int AddrWidth = prim_util_pkg::vbits(Depth), + localparam int IfWidth = 2**SizeWidth*Width, + // VMEM file to initialize the memory with + parameter MemInitFile = "" ) ( - input clk_i, - input rst_ni, - // TODO: power sequencing signals from/to AST + input clk_i, + input rst_ni, + // Macro-specific power sequencing signals to/from AST + output logic [PwrSeqWidth-1:0] pwr_seq_o, + input [PwrSeqWidth-1:0] pwr_seq_h_i, // Test interface - input tlul_pkg::tl_h2d_t test_tl_i, - output tlul_pkg::tl_d2h_t test_tl_o, - // Start Macro init sequence - // init shall be asserted until acknowledged with done - input init_req_i, - output logic init_done_o, - // Macro error output - // TODO: define error codes - output logic err_valid_o, - output logic [ErrWidth-1:0] err_code_o, + input tlul_pkg::tl_h2d_t test_tl_i, + output tlul_pkg::tl_d2h_t test_tl_o, // Ready valid handshake for read/write command - output logic ready_o, - input valid_i, - input [AddrWidth-1:0] addr_i, - input [Width-1:0] wdata_i, - input wren_i, // 0: read command, 1: write command - // Read data output - output logic [Width-1:0] rdata_o, - output logic rvalid_o + output logic ready_o, + input valid_i, + input [SizeWidth-1:0] size_i, // #(Native words)-1, e.g. size == 0 for 1 native word. + input [CmdWidth-1:0] cmd_i, // 00: read command, 01: write command, 11: init command + input [AddrWidth-1:0] addr_i, + input [IfWidth-1:0] wdata_i, + // Response channel + output logic valid_o, + output logic [IfWidth-1:0] rdata_o, + output otp_ctrl_pkg::otp_err_e err_o ); + // Not supported in open-source emulation model. + logic [PwrSeqWidth-1:0] unused_pwr_seq_h; + assign unused_pwr_seq_h = pwr_seq_h_i; + assign pwr_seq_o = '0; + + //////////////////////////////////// + // TL-UL Test Interface Emulation // + //////////////////////////////////// + + // Put down a register that can be used to test the TL interface. + // TODO: this emulation may need to be adjusted, once closed source wrapper is + // implemented. + localparam int TlAddrWidth = prim_util_pkg::vbits(TlDepth); + logic tlul_req, tlul_rvalid_q, tlul_wren; + logic [TlDepth-1:0][31:0] tlul_regfile_q; + logic [31:0] tlul_wdata, tlul_rdata_q; + logic [TlAddrWidth-1:0] tlul_addr; + + tlul_adapter_sram #( + .SramAw ( TlAddrWidth ), + .SramDw ( 32 ), + .Outstanding ( 1 ), + .ByteAccess ( 0 ), + .ErrOnWrite ( 0 ) + ) u_tlul_adapter_sram ( + .clk_i, + .rst_ni, + .tl_i ( test_tl_i ), + .tl_o ( test_tl_o ), + .req_o ( tlul_req ), + .gnt_i ( tlul_req ), + .we_o ( tlul_wren ), + .addr_o ( tlul_addr ), + .wdata_o ( tlul_wdata ), + .wmask_o ( ), + .rdata_i ( tlul_rdata_q ), + .rvalid_i ( tlul_rvalid_q ), + .rerror_i ( '0 ) + ); + + always_ff @(posedge clk_i or negedge rst_ni) begin : p_tlul_testreg + if (!rst_ni) begin + tlul_rvalid_q <= 1'b0; + tlul_rdata_q <= '0; + tlul_regfile_q <= '0; + end else begin + tlul_rvalid_q <= tlul_req & ~tlul_wren; + if (tlul_req && tlul_wren) begin + tlul_regfile_q[tlul_addr] <= tlul_wdata; + end else if (tlul_req && !tlul_wren) begin + tlul_rdata_q <= tlul_regfile_q[tlul_addr]; + end + end + end + /////////////////// // Control logic // /////////////////// - logic req, write_d, write_q, read_d, read_q; - logic [Width-1:0] wdata, wdata_d, wdata_q; - logic [AddrWidth-1:0] addr, waddr_d, waddr_q; - - // TODO: add support for these in emulation - assign test_tl_o = '0; - assign err_valid_o = '0; - assign err_type_o = '0; - assign init_done_o = 1'b1; - - // TODO: randomize / extend access times - assign read_d = ready_o & valid_i & ~wren_i; - assign write_d = ready_o & valid_i & wren_i; - assign wdata_d = (write_d) ? wdata_i : wdata_q; - assign waddr_d = (write_d) ? addr_i : waddr_q; - - assign ready_o = ~write_q; - assign rvalid_o = read_q; - - // perform read modify write and OR bits on top - // of existing data - assign wdata = rdata_o | wdata_q; - assign addr = (write_q) ? waddr_q : addr_i; - assign req = read_d | write_d | write_q; - - ////////////////////////////////// - // Emulate using memory process // - ////////////////////////////////// - - logic [Width-1:0] mem [Depth]; - - // using always instead of always_ff to avoid 'ICPD - illegal combination of drivers' error - // thrown when using $readmemh system task to backdoor load an image - always @(posedge clk_i) begin - if (req) begin - if (write_q) begin - mem[addr] <= wdata; - end else begin - rdata_o <= mem[addr]; + // Encoding generated with ./sparse-fsm-encode.py -d 5 -m 8 -n 10 + // Hamming distance histogram: + // + // 0: -- + // 1: -- + // 2: -- + // 3: -- + // 4: -- + // 5: |||||||||||||||||||| (53.57%) + // 6: ||||||||||||| (35.71%) + // 7: | (3.57%) + // 8: || (7.14%) + // 9: -- + // 10: -- + // + // Minimum Hamming distance: 5 + // Maximum Hamming distance: 8 + // + localparam int StateWidth = 10; + typedef enum logic [StateWidth-1:0] { + ResetSt = 10'b1100000011, + InitSt = 10'b1100110100, + IdleSt = 10'b1010111010, + ReadSt = 10'b0011100000, + ReadWaitSt = 10'b1001011111, + WriteCheckSt = 10'b0111010101, + WriteWaitSt = 10'b0000001100, + WriteSt = 10'b0110101111 + } state_e; + + state_e state_d, state_q; + otp_ctrl_pkg::otp_err_e err_d, err_q; + logic valid_d, valid_q; + logic req, wren, rvalid; + logic [1:0] rerror; + logic [Width-1:0] rdata_d; + logic [2**SizeWidth-1:0][Width-1:0] rdata_q, wdata_q; + logic [AddrWidth-1:0] addr_q; + logic [SizeWidth-1:0] size_q; + logic [SizeWidth-1:0] cnt_d, cnt_q; + logic cnt_clr, cnt_en; + + assign cnt_d = (cnt_clr) ? '0 : + (cnt_en) ? cnt_q + 1'b1 : cnt_q; + + assign valid_o = valid_q; + assign rdata_o = rdata_q; + assign err_o = err_q; + + always_comb begin : p_fsm + // Default + state_d = state_q; + ready_o = 1'b0; + valid_d = 1'b0; + err_d = otp_ctrl_pkg::NoError; + req = 1'b0; + wren = 1'b0; + cnt_clr = 1'b0; + cnt_en = 1'b0; + + unique case (state_q) + // Wait here until we receive an initialization command. + ResetSt: begin + ready_o = 1'b1; + if (valid_i) begin + if (cmd_i == otp_ctrl_pkg::OtpInit) begin + state_d = InitSt; + end else begin + // Invalid commands get caught here + valid_d = 1'b1; + err_d = otp_ctrl_pkg::MacroError; + end + end end - end + // Wait for some time until the OTP macro is ready. + InitSt: begin + state_d = IdleSt; + valid_d = 1'b1; + end + // In the idle state, we basically wait for read or write commands. + IdleSt: begin + ready_o = 1'b1; + if (valid_i) begin + cnt_clr = 1'b1; + err_d = otp_ctrl_pkg::NoError; + unique case (cmd_i) + otp_ctrl_pkg::OtpRead: state_d = ReadSt; + otp_ctrl_pkg::OtpWrite: state_d = WriteCheckSt; + default: begin + // Invalid commands get caught here + valid_d = 1'b1; + err_d = otp_ctrl_pkg::MacroError; + end + endcase // cmd_i + end + end + // Issue a read command to the macro. + ReadSt: begin + state_d = ReadWaitSt; + req = 1'b1; + end + // Wait for response from macro. + ReadWaitSt: begin + if (rvalid) begin + cnt_en = 1'b1; + // Uncorrectable error, bail out. + if (rerror[1]) begin + state_d = IdleSt; + valid_d = 1'b1; + err_d = otp_ctrl_pkg::MacroEccUncorrError; + end else begin + if (cnt_q == size_q) begin + state_d = IdleSt; + valid_d = 1'b1; + end else begin + state_d = ReadSt; + end + // Correctable error, carry on but signal back. + if (rerror[0]) begin + err_d = otp_ctrl_pkg::MacroEccCorrError; + end + end + end + end + // First, perform a blank check. + WriteCheckSt: begin + state_d = WriteWaitSt; + req = 1'b1; + end + // Wait for readout to complete first. + // If the write data would clear an already programmed bit, or if we got an uncorrectable + // ECC error, the check has failed and we abort the write at this point. + WriteWaitSt: begin + if (rvalid) begin + cnt_en = 1'b1; + // TODO: this blank check needs to be extended to account for the ECC bits as well. + if (rerror[1] || (rdata_d & wdata_q[cnt_q]) != rdata_d) begin + state_d = IdleSt; + valid_d = 1'b1; + err_d = otp_ctrl_pkg::MacroWriteBlankError; + end else begin + if (cnt_q == size_q) begin + cnt_clr = 1'b1; + state_d = WriteSt; + end else begin + state_d = WriteCheckSt; + end + end + end + end + // Now that the write check was successful, we can write all native words in one go. + WriteSt: begin + req = 1'b1; + wren = 1'b1; + cnt_en = 1'b1; + if (cnt_q == size_q) begin + valid_d = 1'b1; + state_d = IdleSt; + end + end + default: begin + state_d = ResetSt; + end + endcase // state_q end - // TODO: add verilator init mechanism - `ifdef OTP_INIT_FILE - localparam MEM_FILE = `PRIM_STRINGIFY(`OTP_INIT_FILE); - initial begin - $display("Initializing OTP from %s", MEM_FILE); - $readmemh(MEM_FILE, mem); - end - `endif + /////////////////////////////////////////// + // Emulate using ECC protected Block RAM // + /////////////////////////////////////////// + + logic [AddrWidth-1:0] addr; + assign addr = addr_q + AddrWidth'(cnt_q); + + prim_ram_1p_adv #( + .Depth (Depth), + .Width (Width), + .MemInitFile (MemInitFile), + .EnableECC (1'b1), + .EnableInputPipeline (1), + .EnableOutputPipeline (1) + ) i_prim_ram_1p_adv ( + .clk_i, + .rst_ni, + .req_i ( req ), + .write_i ( wren ), + .addr_i ( addr ), + .wdata_i ( wdata_q[cnt_q] ), + .wmask_i ( {Width{1'b1}} ), + .rdata_o ( rdata_d ), + .rvalid_o ( rvalid ), + .rerror_o ( rerror ), + .cfg_i ( '0 ) + ); + + // Currently it is assumed that no wrap arounds can occur. + `ASSERT(NoWrapArounds_A, addr >= addr_q) ////////// // Regs // ////////// + // This primitive is used to place a size-only constraint on the + // flops in order to prevent FSM state encoding optimizations. + logic [StateWidth-1:0] state_raw_q; + assign state_q = state_e'(state_raw_q); + prim_flop #( + .Width(StateWidth), + .ResetValue(StateWidth'(ResetSt)) + ) u_state_regs ( + .clk_i, + .rst_ni, + .d_i ( state_d ), + .q_o ( state_raw_q ) + ); + always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs if (!rst_ni) begin - read_q <= 1'b0; - write_q <= 1'b0; + valid_q <= '0; + err_q <= otp_ctrl_pkg::NoError; + addr_q <= '0; wdata_q <= '0; - waddr_q <= '0; + rdata_q <= '0; + cnt_q <= '0; + size_q <= '0; end else begin - read_q <= read_d; - write_q <= write_d; - wdata_q <= wdata_d; - waddr_q <= waddr_d; + valid_q <= valid_d; + err_q <= err_d; + cnt_q <= cnt_d; + if (ready_o && valid_i) begin + addr_q <= addr_i; + wdata_q <= wdata_i; + size_q <= size_i; + end + if (rvalid) begin + rdata_q[cnt_q] <= rdata_d; + end end end diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_pad_wrapper.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_pad_wrapper.sv index 962d3b559c..62a518edf8 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_pad_wrapper.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_pad_wrapper.sv @@ -79,8 +79,7 @@ module prim_generic_pad_wrapper #( assign (strong0, strong1) inout_io = (oe && drv != DRIVE_00) ? out : 1'bz; assign (pull0, pull1) inout_io = (oe && drv == DRIVE_00) ? out : 1'bz; // pullup / pulldown termination - assign (highz0, weak1) inout_io = pe & ps; // enabled and select = 1 - assign (weak0, highz1) inout_io = pe & ~ps; // enabled and select = 0 + assign (weak0, weak1) inout_io = pe ? ps : 1'bz; // fake trireg emulation assign (weak0, weak1) inout_io = (kp) ? inout_io : 1'bz; // received data driver diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_usb_diff_rx.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_usb_diff_rx.sv new file mode 100644 index 0000000000..7830413b11 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_usb_diff_rx.sv @@ -0,0 +1,32 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Generic differential receiver for USB. Note that this is meant for emulation purposes only, and +// the pull-up, calibration and pok signals are not connected in this module. + +`include "prim_assert.sv" + +module prim_generic_usb_diff_rx #( + parameter int CalibW = 32 +) ( + input wire input_pi, // differential input + input wire input_ni, // differential input + input input_en_i, // input buffer enable + input core_pok_i, // core power indication at VCC level + input pullup_p_en_i, // pullup enable for P + input pullup_n_en_i, // pullup enable for N + input [CalibW-1:0] calibration_i, // calibration input + output logic input_o // output of differential input buffer +); + + assign input_o = (input_en_i) ? input_pi & ~input_ni : 1'b0; + + logic unused_pullup_p_en, unused_pullup_n_en; + logic [CalibW-1:0] unused_calibration; + + assign unused_calibration = calibration_i; + assign unused_pullup_p_en = pullup_p_en_i; + assign unused_pullup_n_en = pullup_n_en_i; + +endmodule : prim_generic_usb_diff_rx diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/lint/prim_xilinx_clock_buf.vlt b/vendor/lowrisc_ip/ip/prim_xilinx/lint/prim_xilinx_clock_buf.vlt new file mode 100644 index 0000000000..544a7b79b1 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim_xilinx/lint/prim_xilinx_clock_buf.vlt @@ -0,0 +1,4 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/lint/prim_xilinx_clock_buf.waiver b/vendor/lowrisc_ip/ip/prim_xilinx/lint/prim_xilinx_clock_buf.waiver new file mode 100644 index 0000000000..af90009c05 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim_xilinx/lint/prim_xilinx_clock_buf.waiver @@ -0,0 +1,4 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/lint/prim_xilinx_pad_wrapper.waiver b/vendor/lowrisc_ip/ip/prim_xilinx/lint/prim_xilinx_pad_wrapper.waiver index 0269d16604..95afe1398f 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/lint/prim_xilinx_pad_wrapper.waiver +++ b/vendor/lowrisc_ip/ip/prim_xilinx/lint/prim_xilinx_pad_wrapper.waiver @@ -4,9 +4,9 @@ # # waiver file for prim_xilinx_pad_wrapper # note that this code is NOT synthesizable and meant for sim only -waive -rules TRI_DRIVER -regexp {'inout_io' is driven by a tristate driver} - -location {prim_xilinx_pad_wrapper.sv} +waive -rules TRI_DRIVER -regexp {'inout_io' is driven by a tristate driver} \ + -location {prim_xilinx_pad_wrapper.sv} \ -comment "This is a bidirectional pad inout." -waive -rules INPUT_NOT_READ -regexp {Input port 'attr\_i\[.:2\]' is not read from} - -location {prim_xilinx_pad_wrapper.sv} +waive -rules INPUT_NOT_READ -regexp {Input port 'attr\_i\[.:2\]' is not read from} \ + -location {prim_xilinx_pad_wrapper.sv} \ -comment "Some IO attributes may not be implemented." diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_clock_buf.core b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_clock_buf.core new file mode 100644 index 0000000000..a94a86fb7f --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_clock_buf.core @@ -0,0 +1,42 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +name: "lowrisc:prim_xilinx:clock_buf" +description: "clock buffer" +filesets: + files_rtl: + files: + - rtl/prim_xilinx_clock_buf.sv + file_type: systemVerilogSource + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + - lint/prim_xilinx_clock_buf.vlt + file_type: vlt + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + - lint/prim_xilinx_clock_buf.waiver + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + - lowrisc:lint:comportable + +targets: + default: + filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) + - files_rtl diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_flop.core b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_flop.core new file mode 100644 index 0000000000..ecd876b0b2 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_flop.core @@ -0,0 +1,40 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +name: "lowrisc:prim_xilinx:flop" +description: "generic flop" +filesets: + files_rtl: + files: + - rtl/prim_xilinx_flop.sv + file_type: systemVerilogSource + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + file_type: vlt + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + - lowrisc:lint:comportable + +targets: + default: + filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) + - files_rtl diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_clock_buf.sv b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_clock_buf.sv new file mode 100644 index 0000000000..5de8f58f2e --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_clock_buf.sv @@ -0,0 +1,15 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +module prim_xilinx_clock_buf ( + input clk_i, + output logic clk_o +); + + BUFG bufg_i ( + .I (clk_i), + .O (clk_o) + ); + +endmodule diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_clock_gating.sv b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_clock_gating.sv index 402af9043c..c30e95cf61 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_clock_gating.sv +++ b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_clock_gating.sv @@ -2,17 +2,25 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -module prim_xilinx_clock_gating ( +module prim_xilinx_clock_gating #( + parameter bit NoFpgaGate = 1'b0 +) ( input clk_i, input en_i, input test_en_i, output logic clk_o ); - BUFGCE u_bufgce ( - .I (clk_i), - .CE (en_i | test_en_i), - .O (clk_o) - ); + if (NoFpgaGate) begin : gen_no_gate + assign clk_o = clk_i; + end else begin : gen_gate + BUFGCE u_bufgce ( + .I (clk_i), + .CE (en_i | test_en_i), + .O (clk_o) + ); + end + + endmodule diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_clock_mux2.sv b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_clock_mux2.sv index 572c20ffed..fd251475ec 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_clock_mux2.sv +++ b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_clock_mux2.sv @@ -4,22 +4,28 @@ `include "prim_assert.sv" -module prim_xilinx_clock_mux2 ( +module prim_xilinx_clock_mux2 #( + parameter bit NoFpgaBufG = 1'b0 +) ( input clk0_i, input clk1_i, input sel_i, output logic clk_o ); - // for more info, refer to the Xilinx technology primitives userguide, e.g.: - // ug953-vivado-7series-libraries.pdf - // ug974-vivado-ultrascale-libraries.pdf - BUFGMUX bufgmux_i ( - .S ( sel_i ), - .I0 ( clk0_i ), - .I1 ( clk1_i ), - .O ( clk_o ) - ); + if (NoFpgaBufG) begin : gen_no_bufg + assign clk_o = (sel_i) ? clk1_i : clk0_i; + end else begin : gen_bufg + // for more info, refer to the Xilinx technology primitives userguide, e.g.: + // ug953-vivado-7series-libraries.pdf + // ug974-vivado-ultrascale-libraries.pdf + BUFGMUX bufgmux_i ( + .S ( sel_i ), + .I0 ( clk0_i ), + .I1 ( clk1_i ), + .O ( clk_o ) + ); + end // make sure sel is never X (including during reset) // need to use ##1 as this could break with inverted clocks that diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_flop.sv b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_flop.sv new file mode 100644 index 0000000000..f98314a6cc --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_flop.sv @@ -0,0 +1,27 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`include "prim_assert.sv" + +module prim_xilinx_flop # ( + parameter int Width = 1, + localparam int WidthSubOne = Width-1, + parameter logic [WidthSubOne:0] ResetValue = 0 +) ( + input clk_i, + input rst_ni, + input [Width-1:0] d_i, + // Prevent Vivado from optimizing this signal away. + (* keep = "true" *) output logic [Width-1:0] q_o +); + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + q_o <= ResetValue; + end else begin + q_o <= d_i; + end + end + +endmodule // prim_xilinx_flop diff --git a/vendor/lowrisc_ip/lint/doc/README.md b/vendor/lowrisc_ip/lint/doc/README.md index e84447fd62..ab918c1fec 100644 --- a/vendor/lowrisc_ip/lint/doc/README.md +++ b/vendor/lowrisc_ip/lint/doc/README.md @@ -1,3 +1,7 @@ +--- +title: "Linting" +--- + # RTL Linting Linting is a productivity tool for designers to quickly find typos and bugs at the time when the RTL is written. @@ -59,6 +63,10 @@ targets: parameters: - SYNTHESIS=true tools: + ascentlint: + ascentlint_options: + - "-wait_license" + - "-stop_on_error" verilator: mode: lint-only verilator_options: diff --git a/vendor/lowrisc_ip/lint/tools/ascentlint/parse-lint-report.py b/vendor/lowrisc_ip/lint/tools/ascentlint/parse-lint-report.py index b85f55c9ec..b05884c9c6 100755 --- a/vendor/lowrisc_ip/lint/tools/ascentlint/parse-lint-report.py +++ b/vendor/lowrisc_ip/lint/tools/ascentlint/parse-lint-report.py @@ -47,7 +47,9 @@ def get_results(resdir): ("errors", r"^ERROR.*"), ("errors", r"^ ERR .*"), ("warnings", r"^Warning: .*"), - ("warnings", r"^ WARN .*")] + # TODO: struct assignment labels within concatenation + # not supported. check with newer ascentlint version. + ("warnings", r"^ (?!WARN \[#39024\])WARN .*")] extract_messages(full_file, err_warn_patterns, results) except IOError as err: results["errors"] += ["IOError: %s" % err] diff --git a/vendor/lowrisc_ip/lint/data/ascentlint.hjson b/vendor/lowrisc_ip/lint/tools/dvsim/ascentlint.hjson similarity index 100% rename from vendor/lowrisc_ip/lint/data/ascentlint.hjson rename to vendor/lowrisc_ip/lint/tools/dvsim/ascentlint.hjson diff --git a/vendor/lowrisc_ip/lint/data/common_lint_cfg.hjson b/vendor/lowrisc_ip/lint/tools/dvsim/common_lint_cfg.hjson similarity index 89% rename from vendor/lowrisc_ip/lint/data/common_lint_cfg.hjson rename to vendor/lowrisc_ip/lint/tools/dvsim/common_lint_cfg.hjson index 3f53b9248c..a4e571c24f 100644 --- a/vendor/lowrisc_ip/lint/data/common_lint_cfg.hjson +++ b/vendor/lowrisc_ip/lint/tools/dvsim/common_lint_cfg.hjson @@ -3,12 +3,12 @@ // SPDX-License-Identifier: Apache-2.0 { flow: lint - flow_makefile: "{proj_root}/hw/lint/data/lint.mk" + flow_makefile: "{proj_root}/hw/lint/tools/dvsim/lint.mk" import_cfgs: [// common server configuration for results upload "{proj_root}/hw/data/common_project_cfg.hjson" // tool-specific configuration - "{proj_root}/hw/lint/data/{tool}.hjson"] + "{proj_root}/hw/lint/tools/dvsim/{tool}.hjson"] // Name of the DUT / top-level to be run through lint dut: "{name}" diff --git a/vendor/lowrisc_ip/lint/data/lint.mk b/vendor/lowrisc_ip/lint/tools/dvsim/lint.mk similarity index 100% rename from vendor/lowrisc_ip/lint/data/lint.mk rename to vendor/lowrisc_ip/lint/tools/dvsim/lint.mk diff --git a/vendor/lowrisc_ip/lint/data/veriblelint.hjson b/vendor/lowrisc_ip/lint/tools/dvsim/veriblelint.hjson similarity index 100% rename from vendor/lowrisc_ip/lint/data/veriblelint.hjson rename to vendor/lowrisc_ip/lint/tools/dvsim/veriblelint.hjson diff --git a/vendor/lowrisc_ip/lint/data/verilator.hjson b/vendor/lowrisc_ip/lint/tools/dvsim/verilator.hjson similarity index 100% rename from vendor/lowrisc_ip/lint/data/verilator.hjson rename to vendor/lowrisc_ip/lint/tools/dvsim/verilator.hjson diff --git a/vendor/lowrisc_ip/util/dvsim/Deploy.py b/vendor/lowrisc_ip/util/dvsim/Deploy.py index 4be4454227..b945fe1e35 100644 --- a/vendor/lowrisc_ip/util/dvsim/Deploy.py +++ b/vendor/lowrisc_ip/util/dvsim/Deploy.py @@ -75,7 +75,7 @@ def __init__(self, sim_cfg): self.renew_odir = False # List of vars required to be exported to sub-shell - self.exports = {} + self.exports = None # Deploy sub commands self.sub = [] @@ -157,9 +157,36 @@ def __post_init__(self): self.odir_ln = os.path.basename(os.path.normpath(self.odir)) self.log = self.odir + "/" + self.target + ".log" + # Make exports more easily mergeable with the current process' env. + self._process_exports() + # If using LSF, redirect stdout and err to the log file self.cmd = self.construct_cmd() + def _process_exports(self): + '''Convert 'exports' as a list of dicts in the HJson to a dict. + + Exports is a list of key-value pairs that are to be exported to the + subprocess' environment so that the tools can lookup those options. + DVSim limits how the data is presented in the HJson (the value of a + HJson member cannot be an object). This method converts a list of dicts + into a dict variable, which makes it easy to merge the list of exports + with the subprocess' env where the ASIC tool is invoked. + ''' + exports_dict = {} + if self.exports: + try: + exports_dict = { + k: str(v) + for item in self.exports for k, v in item.items() + } + except ValueError as e: + log.error( + "%s: exports: \'%s\' Exports key must be a list of dicts!", + e, str(self.exports)) + sys.exit(1) + self.exports = exports_dict + def construct_cmd(self): cmd = "make -f " + self.flow_makefile + " " + self.target if self.dry_run is True: @@ -216,7 +243,11 @@ def is_equivalent_job(self, item): return True def dispatch_cmd(self): - self.exports.update(os.environ) + # Update the shell's env vars with self.exports. Values in exports must + # replace the values in the shell's env vars if the keys match. + exports = os.environ.copy() + exports.update(self.exports) + args = shlex.split(self.cmd) try: # If renew_odir flag is True - then move it. @@ -228,8 +259,8 @@ def dispatch_cmd(self): "w", encoding="UTF-8", errors="surrogateescape") as f: - for var in sorted(self.exports.keys()): - f.write("{}={}\n".format(var, self.exports[var])) + for var in sorted(exports.keys()): + f.write("{}={}\n".format(var, exports[var])) f.close() os.system("ln -s " + self.odir + " " + self.sim_cfg.links['D'] + '/' + self.odir_ln) @@ -241,7 +272,7 @@ def dispatch_cmd(self): universal_newlines=True, stdout=f, stderr=f, - env=self.exports) + env=exports) self.log_fd = f self.status = "D" Deploy.dispatch_counter += 1 @@ -385,7 +416,15 @@ def kill(self): ''' if self.status == "D" and self.process.poll() is None: self.kill_remote_job() - self.process.kill() + + # Try to kill the running process. Send SIGTERM first, wait a bit, + # and then send SIGKILL if it didn't work. + self.process.terminate() + try: + self.process.wait(timeout=2) + except subprocess.TimeoutExpired: + self.process.kill() + if self.log_fd: self.log_fd.close() self.status = "K" @@ -713,6 +752,10 @@ def __init__(self, index, test, sim_cfg): self.fail_patterns = [] self.mandatory_cmd_attrs.update({ + # tool srcs + "tool_srcs": False, + "tool_srcs_dir": False, + "proj_root": False, "uvm_test": False, "uvm_test_seq": False, @@ -855,6 +898,9 @@ def __post_init__(self): ignored_wildcards=["cov_db_dirs"], ignore_error=False) + # Call base class __post_init__ to do checks and substitutions + super().__post_init__() + # Prune previous merged cov directories. prev_cov_db_dirs = self.odir_limiter(odir=self.cov_merge_db_dir) @@ -867,9 +913,6 @@ def __post_init__(self): # Append cov_db_dirs to the list of exports. self.exports["cov_db_dirs"] = "\"{}\"".format(self.cov_db_dirs) - # Call base class __post_init__ to do checks and substitutions - super().__post_init__() - class CovReport(Deploy): """ diff --git a/vendor/lowrisc_ip/util/dvsim/FlowCfg.py b/vendor/lowrisc_ip/util/dvsim/FlowCfg.py index 94804837eb..584d2acb9e 100644 --- a/vendor/lowrisc_ip/util/dvsim/FlowCfg.py +++ b/vendor/lowrisc_ip/util/dvsim/FlowCfg.py @@ -16,7 +16,7 @@ from utils import VERBOSE, md_results_to_html, parse_hjson, subst_wildcards # A set of fields that can be overridden on the command line. -_CMDLINE_FIELDS = {'tool'} +_CMDLINE_FIELDS = {'tool', 'verbosity'} # Interface class for extensions. @@ -24,9 +24,6 @@ class FlowCfg(): def __str__(self): return pprint.pformat(self.__dict__) - def __repr__(self): - return pprint.pformat(self.__dict__) - def __init__(self, flow_cfg_file, proj_root, args): # Options set from command line self.items = args.items @@ -382,25 +379,6 @@ def _do_override(self, ov_name, ov_value): log.error("Override key \"%s\" not found in the cfg!", ov_name) sys.exit(1) - def _process_exports(self): - # Convert 'exports' to dict - exports_dict = {} - if self.exports != []: - for item in self.exports: - if type(item) is dict: - exports_dict.update(item) - elif type(item) is str: - [key, value] = item.split(':', 1) - if type(key) is not str: - key = str(key) - if type(value) is not str: - value = str(value) - exports_dict.update({key.strip(): value.strip()}) - else: - log.error("Type error in \"exports\": %s", str(item)) - sys.exit(1) - self.exports = exports_dict - def _purge(self): '''Purge the existing scratch areas in preperation for the new run.''' return diff --git a/vendor/lowrisc_ip/util/dvsim/Makefile b/vendor/lowrisc_ip/util/dvsim/Makefile new file mode 100644 index 0000000000..f0ab377746 --- /dev/null +++ b/vendor/lowrisc_ip/util/dvsim/Makefile @@ -0,0 +1,7 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +.PHONY: test +test: + pytest . diff --git a/vendor/lowrisc_ip/util/dvsim/OneShotCfg.py b/vendor/lowrisc_ip/util/dvsim/OneShotCfg.py index e79e837a80..6e407ec608 100644 --- a/vendor/lowrisc_ip/util/dvsim/OneShotCfg.py +++ b/vendor/lowrisc_ip/util/dvsim/OneShotCfg.py @@ -109,8 +109,6 @@ def __init__(self, flow_cfg_file, proj_root, args): if not hasattr(self, "build_mode"): setattr(self, "build_mode", "default") - self._process_exports() - # Create objects from raw dicts - build_modes, sim_modes, run_modes, # tests and regressions, only if not a primary cfg obj self._create_objects() diff --git a/vendor/lowrisc_ip/util/dvsim/SimCfg.py b/vendor/lowrisc_ip/util/dvsim/SimCfg.py index ef4d11ba36..b7dff526c4 100644 --- a/vendor/lowrisc_ip/util/dvsim/SimCfg.py +++ b/vendor/lowrisc_ip/util/dvsim/SimCfg.py @@ -20,8 +20,8 @@ from utils import VERBOSE, find_and_substitute_wildcards -def pick_dump_format(fmts): - '''Choose a supported wave dumping format +def pick_wave_format(fmts): + '''Pick a supported wave format from a list. fmts is a list of formats that the chosen tool supports. Return the first that we think is possible (e.g. not fsdb if Verdi is not installed). @@ -29,53 +29,17 @@ def pick_dump_format(fmts): ''' assert fmts fmt = fmts[0] + # TODO: This will not work if the EDA tools are expected to be launched + # in a separate sandboxed environment such as Docker / LSF. In such case, + # Verdi may be installed in that environment, but it may not be visible in + # the current repo environment where dvsim is invoked. if fmt == 'fsdb' and not shutil.which('verdi'): - return pick_dump_format(fmts[1:]) + log.log(VERBOSE, "Skipping fsdb since verdi is not found in $PATH") + return pick_wave_format(fmts[1:]) return fmt -def resolve_dump_format(tool, dump): - '''Decide on the correct dumping format - - This is called after reading the config file. tool is the chosen tool, - which will always have been resolved by this point. waves is a boolean - which determines whether waves should be dumped at all (from the --waves - argument). dump is the dumping format chosen on the command line or None. - - ''' - assert tool is not None - - SUPPORTED_DUMP_FMTS = { - 'vcs': ['fsdb', 'vpd'], - 'xcelium': ['fsdb', 'shm', 'vpd'] - } - - # Look up which dumping formats the tool supports - fmts = SUPPORTED_DUMP_FMTS.get(tool) - - if dump is not None: - # If the user has specified their preferred dumping format, use it. As - # a sanity check, error out if the chosen tool doesn't support the - # format, but only if we know about the tool. If not, we'll just assume - # they know what they're doing. - if fmts is not None and dump not in fmts: - log.error('Chosen tool ({}) does not support wave ' - 'dumping format {!r}.'.format(tool, dump)) - sys.exit(1) - - return dump - - # If the user hasn't specified a dumping format, but has asked for waves, - # we need to decide on a format for them. If fmts is None, we don't know - # about this tool. Maybe it's a new simulator, in which case, default to - # VPD and hope for the best. - if not fmts: - return 'vpd' - - return pick_dump_format(fmts) - - class SimCfg(FlowCfg): """Simulation configuration object @@ -98,14 +62,19 @@ def __init__(self, flow_cfg_file, proj_root, args): self.run_only = args.run_only self.reseed_ovrd = args.reseed self.reseed_multiplier = args.reseed_multiplier - self.waves = args.waves + # Waves must be of type string, since it may be used as substitution + # variable in the HJson cfg files. + self.waves = args.waves or 'none' self.max_waves = args.max_waves self.cov = args.cov self.cov_merge_previous = args.cov_merge_previous self.profile = args.profile or '(cfg uses profile without --profile)' self.xprop_off = args.xprop_off self.no_rerun = args.no_rerun - self.verbosity = "{" + args.verbosity + "}" + # Single-character verbosity setting (n, l, m, h, d). args.verbosity + # might be None, in which case we'll pick up a default value from + # configuration files. + self.verbosity = args.verbosity self.verbose = args.verbose self.dry_run = args.dry_run self.map_full_testplan = args.map_full_testplan @@ -115,7 +84,7 @@ def __init__(self, flow_cfg_file, proj_root, args): self.cov = False # Set default sim modes for unpacking - if self.waves is True: + if args.waves is not None: self.en_build_modes.append("waves") if self.cov is True: self.en_build_modes.append("cov") @@ -142,6 +111,7 @@ def __init__(self, flow_cfg_file, proj_root, args): self.build_modes = [] self.run_modes = [] self.regressions = [] + self.supported_wave_formats = None # Options from tools - for building and running tests self.build_cmd = "" @@ -165,11 +135,10 @@ def __init__(self, flow_cfg_file, proj_root, args): # Parse the cfg_file file tree self._parse_flow_cfg(flow_cfg_file) - # Choose a dump format now. Note that this has to happen after parsing + # Choose a wave format now. Note that this has to happen after parsing # the configuration format because our choice might depend on the # chosen tool. - self.dump_fmt = (resolve_dump_format(self.tool, args.dump) - if self.waves else 'none') + self.waves = self._resolve_waves() # If build_unique is set, then add current timestamp to uniquify it if self.build_unique: @@ -222,8 +191,6 @@ def __init__(self, flow_cfg_file, proj_root, args): if not hasattr(self, "build_mode"): self.build_mode = 'default' - self._process_exports() - # Create objects from raw dicts - build_modes, sim_modes, run_modes, # tests and regressions, only if not a primary cfg obj self._create_objects() @@ -235,6 +202,47 @@ def __post_init__(self): # Run some post init checks super().__post_init__() + def _resolve_waves(self): + '''Choose and return a wave format, if waves are enabled. + + This is called after reading the config file. This method is used to + update the value of class member 'waves', which must be of type string, + since it is used as a substitution variable in the parsed HJson dict. + If waves are not enabled, or if this is a primary cfg, then return + 'none'. 'tool', which must be set at this point, supports a limited + list of wave formats (supplied with 'supported_wave_formats' key). If + waves is set to 'default', then pick the first item on that list; else + pick the desired format. + ''' + if self.waves == 'none' or self.is_primary_cfg: + return 'none' + + assert self.tool is not None + + # If the user hasn't specified a wave format (No argument supplied + # to --waves), we need to decide on a format for them. The supported + # list of wave formats is set in the tool's HJson configuration using + # the `supported_wave_formats` key. If that list is not set, we use + # 'vpd' by default and hope for the best. It that list if set, then we + # pick the first available format for which the waveform viewer exists. + if self.waves == 'default': + if self.supported_wave_formats: + return pick_wave_format(self.supported_wave_formats) + else: + return 'vpd' + + # If the user has specified their preferred wave format, use it. As + # a sanity check, error out if the chosen tool doesn't support the + # format, but only if we know about the tool. If not, we'll just assume + # they know what they're doing. + if self.supported_wave_formats and \ + self.waves not in self.supported_wave_formats: + log.error('Chosen tool ({}) does not support wave format ' + '{!r}.'.format(self.tool, self.waves)) + sys.exit(1) + + return self.waves + def kill(self): '''kill running processes and jobs gracefully ''' diff --git a/vendor/lowrisc_ip/util/dvsim/dvsim.py b/vendor/lowrisc_ip/util/dvsim/dvsim.py index d060f111be..53ccc62f16 100755 --- a/vendor/lowrisc_ip/util/dvsim/dvsim.py +++ b/vendor/lowrisc_ip/util/dvsim/dvsim.py @@ -146,11 +146,11 @@ def make_config(args, proj_root): # the tool by reading the config file. At the moment, this forces a # simulation target (TODO?) factories = { - 'ascentlint' : LintCfg.LintCfg, - 'veriblelint' : LintCfg.LintCfg, - 'verilator' : LintCfg.LintCfg, - 'dc' : SynCfg.SynCfg, - 'jaspergold' : FpvCfg.FpvCfg + 'ascentlint': LintCfg.LintCfg, + 'veriblelint': LintCfg.LintCfg, + 'verilator': LintCfg.LintCfg, + 'dc': SynCfg.SynCfg, + 'jaspergold': FpvCfg.FpvCfg } factory = factories.get(args.tool, SimCfg.SimCfg) @@ -235,9 +235,9 @@ def parse_args(): whatg.add_argument("-i", "--items", nargs="*", - default=["sanity"], + default=["smoke"], help=('Specify the regressions or tests to run. ' - 'Defaults to "sanity", but can be a ' + 'Defaults to "smoke", but can be a ' 'space separated list of test or regression ' 'names.')) @@ -351,7 +351,9 @@ def parse_args(): 'applied to each simulation run.')) rung.add_argument("--profile", "-p", + nargs="?", choices=['time', 'mem'], + const="time", metavar="P", help=('Turn on simulation profiling (where P is time ' 'or mem).')) @@ -367,12 +369,11 @@ def parse_args(): "enabled.")) rung.add_argument("--verbosity", "-v", - default="l", choices=['n', 'l', 'm', 'h', 'd'], metavar='V', - help=('Set UVM verbosity to none (n), low (l; the ' - 'default), medium (m), high (h) or debug (d). ' - 'This overrides any setting in the config files.')) + help=('Set tool/simulation verbosity to none (n), low ' + '(l), medium (m), high (h) or debug (d). ' + 'The default value is set in config files.')) seedg = parser.add_argument_group('Test seeds') @@ -410,16 +411,15 @@ def parse_args(): waveg = parser.add_argument_group('Dumping waves') waveg.add_argument("--waves", "-w", - action='store_true', - help="Enable dumping of waves") - - waveg.add_argument("-d", - "--dump", - choices=["fsdb", "shm", "vpd"], - help=("Format to dump waves for simulation. The default " - "format depends on the tool. With VCS, this " - "defaults to fsdb if Verdi is installed, else " - "vpd. With Xcelium, defaults to shm.")) + nargs="?", + choices=["default", "fsdb", "shm", "vpd", "vcd", "evcd", + "fst"], + const="default", + help=("Enable dumping of waves. It takes an optional " + "argument to pick the desired wave format. If " + "the optional argument is not supplied, it picks " + "whatever is the default for the chosen tool. " + "By default, dumping waves is not enabled.")) waveg.add_argument("--max-waves", "-mw", type=int, @@ -468,7 +468,6 @@ def parse_args(): dvg.add_argument("--verbose", nargs="?", choices=['default', 'debug'], - default=None, const="default", metavar="D", help=('With no argument, print verbose dvsim tool ' diff --git a/vendor/lowrisc_ip/util/dvsim/testplanner/README.md b/vendor/lowrisc_ip/util/dvsim/testplanner/README.md index bd8d84ea5f..8aa8a45dd5 100644 --- a/vendor/lowrisc_ip/util/dvsim/testplanner/README.md +++ b/vendor/lowrisc_ip/util/dvsim/testplanner/README.md @@ -7,7 +7,7 @@ format into a data structure that can be used for: * Expanding the testplan inline within the DV plan as a table * Annotating the regression results with testplan entries for a document driven DV execution -Please see [DV methodology]({{< relref "doc/ug/dv_methodology.md#documentation" >}}) +Please see [DV methodology]({{< relref "doc/ug/dv_methodology/index.md#documentation" >}}) for more details on the rationale and motivation for writing and maintaining testplans in a machine-parsable format (`Hjson`). This document will focus on the anatomy of a Hjson testplan, list of features supported @@ -21,8 +21,8 @@ intent of a planned test: * **name: name of the planned test** This is a single `lower_snake_case` string that succinctly describes the intended - feature being tested. As an example, a basic sanity test which is typically the - first test written on a brand new testbench would be simply named `sanity`. + feature being tested. As an example, a smoke test which is typically the + first test written on a brand new testbench would be simply named `smoke`. * **milestone: verification milestone** @@ -172,7 +172,7 @@ In addition, see the [UART DV Plan]({{< relref "hw/ip/uart/doc/dv_plan" >}}) for real 'production' example of inline expansion of an imported testplan as a table within the DV Plan document. The [UART testplan](https://github.com/lowRISC/opentitan/blob/master/hw/ip/uart/data/uart_testplan.hjson) -imports the shared testplans located at `hw/dv/tools/testplans` area. +imports the shared testplans located at `hw/dv/tools/dvsim/testplans` area. ### Limitations diff --git a/vendor/lowrisc_ip/util/dvsim/testplanner/examples/foo_regr_results.hjson b/vendor/lowrisc_ip/util/dvsim/testplanner/examples/foo_regr_results.hjson index be83aadef1..46f0585e14 100644 --- a/vendor/lowrisc_ip/util/dvsim/testplanner/examples/foo_regr_results.hjson +++ b/vendor/lowrisc_ip/util/dvsim/testplanner/examples/foo_regr_results.hjson @@ -5,7 +5,7 @@ timestamp: 10/10/2019 1:55AM test_results: [ { - name: foo_sanity + name: foo_smoke passing: 25 total: 50 } diff --git a/vendor/lowrisc_ip/util/dvsim/testplanner/examples/foo_testplan.hjson b/vendor/lowrisc_ip/util/dvsim/testplanner/examples/foo_testplan.hjson index 10afb7e82c..d4e079cd8a 100644 --- a/vendor/lowrisc_ip/util/dvsim/testplanner/examples/foo_testplan.hjson +++ b/vendor/lowrisc_ip/util/dvsim/testplanner/examples/foo_testplan.hjson @@ -14,15 +14,15 @@ entries: [ { // name of the testplan entry - should be unique - name: sanity - desc: '''Basic FOO sanity test. Describe this test in sufficient detail. You can - split the description on multiple lines like this (with 3 single-inverted - commas. Note that the subsequent lines are indented right below where the - inverted commas start.''' + name: smoke + desc: '''FOO smoke test. Describe this test in sufficient detail. You can split + the description on multiple lines like this (with 3 single-inverted commas. + Note that the subsequent lines are indented right below where the inverted + commas start.''' // milestone for which this test is targeted for - V1, V2 or V3 milestone: V1 // tests of actual written tests that maps to this entry - tests: ["foo_sanity"] + tests: ["foo_smoke"] } { name: feature1 diff --git a/vendor/lowrisc_ip/util/dvsim/utils.py b/vendor/lowrisc_ip/util/dvsim/utils.py index c4853ee3f5..d18dd53fe8 100644 --- a/vendor/lowrisc_ip/util/dvsim/utils.py +++ b/vendor/lowrisc_ip/util/dvsim/utils.py @@ -86,84 +86,203 @@ def parse_hjson(hjson_file): return hjson_cfg_dict -def subst_wildcards(var, mdict, ignored_wildcards=[], ignore_error=False): +def _stringify_wildcard_value(value): + '''Make sense of a wildcard value as a string (see subst_wildcards) + + Strings are passed through unchanged. Integer or boolean values are printed + as numerical strings. Lists or other sequences have their items printed + separated by spaces. + ''' - If var has wildcards specified within {..}, find and substitute them. + if type(value) is str: + return value + + if type(value) in [bool, int]: + return str(int(value)) + + try: + return ' '.join(_stringify_wildcard_value(x) for x in value) + except TypeError: + raise ValueError('Wildcard had value {!r} which is not of a supported type.') + + +def _subst_wildcards(var, mdict, ignored, ignore_error, seen): + '''Worker function for subst_wildcards + + seen is a list of wildcards that have been expanded on the way to this call + (used for spotting circular recursion). + + Returns (expanded, seen_err) where expanded is the new value of the string + and seen_err is true if we stopped early because of an ignored error. + ''' - def subst(wildcard, mdict): - if wildcard in mdict.keys(): - return mdict[wildcard] - else: - return None - - if "{eval_cmd}" in var: - idx = var.find("{eval_cmd}") + 11 - subst_var = subst_wildcards(var[idx:], mdict, ignored_wildcards, - ignore_error) - # If var has wildcards that were ignored, then skip running the command - # for now, assume that it will be handled later. - match = re.findall(r"{([A-Za-z0-9\_]+)}", subst_var) - if len(match) == 0: - var = run_cmd(subst_var) - else: - match = re.findall(r"{([A-Za-z0-9\_]+)}", var) - if len(match) > 0: - ignored_wildcards_found = False - no_substitutions_found = True - for item in match: - if item in ignored_wildcards: - ignored_wildcards_found = True - else: - log.debug("Found wildcard \"%s\" in \"%s\"", item, var) - found = subst(item, mdict) - if found is not None: - if type(found) is list: - subst_found = [] - for element in found: - element = subst_wildcards( - element, mdict, ignored_wildcards, - ignore_error) - subst_found.append(element) - # Expand list into a str since list within list is - # not supported. - found = " ".join(subst_found) - - elif type(found) is str: - found = subst_wildcards(found, mdict, - ignored_wildcards, - ignore_error) - - elif type(found) is bool: - found = int(found) - var = var.replace("{" + item + "}", str(found)) - no_substitutions_found = False - else: - # Check if the wildcard exists as an environment variable - env_var = os.environ.get(item) - if env_var is not None: - var = var.replace("{" + item + "}", str(env_var)) - no_substitutions_found = False - elif not ignore_error: - log.error( - "Substitution for the wildcard \"%s\" not found", - item) - sys.exit(1) - - # If items were found for substitution, but if they were a part - # of ignored_wildcards list or if substitutions for them were not - # found, then, we return. If all substitutions were made, then check - # for second level of indirection: - # - # For example: lets say we supply the dict: - # {var: '{{foo}_xyz{bar}}', foo: p, bar: q, p_xyz_q: baz} - # - # Then after the substitutions above: {var: '{p_xyz_q}', ...} - # We need to now substitute {p_xyz_q}, so that the final value of - # var is 'baz'. - if not (ignored_wildcards_found or no_substitutions_found): - var = subst_wildcards(var, mdict, ignored_wildcards, - ignore_error) - return var + wildcard_re = re.compile(r"{([A-Za-z0-9\_]+)}") + + # Work from left to right, expanding each wildcard we find. idx is where we + # should start searching (so that we don't keep finding a wildcard that + # we've decided to ignore). + idx = 0 + + any_err = False + + while True: + right_str = var[idx:] + match = wildcard_re.search(right_str) + + # If no match, we're done. + if match is None: + return (var, any_err) + + name = match.group(1) + + # If the name should be ignored, skip over it. + if name in ignored: + idx += match.end() + continue + + # If the name has been seen already, we've spotted circular recursion. + # That's not allowed! + if name in seen: + raise ValueError('String contains circular expansion of ' + 'wildcard {!r}.' + .format(match.group(0))) + + # Treat eval_cmd specially + if name == 'eval_cmd': + cmd = _subst_wildcards(right_str[match.end():], + mdict, ignored, ignore_error, seen)[0] + + # Are there any wildcards left in cmd? If not, we can run the + # command and we're done. + cmd_matches = list(wildcard_re.finditer(cmd)) + if not cmd_matches: + var = var[:idx] + run_cmd(cmd) + continue + + # Otherwise, check that each of them is ignored, or that + # ignore_error is True. + bad_names = False + if not ignore_error: + for cmd_match in cmd_matches: + if cmd_match.group(1) not in ignored: + bad_names = True + + if bad_names: + raise ValueError('Cannot run eval_cmd because the command ' + 'expands to {!r}, which still contains a ' + 'wildcard.' + .format(cmd)) + + # We can't run the command (because it still has wildcards), but we + # don't want to report an error either because ignore_error is true + # or because each wildcard that's left is ignored. Return the + # partially evaluated version. + return (var[:idx] + right_str[:match.end()] + cmd, True) + + # Otherwise, look up name in mdict. + value = mdict.get(name) + + # If the value isn't set, check the environment + if value is None: + value = os.environ.get(name) + + if value is None: + # Ignore missing values if ignore_error is True. + if ignore_error: + idx += match.end() + continue + + raise ValueError('String to be expanded contains ' + 'unknown wildcard, {!r}.' + .format(match.group(0))) + + value = _stringify_wildcard_value(value) + + # Do any recursive expansion of value, adding name to seen (to avoid + # circular recursion). + value, saw_err = _subst_wildcards(value, mdict, + ignored, ignore_error, seen + [name]) + + # Replace the original match with the result and go around again. If + # saw_err, increment idx past what we just inserted. + var = (var[:idx] + + right_str[:match.start()] + value + right_str[match.end():]) + if saw_err: + any_err = True + idx += match.start() + len(value) + + +def subst_wildcards(var, mdict, ignored_wildcards=[], ignore_error=False): + '''Substitute any "wildcard" variables in the string var. + + var is the string to be substituted. mdict is a dictionary mapping + variables to strings. ignored_wildcards is a list of wildcards that + shouldn't be substituted. ignore_error means to partially evaluate rather + than exit on an error. + + A wildcard is written as a name (alphanumeric, allowing backslash and + underscores) surrounded by braces. For example, + + subst_wildcards('foo {x} baz', {'x': 'bar'}) + + returns "foo bar baz". Dictionary values can be strings, booleans, integers + or lists. For example: + + subst_wildcards('{a}, {b}, {c}, {d}', + {'a': 'a', 'b': True, 'c': 42, 'd': ['a', 10]}) + + returns 'a, 1, 42, a 10'. + + If a wildcard is in ignored_wildcards, it is ignored. For example, + + subst_wildcards('{a} {b}', {'b': 'bee'}, ignored_wildcards=['a']) + + returns "{a} bee". + + If a wildcard appears in var but is not in mdict, the environment is + checked for the variable. If the name still isn't found, the default + behaviour is to log an error and exit. If ignore_error is True, the + wildcard is ignored (as if it appeared in ignore_wildcards). + + If {eval_cmd} appears in the string and 'eval_cmd' is not in + ignored_wildcards then the following text is recursively expanded. The + result of this expansion is treated as a command to run and the text is + replaced by the output of the command. + + If a wildcard has been ignored (either because of ignored_wildcards or + ignore_error), the command to run in eval_cmd might contain a match for + wildcard_re. If ignore_error is True, the command is not run. So + + subst_wildcards('{eval_cmd}{foo}', {}, ignore_error=True) + + will return '{eval_cmd}{foo}' unchanged. If ignore_error is False, the + function logs an error and exits. + + Recursion is possible in subst_wildcards. For example, + + subst_wildcards('{a}', {'a': '{b}', 'b': 'c'}) + + returns 'c'. Circular recursion is detected, however. So + + subst_wildcards('{a}', {'a': '{b}', 'b': '{a}'}) + + will log an error and exit. This error is raised whether or not + ignore_error is set. + + Since subst_wildcards works from left to right, it's possible to compute + wildcard names with code like this: + + subst_wildcards('{a}b}', {'a': 'a {', 'b': 'bee'}) + + which returns 'a bee'. This is pretty hard to read though, so is probably + not a good idea to use. + + ''' + try: + return _subst_wildcards(var, mdict, ignored_wildcards, ignore_error, [])[0] + except ValueError as err: + log.error(str(err)) + sys.exit(1) def find_and_substitute_wildcards(sub_dict, diff --git a/vendor/lowrisc_ip/util/dvsim/utils_test.py b/vendor/lowrisc_ip/util/dvsim/utils_test.py new file mode 100644 index 0000000000..d8267b76ec --- /dev/null +++ b/vendor/lowrisc_ip/util/dvsim/utils_test.py @@ -0,0 +1,77 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +'''pytest-based testing for functions in utils.py''' + +import os +import pytest +from .utils import _subst_wildcards, subst_wildcards + + +def test_subst_wildcards(): + '''Pytest-compatible test for the subst_wildcards function.''' + # Basic checks + assert subst_wildcards('foo {x} baz', {'x': 'bar'}) == 'foo bar baz' + + # Stringify + assert (subst_wildcards('{a}, {b}, {c}, {d}', + {'a': 'a', 'b': True, 'c': 42, 'd': ['{b}', 10]}) == + 'a, 1, 42, 1 10') + + # Ignored wildcards (with or without a match in mdict) + assert (subst_wildcards('{a} {b}', {'a': 'aye', 'b': 'bee'}, + ignored_wildcards=['a']) == + '{a} bee') + assert (subst_wildcards('{a} {b}', {'b': 'bee'}, + ignored_wildcards=['a']) == + '{a} bee') + + # Environment variables. We will always have PWD and can probably assume + # that this won't itself have any braced substrings. + assert (subst_wildcards('{PWD}', {}) == os.environ['PWD']) + + # Missing variable with ignore_error=False, running _subst_wildcards + # instead so that we can catch the error. (We assume that 'biggles' isn't + # in the environment) + with pytest.raises(ValueError) as excinfo: + _subst_wildcards('{biggles} {b}', {'b': 'bee'}, [], False, []) + assert "unknown wildcard, '{biggles}'" in str(excinfo.value) + + # ignore_error=True. + assert (subst_wildcards('{biggles} {b}', {'b': 'bee'}, + ignore_error=True) == + '{biggles} bee') + + # Check we support (non-circular) recursion + assert (subst_wildcards('{a}', {'a': '{b}', 'b': 'c'}) == 'c') + + # Check we spot circular recursion + with pytest.raises(ValueError) as excinfo: + _subst_wildcards('{a}', {'a': '{b}', 'b': '{a}'}, [], False, []) + assert "circular expansion of wildcard '{a}'" in str(excinfo.value) + + # Check we also complain about circular recursion with ignore_error + with pytest.raises(ValueError) as excinfo: + _subst_wildcards('{a}', {'a': '{b}', 'b': '{a}'}, [], True, []) + assert "circular expansion of wildcard '{a}'" in str(excinfo.value) + + # Computed variable names (probably not a great idea, but it's probably + # good to check this works the way we think) + assert subst_wildcards('{a}b}', {'a': 'a {', 'b': 'bee'}) == 'a bee' + + # Some eval_cmd calls (using echo, which should always work) + assert (subst_wildcards('{eval_cmd}echo foo {b}', {'b': 'bar'}) == + 'foo bar') + + # Make sure that nested commands work + assert (subst_wildcards('{eval_cmd} {eval_cmd} echo echo a', {}) == 'a') + + # Recursive expansion + assert (subst_wildcards('{var}', + { + 'var': '{{foo}_xyz_{bar}}', + 'foo': 'p', + 'bar': 'q', + 'p_xyz_q': 'baz' + }) == 'baz') diff --git a/vendor/lowrisc_ip/util/uvmdvgen/Makefile.tpl b/vendor/lowrisc_ip/util/uvmdvgen/Makefile.tpl deleted file mode 100644 index 48b652d61d..0000000000 --- a/vendor/lowrisc_ip/util/uvmdvgen/Makefile.tpl +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright lowRISC contributors. -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 -${'####################################################################################################'} -${'## Copyright lowRISC contributors. ##'} -${'## Licensed under the Apache License, Version 2.0, see LICENSE for details. ##'} -${'## SPDX-License-Identifier: Apache-2.0 ##'} -${'####################################################################################################'} -${'## Entry point test Makefile for building and running tests. ##'} -${'## These are generic set of option groups that apply to all testbenches. ##'} -${'## This flow requires the following options to be set: ##'} -${'## DV_DIR - current dv directory that contains the test Makefile ##'} -${'## DUT_TOP - top level dut module name ##'} -${'## TB_TOP - top level tb module name ##'} -${'## DOTF - .f file used for compilation ##'} -${'## COMPILE_KEY - compile option set ##'} -${'## TEST_NAME - name of the test to run - this is supplied on the command line ##'} -${'####################################################################################################'} -DV_DIR := ${'$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))'} -export DUT_TOP := ${name} -export TB_TOP := tb -FUSESOC_CORE := ${vendor}:dv:${name}_sim:0.1 -COMPILE_KEY ?= default - -# Add coverage exclusion file below -COV_IP_EXCL ?= - -${'####################################################################################################'} -${'## A D D I N D I V I D U A L T E S T S B E L O W ##'} -${'####################################################################################################'} -TEST_NAME ?= ${name}_sanity -UVM_TEST ?= ${name}_base_test -UVM_TEST_SEQ ?= ${name}_base_vseq - -# common tests/seqs -include ${'$'}{DV_DIR}/../../../dv/tools/common_tests.mk - -ifeq (${'$'}{TEST_NAME},${name}_sanity) - UVM_TEST_SEQ = ${name}_sanity_vseq -endif - -${'####################################################################################################'} -${'## Include the tool Makefile below ##'} -${'## Dont add anything else below it! ##'} -${'####################################################################################################'} -include ${'$'}{DV_DIR}/../../../dv/tools/Makefile diff --git a/vendor/lowrisc_ip/util/uvmdvgen/README.md b/vendor/lowrisc_ip/util/uvmdvgen/README.md index 21449430e2..98ea4e4486 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/README.md +++ b/vendor/lowrisc_ip/util/uvmdvgen/README.md @@ -24,7 +24,7 @@ switches. $ util/uvmdvgen/uvmdvgen.py -h usage: uvmdvgen.py [-h] [-a] [-s] [-e] [-c] [-hr] [-hi] [-ha] [-ea agt1 agt2 [agt1 agt2 ...]] [-ao [hw/dv/sv]] - [-eo [hw/ip/]] [-m] [-v VENDOR] + [-eo [hw/ip/]] [-v VENDOR] [ip/block name] Command-line tool to autogenerate boilerplate DV testbench code extended from @@ -69,11 +69,6 @@ optional arguments: doc directories). Under dv, it creates 3 sub- directories - env, tb and tests to place all of the testbench sources. (default set to './') - -m, --add-makefile Tests are now run with dvsim.py tool that requires a - hjson based sim cfg. Setting this option will also - result in the Makefile to be auto-generated (which is - the older way of building and running sims going - through deprecation). -v VENDOR, --vendor VENDOR Name of the vendor / entity developing the testbench. This is used to set the VLNV of the FuesSoC core @@ -173,7 +168,7 @@ Please see description for more details. The tool generates not only the UVM environment, but also the base test, testbench, top level fusesoc core file with sim target, Makefile that already -includes the sanity and CSR test suite and more. With just a few tweaks, this +includes the smoke and CSR test suite and more. With just a few tweaks, this enables the user to reach the V1 milestone much quicker. Let's take `i2c_host` as the argument passed for the name of the IP. The following is the list of files generated with a brief description of their contents: @@ -225,9 +220,9 @@ provided by `-hi` and `-ha` respectively. By default, these are set to 'False' starters, it provides the `i2c_host_init()` task and `do_i2c_host_init` knob for controllability. -* `env/seq_lib/i2c_host_sanity_vseq` +* `env/seq_lib/i2c_host_smoke_vseq` - This is the basic sanity test sequence that user needs to develop as the first + This is the smoke test sequence that user needs to develop as the first test sequence. It extends from `i2c_host_base_vseq`. * `env/seq_lib/i2c_host_csr_vseq` @@ -294,13 +289,6 @@ provided by `-hi` and `-ha` respectively. By default, these are set to 'False' and DV dependencies to construct the complete filelist to pass to simulator's build step. -* `Makefile` - - This is the simulation Makefile that is used as the starting point for - building and running tests using the [make flow]({{< relref "hw/dv/tools/README.md" >}}). - It already includes the sanity and CSR suite of tests to allow users to start - running tests right away. - * `i2c_host_dv_plan.md` This is the initial DV plan document that will describe the entire testbench. This diff --git a/vendor/lowrisc_ip/util/uvmdvgen/agent_pkg.sv.tpl b/vendor/lowrisc_ip/util/uvmdvgen/agent_pkg.sv.tpl index b835748860..d8a64d9568 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/agent_pkg.sv.tpl +++ b/vendor/lowrisc_ip/util/uvmdvgen/agent_pkg.sv.tpl @@ -26,7 +26,7 @@ package ${name}_agent_pkg; .CFG_T (${name}_agent_cfg)) ${name}_driver; % endif - // reuse dv_base_seqeuencer as is with the right parameter set + // reuse dv_base_sequencer as is with the right parameter set typedef dv_base_sequencer #(.ITEM_T(${name}_item), .CFG_T (${name}_agent_cfg)) ${name}_sequencer; diff --git a/vendor/lowrisc_ip/util/uvmdvgen/checklist.md.tpl b/vendor/lowrisc_ip/util/uvmdvgen/checklist.md.tpl index 45656ebe4e..615115015d 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/checklist.md.tpl +++ b/vendor/lowrisc_ip/util/uvmdvgen/checklist.md.tpl @@ -10,35 +10,33 @@ stage, and updated as needed. Once done, please remove this comment before check This checklist is for [Hardware Stage]({{< relref "/doc/project/development_stages.md" >}}) transitions for the [${name.upper()} peripheral.]({{< relref "hw/ip/${name}/doc" >}}) All checklist items refer to the content in the [Checklist.]({{< relref "/doc/project/checklist.md" >}}) -## Design Checklist - -### D1 - -Type | Item | Resolution | Note/Collaterals ---------------|-----------------------|-------------|------------------ -Documentation | [SPEC_COMPLETE][] | Not Started | [${name.upper()} Design Spec]({{}}) -Documentation | [CSR_DEFINED][] | Not Started | -RTL | [CLKRST_CONNECTED][] | Not Started | -RTL | [IP_TOP][] | Not Started | -RTL | [IP_INSTANTIABLE][] | Not Started | -RTL | [MEM_INSTANCED_80][] | Not Started | -RTL | [FUNC_IMPLEMENTED][] | Not Started | -RTL | [ASSERT_KNOWN_ADDED][]| Not Started | -Code Quality | [LINT_SETUP][] | Not Started | -Review | Reviewer(s) | Not Started | -Review | Signoff date | Not Started | - -[SPEC_COMPLETE]: {{}} -[CSR_DEFINED]: {{}} -[CLKRST_CONNECTED]: {{}} -[IP_TOP]: {{}} -[IP_INSTANTIABLE]: {{}} -[MEM_INSTANCED_80]: {{}} -[FUNC_IMPLEMENTED]: {{}} -[ASSERT_KNOWN_ADDED]: {{}} -[LINT_SETUP]: {{}} - -### D2 +<%text>## Design Checklist + +<%text>### D1 + +Type | Item | Resolution | Note/Collaterals +--------------|--------------------------------|-------------|------------------ +Documentation | [SPEC_COMPLETE][] | Not Started | [${name.upper()} Design Spec]({{}}) +Documentation | [CSR_DEFINED][] | Not Started | +RTL | [CLKRST_CONNECTED][] | Not Started | +RTL | [IP_TOP][] | Not Started | +RTL | [IP_INSTANTIABLE][] | Not Started | +RTL | [PHYSICAL_MACROS_DEFINED_80][] | Not Started | +RTL | [FUNC_IMPLEMENTED][] | Not Started | +RTL | [ASSERT_KNOWN_ADDED][] | Not Started | +Code Quality | [LINT_SETUP][] | Not Started | + +[SPEC_COMPLETE]: {{}} +[CSR_DEFINED]: {{}} +[CLKRST_CONNECTED]: {{}} +[IP_TOP]: {{}} +[IP_INSTANTIABLE]: {{}} +[PHYSICAL_MACROS_DEFINED_80]: {{}} +[FUNC_IMPLEMENTED]: {{}} +[ASSERT_KNOWN_ADDED]: {{}} +[LINT_SETUP]: {{}} + +<%text>### D2 Type | Item | Resolution | Note/Collaterals --------------|-------------------------|-------------|------------------ @@ -48,7 +46,7 @@ Documentation | [DOC_INTERFACE][] | Not Started | Documentation | [MISSING_FUNC][] | Not Started | Documentation | [FEATURE_FROZEN][] | Not Started | RTL | [FEATURE_COMPLETE][] | Not Started | -RTL | [AREA_SANITY_CHECK][] | Not Started | +RTL | [AREA_CHECK][] | Not Started | RTL | [PORT_FROZEN][] | Not Started | RTL | [ARCHITECTURE_FROZEN][] | Not Started | RTL | [REVIEW_TODO][] | Not Started | @@ -60,29 +58,29 @@ Code Quality | [CDC_SYNCMACRO][] | Not Started | Security | [SEC_CM_IMPLEMENTED][] | Not Started | Security | [SEC_NON_RESET_FLOPS][] | Not Started | Security | [SEC_SHADOW_REGS][] | Not Started | -Review | Reviewer(s) | Not Started | -Review | Signoff date | Not Started | - -[NEW_FEATURES]: {{}} -[BLOCK_DIAGRAM]: {{}} -[DOC_INTERFACE]: {{}} -[MISSING_FUNC]: {{}} -[FEATURE_FROZEN]: {{}} -[FEATURE_COMPLETE]: {{}} -[AREA_SANITY_CHECK]: {{}} -[PORT_FROZEN]: {{}} -[ARCHITECTURE_FROZEN]: {{}} -[REVIEW_TODO]: {{}} -[STYLE_X]: {{}} -[LINT_PASS]: {{}} -[CDC_SETUP]: {{}} -[FPGA_TIMING]: {{}} -[CDC_SYNCMACRO]: {{}} -[SEC_CM_IMPLEMENTED]: {{}} -[SEC_NON_RESET_FLOPS]: {{}} -[SEC_SHADOW_REGS]: {{}} - -### D3 +Security | [SEC_RND_CNST][] | Not Started | + +[NEW_FEATURES]: {{}} +[BLOCK_DIAGRAM]: {{}} +[DOC_INTERFACE]: {{}} +[MISSING_FUNC]: {{}} +[FEATURE_FROZEN]: {{}} +[FEATURE_COMPLETE]: {{}} +[AREA_CHECK]: {{}} +[PORT_FROZEN]: {{}} +[ARCHITECTURE_FROZEN]: {{}} +[REVIEW_TODO]: {{}} +[STYLE_X]: {{}} +[LINT_PASS]: {{}} +[CDC_SETUP]: {{}} +[FPGA_TIMING]: {{}} +[CDC_SYNCMACRO]: {{}} +[SEC_CM_IMPLEMENTED]: {{}} +[SEC_NON_RESET_FLOPS]: {{}} +[SEC_SHADOW_REGS]: {{}} +[SEC_RND_CNST]: {{}} + +<%text>### D3 Type | Item | Resolution | Note/Collaterals --------------|-------------------------|-------------|------------------ @@ -99,21 +97,21 @@ Review | [REVIEW_SW_ERRATA][] | Not Started | Review | Reviewer(s) | Not Started | Review | Signoff date | Not Started | -[NEW_FEATURES_D3]: {{}} -[TODO_COMPLETE]: {{}} -[LINT_COMPLETE]: {{}} -[CDC_COMPLETE]: {{}} -[REVIEW_RTL]: {{}} -[REVIEW_DBG]: {{}} -[REVIEW_DELETED_FF]: {{}} -[REVIEW_SW_CSR]: {{}} -[REVIEW_SW_FATAL_ERR]: {{}} -[REVIEW_SW_CHANGE]: {{}} -[REVIEW_SW_ERRATA]: {{}} +[NEW_FEATURES_D3]: {{}} +[TODO_COMPLETE]: {{}} +[LINT_COMPLETE]: {{}} +[CDC_COMPLETE]: {{}} +[REVIEW_RTL]: {{}} +[REVIEW_DBG]: {{}} +[REVIEW_DELETED_FF]: {{}} +[REVIEW_SW_CSR]: {{}} +[REVIEW_SW_FATAL_ERR]: {{}} +[REVIEW_SW_CHANGE]: {{}} +[REVIEW_SW_ERRATA]: {{}} -## Verification Checklist +<%text>## Verification Checklist -### V1 +<%text>### V1 Type | Item | Resolution | Note/Collaterals --------------|---------------------------------------|-------------|------------------ @@ -125,116 +123,118 @@ Testbench | [SIM_TB_ENV_CREATED][] | Not Started | Testbench | [SIM_RAL_MODEL_GEN_AUTOMATED][] | Not Started | Testbench | [CSR_CHECK_GEN_AUTOMATED][] | Not Started | Testbench | [TB_GEN_AUTOMATED][] | Not Started | -Tests | [SIM_SANITY_TEST_PASSING][] | Not Started | +Tests | [SIM_SMOKE_TEST_PASSING][] | Not Started | Tests | [SIM_CSR_MEM_TEST_SUITE_PASSING][] | Not Started | Tests | [FPV_MAIN_ASSERTIONS_PROVEN][] | Not Started | Tool Setup | [SIM_ALT_TOOL_SETUP][] | Not Started | -Regression | [SIM_SANITY_REGRESSION_SETUP][] | Not Started | +Regression | [SIM_SMOKE_REGRESSION_SETUP][] | Not Started | Regression | [SIM_NIGHTLY_REGRESSION_SETUP][] | Not Started | Regression | [FPV_REGRESSION_SETUP][] | Not Started | Coverage | [SIM_COVERAGE_MODEL_ADDED][] | Not Started | +Code Quality | [TB_LINT_SETUP][] | Not Started | Integration | [PRE_VERIFIED_SUB_MODULES_V1][] | Not Started | Review | [DESIGN_SPEC_REVIEWED][] | Not Started | Review | [DV_PLAN_TESTPLAN_REVIEWED][] | Not Started | Review | [STD_TEST_CATEGORIES_PLANNED][] | Not Started | Exception (?) Review | [V2_CHECKLIST_SCOPED][] | Not Started | -Review | Reviewer(s) | Not Started | -Review | Signoff date | Not Started | - -[DV_PLAN_DRAFT_COMPLETED]: {{}} -[TESTPLAN_COMPLETED]: {{}} -[TB_TOP_CREATED]: {{}} -[PRELIMINARY_ASSERTION_CHECKS_ADDED]: {{}} -[SIM_TB_ENV_CREATED]: {{}} -[SIM_RAL_MODEL_GEN_AUTOMATED]: {{}} -[CSR_CHECK_GEN_AUTOMATED]: {{}} -[TB_GEN_AUTOMATED]: {{}} -[SIM_SANITY_TEST_PASSING]: {{}} -[SIM_CSR_MEM_TEST_SUITE_PASSING]: {{}} -[FPV_MAIN_ASSERTIONS_PROVEN]: {{}} -[SIM_ALT_TOOL_SETUP]: {{}} -[SIM_SANITY_REGRESSION_SETUP]: {{}} -[SIM_NIGHTLY_REGRESSION_SETUP]: {{}} -[FPV_REGRESSION_SETUP]: {{}} -[SIM_COVERAGE_MODEL_ADDED]: {{}} -[PRE_VERIFIED_SUB_MODULES_V1]: {{}} -[DESIGN_SPEC_REVIEWED]: {{}} -[DV_PLAN_TESTPLAN_REVIEWED]: {{}} -[STD_TEST_CATEGORIES_PLANNED]: {{}} -[V2_CHECKLIST_SCOPED]: {{}} - -### V2 + +[DV_PLAN_DRAFT_COMPLETED]: {{}} +[TESTPLAN_COMPLETED]: {{}} +[TB_TOP_CREATED]: {{}} +[PRELIMINARY_ASSERTION_CHECKS_ADDED]: {{}} +[SIM_TB_ENV_CREATED]: {{}} +[SIM_RAL_MODEL_GEN_AUTOMATED]: {{}} +[CSR_CHECK_GEN_AUTOMATED]: {{}} +[TB_GEN_AUTOMATED]: {{}} +[SIM_SMOKE_TEST_PASSING]: {{}} +[SIM_CSR_MEM_TEST_SUITE_PASSING]: {{}} +[FPV_MAIN_ASSERTIONS_PROVEN]: {{}} +[SIM_ALT_TOOL_SETUP]: {{}} +[SIM_SMOKE_REGRESSION_SETUP]: {{}} +[SIM_NIGHTLY_REGRESSION_SETUP]: {{}} +[FPV_REGRESSION_SETUP]: {{}} +[SIM_COVERAGE_MODEL_ADDED]: {{}} +[TB_LINT_SETUP]: {{}} +[PRE_VERIFIED_SUB_MODULES_V1]: {{}} +[DESIGN_SPEC_REVIEWED]: {{}} +[DV_PLAN_TESTPLAN_REVIEWED]: {{}} +[STD_TEST_CATEGORIES_PLANNED]: {{}} +[V2_CHECKLIST_SCOPED]: {{}} + +<%text>### V2 Type | Item | Resolution | Note/Collaterals --------------|-----------------------------------------|-------------|------------------ -Documentation | [DESIGN_DELTAS_CAPTURED_V2][] | Not started | -Documentation | [DV_PLAN_COMPLETED][] | Not started | -Testbench | [ALL_INTERFACES_EXERCISED][] | Not started | -Testbench | [ALL_ASSERTION_CHECKS_ADDED][] | Not started | -Testbench | [SIM_TB_ENV_COMPLETED][] | Not started | -Tests | [SIM_ALL_TESTS_PASSING][] | Not started | -Tests | [FPV_ALL_ASSERTIONS_WRITTEN][] | Not started | -Tests | [FPV_ALL_ASSUMPTIONS_REVIEWED][] | Not started | -Tests | [SIM_FW_SIMULATED][] | Not started | -Regression | [SIM_NIGHTLY_REGRESSION_V2][] | Not started | -Coverage | [SIM_CODE_COVERAGE_V2][] | Not started | -Coverage | [SIM_FUNCTIONAL_COVERAGE_V2][] | Not started | -Coverage | [FPV_CODE_COVERAGE_V2][] | Not started | -Coverage | [FPV_COI_COVERAGE_V2][] | Not started | -Issues | [NO_HIGH_PRIORITY_ISSUES_PENDING][] | Not started | -Issues | [ALL_LOW_PRIORITY_ISSUES_ROOT_CAUSED][] | Not started | -Integration | [PRE_VERIFIED_SUB_MODULES_V2][] | Not started | -Review | [V3_CHECKLIST_SCOPED][] | Not started | -Review | Reviewer(s) | Not started | -Review | Signoff date | Not started | - -[DESIGN_DELTAS_CAPTURED_V2]: {{}} -[DV_PLAN_COMPLETED]: {{}} -[ALL_INTERFACES_EXERCISED]: {{}} -[ALL_ASSERTION_CHECKS_ADDED]: {{}} -[SIM_TB_ENV_COMPLETED]: {{}} -[SIM_ALL_TESTS_PASSING]: {{}} -[FPV_ALL_ASSERTIONS_WRITTEN]: {{}} -[FPV_ALL_ASSUMPTIONS_REVIEWED]: {{}} -[SIM_FW_SIMULATED]: {{}} -[SIM_NIGHTLY_REGRESSION_V2]: {{}} -[SIM_CODE_COVERAGE_V2]: {{}} -[SIM_FUNCTIONAL_COVERAGE_V2]: {{}} -[FPV_CODE_COVERAGE_V2]: {{}} -[FPV_COI_COVERAGE_V2]: {{}} -[NO_HIGH_PRIORITY_ISSUES_PENDING]: {{}} -[ALL_LOW_PRIORITY_ISSUES_ROOT_CAUSED]:{{}} -[PRE_VERIFIED_SUB_MODULES_V2]: {{}} -[V3_CHECKLIST_SCOPED]: {{}} - -### V3 +Documentation | [DESIGN_DELTAS_CAPTURED_V2][] | Not Started | +Documentation | [DV_PLAN_COMPLETED][] | Not Started | +Testbench | [ALL_INTERFACES_EXERCISED][] | Not Started | +Testbench | [ALL_ASSERTION_CHECKS_ADDED][] | Not Started | +Testbench | [SIM_TB_ENV_COMPLETED][] | Not Started | +Tests | [SIM_ALL_TESTS_PASSING][] | Not Started | +Tests | [FPV_ALL_ASSERTIONS_WRITTEN][] | Not Started | +Tests | [FPV_ALL_ASSUMPTIONS_REVIEWED][] | Not Started | +Tests | [SIM_FW_SIMULATED][] | Not Started | +Regression | [SIM_NIGHTLY_REGRESSION_V2][] | Not Started | +Coverage | [SIM_CODE_COVERAGE_V2][] | Not Started | +Coverage | [SIM_FUNCTIONAL_COVERAGE_V2][] | Not Started | +Coverage | [FPV_CODE_COVERAGE_V2][] | Not Started | +Coverage | [FPV_COI_COVERAGE_V2][] | Not Started | +Code Quality | [TB_LINT_PASS][] | Not Started | +Issues | [NO_HIGH_PRIORITY_ISSUES_PENDING][] | Not Started | +Issues | [ALL_LOW_PRIORITY_ISSUES_ROOT_CAUSED][] | Not Started | +Integration | [PRE_VERIFIED_SUB_MODULES_V2][] | Not Started | +Review | [V3_CHECKLIST_SCOPED][] | Not Started | + +[DESIGN_DELTAS_CAPTURED_V2]: {{}} +[DV_PLAN_COMPLETED]: {{}} +[ALL_INTERFACES_EXERCISED]: {{}} +[ALL_ASSERTION_CHECKS_ADDED]: {{}} +[SIM_TB_ENV_COMPLETED]: {{}} +[SIM_ALL_TESTS_PASSING]: {{}} +[FPV_ALL_ASSERTIONS_WRITTEN]: {{}} +[FPV_ALL_ASSUMPTIONS_REVIEWED]: {{}} +[SIM_FW_SIMULATED]: {{}} +[SIM_NIGHTLY_REGRESSION_V2]: {{}} +[SIM_CODE_COVERAGE_V2]: {{}} +[SIM_FUNCTIONAL_COVERAGE_V2]: {{}} +[FPV_CODE_COVERAGE_V2]: {{}} +[FPV_COI_COVERAGE_V2]: {{}} +[TB_LINT_PASS]: {{}} +[NO_HIGH_PRIORITY_ISSUES_PENDING]: {{}} +[ALL_LOW_PRIORITY_ISSUES_ROOT_CAUSED]:{{}} +[PRE_VERIFIED_SUB_MODULES_V2]: {{}} +[V3_CHECKLIST_SCOPED]: {{}} + +<%text>### V3 Type | Item | Resolution | Note/Collaterals --------------|-----------------------------------|-------------|------------------ -Documentation | [DESIGN_DELTAS_CAPTURED_V3][] | Not started | -Testbench | [ALL_TODOS_RESOLVED][] | Not started | -Tests | [X_PROP_ANALYSIS_COMPLETED][] | Not started | -Tests | [FPV_ASSERTIONS_PROVEN_AT_V3][] | Not started | -Regression | [SIM_NIGHTLY_REGRESSION_AT_V3][] | Not started | -Coverage | [SIM_CODE_COVERAGE_AT_100][] | Not started | -Coverage | [SIM_FUNCTIONAL_COVERAGE_AT_100][]| Not started | -Coverage | [FPV_CODE_COVERAGE_AT_100][] | Not started | -Coverage | [FPV_COI_COVERAGE_AT_100][] | Not started | -Issues | [NO_ISSUES_PENDING][] | Not started | -Code Quality | [NO_TOOL_WARNINGS_THROWN][] | Not started | -Integration | [PRE_VERIFIED_SUB_MODULES_V3][] | Not started | -Review | Reviewer(s) | Not started | -Review | Signoff date | Not started | - -[DESIGN_DELTAS_CAPTURED_V3]: {{}} -[ALL_TODOS_RESOLVED]: {{}} -[X_PROP_ANALYSIS_COMPLETED]: {{}} -[FPV_ASSERTIONS_PROVEN_AT_V3]: {{}} -[SIM_NIGHTLY_REGRESSION_AT_V3]: {{}} -[SIM_CODE_COVERAGE_AT_100]: {{}} -[SIM_FUNCTIONAL_COVERAGE_AT_100]:{{}} -[FPV_CODE_COVERAGE_AT_100]: {{}} -[FPV_COI_COVERAGE_AT_100]: {{}} -[NO_ISSUES_PENDING]: {{}} -[NO_TOOL_WARNINGS_THROWN]: {{}} -[PRE_VERIFIED_SUB_MODULES_V3]: {{}} +Documentation | [DESIGN_DELTAS_CAPTURED_V3][] | Not Started | +Testbench | [ALL_TODOS_RESOLVED][] | Not Started | +Tests | [X_PROP_ANALYSIS_COMPLETED][] | Not Started | +Tests | [FPV_ASSERTIONS_PROVEN_AT_V3][] | Not Started | +Regression | [SIM_NIGHTLY_REGRESSION_AT_V3][] | Not Started | +Coverage | [SIM_CODE_COVERAGE_AT_100][] | Not Started | +Coverage | [SIM_FUNCTIONAL_COVERAGE_AT_100][]| Not Started | +Coverage | [FPV_CODE_COVERAGE_AT_100][] | Not Started | +Coverage | [FPV_COI_COVERAGE_AT_100][] | Not Started | +Issues | [NO_ISSUES_PENDING][] | Not Started | +Code Quality | [NO_TOOL_WARNINGS_THROWN][] | Not Started | +Code Quality | [TB_LINT_COMPLETE][] | Not Started | +Integration | [PRE_VERIFIED_SUB_MODULES_V3][] | Not Started | +Review | Reviewer(s) | Not Started | +Review | Signoff date | Not Started | + +[DESIGN_DELTAS_CAPTURED_V3]: {{}} +[ALL_TODOS_RESOLVED]: {{}} +[X_PROP_ANALYSIS_COMPLETED]: {{}} +[FPV_ASSERTIONS_PROVEN_AT_V3]: {{}} +[SIM_NIGHTLY_REGRESSION_AT_V3]: {{}} +[SIM_CODE_COVERAGE_AT_100]: {{}} +[SIM_FUNCTIONAL_COVERAGE_AT_100]:{{}} +[FPV_CODE_COVERAGE_AT_100]: {{}} +[FPV_COI_COVERAGE_AT_100]: {{}} +[NO_ISSUES_PENDING]: {{}} +[NO_TOOL_WARNINGS_THROWN]: {{}} +[TB_LINT_COMPLETE]: {{}} +[PRE_VERIFIED_SUB_MODULES_V3]: {{}} diff --git a/vendor/lowrisc_ip/util/uvmdvgen/driver.sv.tpl b/vendor/lowrisc_ip/util/uvmdvgen/driver.sv.tpl index 074280cf65..35ac143511 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/driver.sv.tpl +++ b/vendor/lowrisc_ip/util/uvmdvgen/driver.sv.tpl @@ -2,7 +2,8 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -class ${name}_driver extends dv_base_driver #(${name}_item, ${name}_agent_cfg); +class ${name}_driver extends dv_base_driver #(.ITEM_T(${name}_item), + .CFG_T (${name}_agent_cfg)); `uvm_component_utils(${name}_driver) // the base class provides the following handles for use: diff --git a/vendor/lowrisc_ip/util/uvmdvgen/env.core.tpl b/vendor/lowrisc_ip/util/uvmdvgen/env.core.tpl index cb8ff7ebfd..97f65ee548 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/env.core.tpl +++ b/vendor/lowrisc_ip/util/uvmdvgen/env.core.tpl @@ -28,7 +28,7 @@ filesets: - seq_lib/${name}_vseq_list.sv: {is_include_file: true} - seq_lib/${name}_base_vseq.sv: {is_include_file: true} - seq_lib/${name}_common_vseq.sv: {is_include_file: true} - - seq_lib/${name}_sanity_vseq.sv: {is_include_file: true} + - seq_lib/${name}_smoke_vseq.sv: {is_include_file: true} file_type: systemVerilogSource % if has_ral: diff --git a/vendor/lowrisc_ip/util/uvmdvgen/env_cfg.sv.tpl b/vendor/lowrisc_ip/util/uvmdvgen/env_cfg.sv.tpl index 71cbb7420b..6fce2bbada 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/env_cfg.sv.tpl +++ b/vendor/lowrisc_ip/util/uvmdvgen/env_cfg.sv.tpl @@ -23,13 +23,10 @@ class ${name}_env_cfg extends dv_base_env_cfg; `uvm_object_new -% if has_ral: - virtual function void initialize_csr_addr_map_size(); - this.csr_addr_map_size = ${name.upper()}_ADDR_MAP_SIZE; - endfunction : initialize_csr_addr_map_size -% endif - virtual function void initialize(bit [31:0] csr_base_addr = '1); +% if has_alerts: + list_of_alerts = ${name}_env_pkg::LIST_OF_ALERTS; +% endif % if has_ral: super.initialize(csr_base_addr); % endif diff --git a/vendor/lowrisc_ip/util/uvmdvgen/env_pkg.sv.tpl b/vendor/lowrisc_ip/util/uvmdvgen/env_pkg.sv.tpl index abe79b4cb8..d03af31cae 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/env_pkg.sv.tpl +++ b/vendor/lowrisc_ip/util/uvmdvgen/env_pkg.sv.tpl @@ -25,9 +25,10 @@ package ${name}_env_pkg; `include "dv_macros.svh" // parameters -% if has_ral: - // TODO update below, or compile error occurs - parameter uint ${name.upper()}_ADDR_MAP_SIZE = ; +% if has_alerts: + // TODO: add the names of alerts in order + parameter string LIST_OF_ALERTS[] = {}; + parameter uint NUM_ALERTS = ; % endif // types diff --git a/vendor/lowrisc_ip/util/uvmdvgen/gen_env.py b/vendor/lowrisc_ip/util/uvmdvgen/gen_env.py index fe60f5a93b..0fcbc65815 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/gen_env.py +++ b/vendor/lowrisc_ip/util/uvmdvgen/gen_env.py @@ -5,6 +5,7 @@ """ import os +import logging as log from mako.template import Template from pkg_resources import resource_filename @@ -12,7 +13,7 @@ def gen_env(name, is_cip, has_ral, has_interrupts, has_alerts, env_agents, - root_dir, add_makefile, vendor): + root_dir, vendor): # yapf: disable # 4-tuple - sub-path, ip name, class name, file ext env_srcs = [('dv/env', name + '_', 'env_cfg', '.sv'), @@ -23,17 +24,16 @@ def gen_env(name, is_cip, has_ral, has_interrupts, has_alerts, env_agents, ('dv/env', name + '_', 'env', '.sv'), ('dv/env', name + '_', 'env', '.core'), ('dv/env/seq_lib', name + '_', 'base_vseq', '.sv'), - ('dv/env/seq_lib', name + '_', 'sanity_vseq', '.sv'), + ('dv/env/seq_lib', name + '_', 'smoke_vseq', '.sv'), ('dv/env/seq_lib', name + '_', 'common_vseq', '.sv'), ('dv/env/seq_lib', name + '_', 'vseq_list', '.sv'), ('dv', '', 'tb', '.sv'), ('dv/sva', name + '_', 'bind', '.sv'), - ('dv/sva', name + '_', 'sva', '.core'), + ('dv/sva', name + '_', 'sva', '.core'), ('dv/tests', name + '_', 'base_test', '.sv'), ('dv/tests', name + '_', 'test_pkg', '.sv'), ('dv/tests', name + '_', 'test', '.core'), ('dv/cov', '', '', ''), - ('dv', '', 'Makefile', ''), ('dv', name + '_', 'sim_cfg', '.hjson'), ('doc/dv_plan', '', 'index', '.md'), ('doc', '', 'checklist', '.md'), @@ -54,18 +54,18 @@ def gen_env(name, is_cip, has_ral, has_interrupts, has_alerts, env_agents, src = tup[2] src_suffix = tup[3] - # Skip Makefile - if src == 'Makefile' and not add_makefile: continue - ftpl = src + src_suffix + '.tpl' file_name = src_prefix + src + src_suffix - if not os.path.exists(path_dir): os.system("mkdir -p " + path_dir) - if file_name == "": continue + if not os.path.exists(path_dir): + os.system("mkdir -p " + path_dir) + if file_name == "": + continue # Skip the checklist if it already exists. file_path = os.path.join(path_dir, file_name) - if src == 'checklist' and os.path.exists(file_path): continue + if src == 'checklist' and os.path.exists(file_path): + continue # read template tpl = Template(filename=resource_filename('uvmdvgen', ftpl)) @@ -81,5 +81,5 @@ def gen_env(name, is_cip, has_ral, has_interrupts, has_alerts, env_agents, has_alerts=has_alerts, env_agents=env_agents, vendor=vendor)) - except: - log.error(exceptions.text_error_template().render()) + except Exception as e: + log.error(e.text_error_template().render()) diff --git a/vendor/lowrisc_ip/util/uvmdvgen/index.md.tpl b/vendor/lowrisc_ip/util/uvmdvgen/index.md.tpl index 4880d04072..3ccb35dc6f 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/index.md.tpl +++ b/vendor/lowrisc_ip/util/uvmdvgen/index.md.tpl @@ -78,7 +78,7 @@ ${'###'} UVC/agent 2 ${'###'} UVM RAL Model The ${name.upper()} RAL model is created with the [`ralgen`]({{< relref "hw/dv/tools/ralgen/README.md" >}}) FuseSoC generator script automatically when the simulation is at the build stage. -It can be created manually (separately) by running `make` in the the `hw/` area. +It can be created manually by invoking [`regtool`]({{< relref "util/reggen/README.md" >}}): % endif ${'###'} Reference models @@ -117,10 +117,9 @@ ${'####'} Assertions ${'##'} Building and running tests We are using our in-house developed [regression tool]({{< relref "hw/dv/tools/README.md" >}}) for building and running our tests and regressions. Please take a look at the link for detailed information on the usage, capabilities, features and known issues. -Here's how to run a basic sanity test: +Here's how to run a smoke test: ```console -$ cd hw/ip/${name}/dv -$ make TEST_NAME=${name}_sanity +$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/ip/${name}/dv/${name}_sim_cfg.hjson -i ${name}_smoke ``` ${'##'} Testplan diff --git a/vendor/lowrisc_ip/util/uvmdvgen/scoreboard.sv.tpl b/vendor/lowrisc_ip/util/uvmdvgen/scoreboard.sv.tpl index ac117c79ba..f3cdf5cdcb 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/scoreboard.sv.tpl +++ b/vendor/lowrisc_ip/util/uvmdvgen/scoreboard.sv.tpl @@ -64,7 +64,7 @@ class ${name}_scoreboard extends dv_base_scoreboard #( uvm_reg csr; bit do_read_check = 1'b1; bit write = item.is_write(); - uvm_reg_addr_t csr_addr = get_normalized_addr(item.a_addr); + uvm_reg_addr_t csr_addr = ral.get_word_aligned_addr(item.a_addr); bit addr_phase_read = (!write && channel == AddrChannel); bit addr_phase_write = (write && channel == AddrChannel); diff --git a/vendor/lowrisc_ip/util/uvmdvgen/sim.core.tpl b/vendor/lowrisc_ip/util/uvmdvgen/sim.core.tpl index 76c29c8c58..c65dc35ec3 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/sim.core.tpl +++ b/vendor/lowrisc_ip/util/uvmdvgen/sim.core.tpl @@ -18,9 +18,13 @@ filesets: file_type: systemVerilogSource targets: - sim: + sim: &sim_target toplevel: tb filesets: - files_rtl - files_dv default_tool: vcs + + # TODO: add a lint check cfg in `hw/top_earlgrey/lint/top_earlgrey_dv_lint_cfgs.hjson` + lint: + <<: *sim_target diff --git a/vendor/lowrisc_ip/util/uvmdvgen/sim_cfg.hjson.tpl b/vendor/lowrisc_ip/util/uvmdvgen/sim_cfg.hjson.tpl index 3d25b64bb4..61727c989a 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/sim_cfg.hjson.tpl +++ b/vendor/lowrisc_ip/util/uvmdvgen/sim_cfg.hjson.tpl @@ -29,28 +29,28 @@ // TODO: remove imported cfgs that do not apply. % if is_cip: import_cfgs: [// Project wide common sim cfg file - "{proj_root}/hw/dv/data/common_sim_cfg.hjson", + "{proj_root}/hw/dv/tools/dvsim/common_sim_cfg.hjson", // Common CIP test lists % if has_ral: - "{proj_root}/hw/dv/data/tests/csr_tests.hjson", + "{proj_root}/hw/dv/tools/dvsim/tests/csr_tests.hjson", % endif - "{proj_root}/hw/dv/data/tests/mem_tests.hjson", + "{proj_root}/hw/dv/tools/dvsim/tests/mem_tests.hjson", % if has_interrupts: - "{proj_root}/hw/dv/data/tests/intr_test.hjson", + "{proj_root}/hw/dv/tools/dvsim/tests/intr_test.hjson", % endif - "{proj_root}/hw/dv/data/tests/tl_access_tests.hjson", - "{proj_root}/hw/dv/data/tests/stress_tests.hjson"] + "{proj_root}/hw/dv/tools/dvsim/tests/tl_access_tests.hjson", + "{proj_root}/hw/dv/tools/dvsim/tests/stress_tests.hjson"] % else: import_cfgs: [// Project wide common sim cfg file - "{proj_root}/hw/dv/data/common_sim_cfg.hjson", + "{proj_root}/hw/dv/tools/dvsim/common_sim_cfg.hjson", % if has_ral: - "{proj_root}/hw/dv/data/tests/csr_tests.hjson", - "{proj_root}/hw/dv/data/tests/mem_tests.hjson"] + "{proj_root}/hw/dv/tools/dvsim/tests/csr_tests.hjson", + "{proj_root}/hw/dv/tools/dvsim/tests/mem_tests.hjson"] % endif % endif // Add additional tops for simulation. - sim_tops: ["-top {name}_bind"] + sim_tops: ["-top ${name}_bind"] // Default iterations for all tests - each test entry can override this. reseed: 50 @@ -62,8 +62,8 @@ // List of test specifications. tests: [ { - name: ${name}_sanity - uvm_test_seq: ${name}_sanity_vseq + name: ${name}_smoke + uvm_test_seq: ${name}_smoke_vseq } // TODO: add more tests here @@ -72,8 +72,8 @@ // List of regressions. regressions: [ { - name: sanity - tests: ["${name}_sanity"] + name: smoke + tests: ["${name}_smoke"] } ] } diff --git a/vendor/lowrisc_ip/util/uvmdvgen/sanity_vseq.sv.tpl b/vendor/lowrisc_ip/util/uvmdvgen/smoke_vseq.sv.tpl similarity index 60% rename from vendor/lowrisc_ip/util/uvmdvgen/sanity_vseq.sv.tpl rename to vendor/lowrisc_ip/util/uvmdvgen/smoke_vseq.sv.tpl index 7fbc61b04c..aaf859c26a 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/sanity_vseq.sv.tpl +++ b/vendor/lowrisc_ip/util/uvmdvgen/smoke_vseq.sv.tpl @@ -2,9 +2,9 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -// basic sanity test vseq -class ${name}_sanity_vseq extends ${name}_base_vseq; - `uvm_object_utils(${name}_sanity_vseq) +// smoke test vseq +class ${name}_smoke_vseq extends ${name}_base_vseq; + `uvm_object_utils(${name}_smoke_vseq) `uvm_object_new @@ -12,4 +12,4 @@ class ${name}_sanity_vseq extends ${name}_base_vseq; `uvm_error(`gfn, "FIXME") endtask : body -endclass : ${name}_sanity_vseq +endclass : ${name}_smoke_vseq diff --git a/vendor/lowrisc_ip/util/uvmdvgen/sva.core.tpl b/vendor/lowrisc_ip/util/uvmdvgen/sva.core.tpl index 89863d7f9f..3324369f99 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/sva.core.tpl +++ b/vendor/lowrisc_ip/util/uvmdvgen/sva.core.tpl @@ -15,6 +15,10 @@ filesets: - ${name}_bind.sv file_type: systemVerilogSource + files_formal: + depend: + - lowrisc:ip:${name} + % if has_ral: generate: csr_assert_gen: @@ -25,10 +29,16 @@ generate: % endif targets: - default: + default: &default_target filesets: - files_dv % if has_ral: generate: - csr_assert_gen + formal: + <<: *default_target + filesets: + - files_formal + - files_dv + toplevel: ${name} % endif diff --git a/vendor/lowrisc_ip/util/uvmdvgen/tb.sv.tpl b/vendor/lowrisc_ip/util/uvmdvgen/tb.sv.tpl index ea20a8a4b8..ac81d8c432 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/tb.sv.tpl +++ b/vendor/lowrisc_ip/util/uvmdvgen/tb.sv.tpl @@ -19,10 +19,6 @@ module tb; % if has_interrupts: wire [NUM_MAX_INTERRUPTS-1:0] interrupts; % endif -% if has_alerts: - // TODO: change alert_names - list_of_alerts = {"alert_names"}; -% endif % endif // interfaces @@ -30,10 +26,6 @@ module tb; % if is_cip: % if has_interrupts: pins_if #(NUM_MAX_INTERRUPTS) intr_if(interrupts); -% endif -% if has_alerts: - // TODO: declare alert interfaces according to the list_of_alerts - alert_if alert_names(.clk(clk), .rst_n(rst_n)) % endif pins_if #(1) devmode_if(devmode); tl_if tl_if(.clk(clk), .rst_n(rst_n)); @@ -42,22 +34,26 @@ module tb; ${agent}_if ${agent}_if(); % endfor +% if has_alerts: + `DV_ALERT_IF_CONNECT +% endif + // dut ${name} dut ( - .clk_i (clk ), + .clk_i (clk ), % if is_cip: - .rst_ni (rst_n ), + .rst_ni (rst_n ), - .tl_i (tl_if.h2d ), + .tl_i (tl_if.h2d), % if has_alerts: - .tl_o (tl_if.d2h ), - .alert_rx_i (alert_names.alert_rx ), - .alert_tx_o (alert_names.alert_tx ) + .tl_o (tl_if.d2h), + .alert_rx_i (alert_rx ), + .alert_tx_o (alert_tx ) % else: - .tl_o (tl_if.d2h ) + .tl_o (tl_if.d2h) % endif % else: - .rst_ni (rst_n ) + .rst_ni (rst_n ) % endif // TODO: add remaining IOs and hook them @@ -70,11 +66,6 @@ module tb; % if is_cip: % if has_interrupts: uvm_config_db#(intr_vif)::set(null, "*.env", "intr_vif", intr_if); -% endif -% if has_alerts: - // TODO: set alert interfaces with the correct names - uvm_config_db#(virtual alert_if)::set(null, "*.env.m_alert_agent_alert_names", - "vif", alert_names); % endif uvm_config_db#(devmode_vif)::set(null, "*.env", "devmode_vif", devmode_if); uvm_config_db#(virtual tl_if)::set(null, "*.env.m_tl_agent*", "vif", tl_if); diff --git a/vendor/lowrisc_ip/util/uvmdvgen/testplan.hjson.tpl b/vendor/lowrisc_ip/util/uvmdvgen/testplan.hjson.tpl index 4723280eb3..d8fff33b40 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/testplan.hjson.tpl +++ b/vendor/lowrisc_ip/util/uvmdvgen/testplan.hjson.tpl @@ -4,15 +4,15 @@ { name: "${name}" // TODO: remove the common testplans if not applicable - import_testplans: ["hw/dv/tools/testplans/csr_testplan.hjson", - "hw/dv/tools/testplans/mem_testplan.hjson", - "hw/dv/tools/testplans/intr_test_testplan.hjson", - "hw/dv/tools/testplans/tl_device_access_types_testplan.hjson"] + import_testplans: ["hw/dv/tools/dvsim/testplans/csr_testplan.hjson", + "hw/dv/tools/dvsim/testplans/mem_testplan.hjson", + "hw/dv/tools/dvsim/testplans/intr_test_testplan.hjson", + "hw/dv/tools/dvsim/testplans/tl_device_access_types_testplan.hjson"] entries: [ { - name: sanity + name: smoke desc: ''' - Basic sanity test acessing a major datapath within the ${name}. + Smoke test accessing a major datapath within the ${name}. **Stimulus**: - TBD @@ -21,7 +21,7 @@ - TBD ''' milestone: V1 - tests: ["${name}_sanity"] + tests: ["${name}_smoke"] } { name: feature1 diff --git a/vendor/lowrisc_ip/util/uvmdvgen/uvmdvgen.py b/vendor/lowrisc_ip/util/uvmdvgen/uvmdvgen.py index 8e2b5c4f98..9773581698 100755 --- a/vendor/lowrisc_ip/util/uvmdvgen/uvmdvgen.py +++ b/vendor/lowrisc_ip/util/uvmdvgen/uvmdvgen.py @@ -5,8 +5,6 @@ r"""Command-line tool to autogenerate boilerplate DV testbench code extended from dv_lib / cip_lib """ import argparse -import os -import sys import gen_agent import gen_env @@ -106,17 +104,6 @@ def main(): tb and tests to place all of the testbench sources. (default set to './')""" ) - parser.add_argument( - "-m", - "--add-makefile", - default=False, - action='store_true', - help= - """Tests are now run with dvsim.py tool that requires a hjson based sim cfg. - Setting this option will also result in the Makefile to be auto-generated (which is - the older way of building and running sims going through deprecation).""" - ) - parser.add_argument( "-v", "--vendor", @@ -126,8 +113,10 @@ def main(): of the FuesSoC core files.""") args = parser.parse_args() - if not args.agent_outdir: args.agent_outdir = args.name - if not args.env_outdir: args.env_outdir = args.name + if not args.agent_outdir: + args.agent_outdir = args.name + if not args.env_outdir: + args.env_outdir = args.name # The has_ral option must be set if either is_cip or has_interrupts is set, # as both require use of a RAL model. As such, it is disallowed to not have @@ -142,10 +131,11 @@ def main(): args.agent_outdir, args.vendor) if args.gen_env: - if not args.env_agents: args.env_agents = [] + if not args.env_agents: + args.env_agents = [] gen_env.gen_env(args.name, args.is_cip, args.has_ral, args.has_interrupts, args.has_alerts, args.env_agents, - args.env_outdir, args.add_makefile, args.vendor) + args.env_outdir, args.vendor) if __name__ == '__main__': diff --git a/vendor/lowrisc_ip/util/uvmdvgen/vseq_list.sv.tpl b/vendor/lowrisc_ip/util/uvmdvgen/vseq_list.sv.tpl index 6e306980ad..1c99c1389a 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/vseq_list.sv.tpl +++ b/vendor/lowrisc_ip/util/uvmdvgen/vseq_list.sv.tpl @@ -3,5 +3,5 @@ // SPDX-License-Identifier: Apache-2.0 `include "${name}_base_vseq.sv" -`include "${name}_sanity_vseq.sv" +`include "${name}_smoke_vseq.sv" `include "${name}_common_vseq.sv" diff --git a/vendor/patches/lowrisc_ip/dv_data/0001-common-sim-cfg.patch b/vendor/patches/lowrisc_ip/dv_tools/0001-common-sim-cfg.patch similarity index 64% rename from vendor/patches/lowrisc_ip/dv_data/0001-common-sim-cfg.patch rename to vendor/patches/lowrisc_ip/dv_tools/0001-common-sim-cfg.patch index 9b52c3943c..af7e0e1084 100644 --- a/vendor/patches/lowrisc_ip/dv_data/0001-common-sim-cfg.patch +++ b/vendor/patches/lowrisc_ip/dv_tools/0001-common-sim-cfg.patch @@ -1,27 +1,23 @@ ---- a/common_sim_cfg.hjson -+++ b/common_sim_cfg.hjson -@@ -2,17 +2,13 @@ +--- a/dvsim/common_sim_cfg.hjson ++++ b/dvsim/common_sim_cfg.hjson +@@ -2,13 +2,13 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 { -- project: opentitan -- doc_server: docs.opentitan.org -- results_server: reports.opentitan.org -- // Where to find DV code - dv_root: "{proj_root}/hw/dv" + dv_root: "{proj_root}/vendor/lowrisc_ip/dv" flow: sim - flow_makefile: "{dv_root}/data/sim.mk" + flow_makefile: "{dv_root}/tools/dvsim/sim.mk" - import_cfgs: ["{proj_root}/hw/data/common_project_cfg.hjson", + import_cfgs: ["{proj_root}/dv/uvm/common_project_cfg.hjson", - "{dv_root}/data/common_modes.hjson", - "{dv_root}/data/fusesoc.hjson", - "{dv_root}/data/{tool}/{tool}.hjson"] ---- a/fusesoc.hjson -+++ b/fusesoc.hjson + "{dv_root}/tools/dvsim/common_modes.hjson", + "{dv_root}/tools/dvsim/fusesoc.hjson", + "{dv_root}/tools/dvsim/{tool}.hjson"] +--- a/dvsim/fusesoc.hjson ++++ b/dvsim/fusesoc.hjson @@ -10,7 +10,7 @@ "--target=sim", "--build-root={build_dir}", diff --git a/vendor/patches/lowrisc_ip/dv_utils/0001-use-ibex-bus-params.patch b/vendor/patches/lowrisc_ip/dv_utils/0001-use-ibex-bus-params.patch index 386ba84562..e327c44dc8 100644 --- a/vendor/patches/lowrisc_ip/dv_utils/0001-use-ibex-bus-params.patch +++ b/vendor/patches/lowrisc_ip/dv_utils/0001-use-ibex-bus-params.patch @@ -2,12 +2,12 @@ diff --git a/dv_utils/dv_utils.core b/dv_utils/dv_utils.core index 0dba0235..801e84f6 100644 --- a/dv_utils.core +++ b/dv_utils.core -@@ -10,7 +10,7 @@ filesets: - depend: +@@ -11,7 +11,7 @@ filesets: + - lowrisc:dv:dv_macros - lowrisc:dv:common_ifs - lowrisc:prim:assert:0.1 - - lowrisc:opentitan:bus_params_pkg + - lowrisc:ibex:bus_params_pkg files: - dv_utils_pkg.sv - - dv_macros.svh: {is_include_file: true} + - dv_report_server.sv: {is_include_file: true}