diff --git a/check_tool_requirements.core b/check_tool_requirements.core index 375970cd8b..89e083a869 100644 --- a/check_tool_requirements.core +++ b/check_tool_requirements.core @@ -7,9 +7,10 @@ description: "Check tool requirements" filesets: files_check_tool_requirements: + file_type: user files: - - ./util/check_tool_requirements.py : { copyto: util/check_tool_requirements.py } - - ./tool_requirements.py : { copyto: tool_requirements.py } + - util/check_tool_requirements.py : { copyto: util/check_tool_requirements.py } + - util/tool_requirements.py : { copyto: util/tool_requirements.py } scripts: check_tool_requirements: diff --git a/dv/cs_registers/tb_cs_registers.core b/dv/cs_registers/tb_cs_registers.core index 226e1afe4f..b1614b6cbc 100644 --- a/dv/cs_registers/tb_cs_registers.core +++ b/dv/cs_registers/tb_cs_registers.core @@ -56,7 +56,7 @@ scripts: cmd: - make - -C - - ../src/lowrisc_ibex_tb_cs_registers_0 + - src/lowrisc_ibex_tb_cs_registers_0 parameters: PMPEnable: @@ -106,13 +106,13 @@ targets: vcs: vcs_options: - '-xlrm uniq_prior_final' - - '../src/lowrisc_ibex_tb_cs_registers_0/build/bin/reg_dpi.so' + - 'src/lowrisc_ibex_tb_cs_registers_0/build/bin/reg_dpi.so' - '-debug_access+all' verilator: mode: cc libs: - - '../src/lowrisc_ibex_tb_cs_registers_0/build/bin/reg_dpi.so' + - 'src/lowrisc_ibex_tb_cs_registers_0/build/bin/reg_dpi.so' verilator_options: # Disabling tracing reduces compile times but doesn't have a # huge influence on runtime performance. diff --git a/dv/formal/build_all.ys b/dv/formal/build_all.ys index 2476fa9792..dfc6a89460 100644 --- a/dv/formal/build_all.ys +++ b/dv/formal/build_all.ys @@ -5,7 +5,7 @@ # Parse and lower the Ibex and specification RTL. LOWRISC_SAIL_SRC is replaced in Makefile. read_slang --top top -DSYNTHESIS -DYOSYS \ - -F build/fusesoc/default-vcs/lowrisc_ibex_ibex_formal_0.1.scr \ + -F build/fusesoc/lowrisc_ibex_ibex_formal_0.1/default-vcs/lowrisc_ibex_ibex_formal_0.1.scr \ build/ibexspec.sv spec/stub.sv spec/spec_api.sv check/peek/alt_lsu.sv check/top.sv \ -I LOWRISC_SAIL_SRC/lib/sv/ --single-unit --no-proc setattr -set keep 1 n:\\* # Keep all named wires. FIXME: Is this still necessary? diff --git a/dv/formal/check/top.sv b/dv/formal/check/top.sv index 1a9796326b..a301af0862 100644 --- a/dv/formal/check/top.sv +++ b/dv/formal/check/top.sv @@ -43,69 +43,73 @@ module top import ibex_pkg::*; #( parameter int unsigned PMPNumRegions = 4 ) ( // Clock and Reset - input logic clk_i, + input logic clk_i, `ifndef YOSYS - input logic rst_ni, + input logic rst_ni, `endif - input logic test_en_i, // enable all clock gates for testing - input prim_ram_1p_pkg::ram_1p_cfg_t ram_cfg_i, + input logic test_en_i, + input prim_ram_1p_pkg::ram_1p_cfg_t ram_cfg_icache_tag_i, + output prim_ram_1p_pkg::ram_1p_cfg_rsp_t [ibex_pkg::IC_NUM_WAYS-1:0] ram_cfg_rsp_icache_tag_o, + input prim_ram_1p_pkg::ram_1p_cfg_t ram_cfg_icache_data_i, + output prim_ram_1p_pkg::ram_1p_cfg_rsp_t [ibex_pkg::IC_NUM_WAYS-1:0] ram_cfg_rsp_icache_data_o, - input logic [31:0] hart_id_i, - input logic [31:0] boot_addr_i, + input logic [31:0] hart_id_i, + input logic [31:0] boot_addr_i, // Instruction memory interface - output logic instr_req_o, - input logic instr_gnt_i, - input logic instr_rvalid_i, - output logic [31:0] instr_addr_o, - input logic [31:0] instr_rdata_i, - input logic [6:0] instr_rdata_intg_i, - input logic instr_err_i, + output logic instr_req_o, + input logic instr_gnt_i, + input logic instr_rvalid_i, + output logic [31:0] instr_addr_o, + input logic [31:0] instr_rdata_i, + input logic [6:0] instr_rdata_intg_i, + input logic instr_err_i, // Data memory interface - output logic data_req_o, - output logic data_is_cap_o, - input logic data_gnt_i, - input logic data_rvalid_i, - output logic data_we_o, - output logic [3:0] data_be_o, - output logic [31:0] data_addr_o, - output logic [31:0] data_wdata_o, - output logic [6:0] data_wdata_intg_o, - input logic [31:0] data_rdata_i, - input logic [6:0] data_rdata_intg_i, - input logic data_err_i, + output logic data_req_o, + output logic data_is_cap_o, + input logic data_gnt_i, + input logic data_rvalid_i, + output logic data_we_o, + output logic [3:0] data_be_o, + output logic [31:0] data_addr_o, + output logic [31:0] data_wdata_o, + output logic [6:0] data_wdata_intg_o, + input logic [31:0] data_rdata_i, + input logic [6:0] data_rdata_intg_i, + input logic data_err_i, // Interrupt inputs - input logic irq_software_i, - input logic irq_timer_i, - input logic irq_external_i, - input logic [14:0] irq_fast_i, - input logic irq_nm_i, // non-maskable interrupt + input logic irq_software_i, + input logic irq_timer_i, + input logic irq_external_i, + input logic [14:0] irq_fast_i, + // non-maskable interrupt + input logic irq_nm_i, // Scrambling Interface - input logic scramble_key_valid_i, - input logic [SCRAMBLE_KEY_W-1:0] scramble_key_i, - input logic [SCRAMBLE_NONCE_W-1:0] scramble_nonce_i, - output logic scramble_req_o, + input logic scramble_key_valid_i, + input logic [SCRAMBLE_KEY_W-1:0] scramble_key_i, + input logic [SCRAMBLE_NONCE_W-1:0] scramble_nonce_i, + output logic scramble_req_o, // Debug Interface - input logic debug_req_i, - output crash_dump_t crash_dump_o, - output logic double_fault_seen_o, + input logic debug_req_i, + output crash_dump_t crash_dump_o, + output logic double_fault_seen_o, // CPU Control Signals - input ibex_mubi_t fetch_enable_i, - output logic core_sleep_o, - output logic alert_minor_o, - output logic alert_major_internal_o, - output logic alert_major_bus_o, + input ibex_mubi_t fetch_enable_i, + output logic core_sleep_o, + output logic alert_minor_o, + output logic alert_major_internal_o, + output logic alert_major_bus_o, // DFT bypass controls - input logic scan_rst_ni + input logic scan_rst_ni ); // Yosys based tools have no inherent understanding of a reset signal (unlike jasper, which has the diff --git a/dv/formal/ibex_formal.core b/dv/formal/ibex_formal.core index b1958ed3b4..387db42cbd 100644 --- a/dv/formal/ibex_formal.core +++ b/dv/formal/ibex_formal.core @@ -10,19 +10,9 @@ filesets: depend: - lowrisc:ibex:ibex_pkg - lowrisc:ibex:ibex_core - - lowrisc:prim:buf - - lowrisc:prim:clock_gating - - lowrisc:prim:secded - - lowrisc:prim:assert - - lowrisc:prim:ram_1p_pkg - - lowrisc:prim_generic:buf - - lowrisc:prim_generic:clock_gating - files: - - ../../rtl/ibex_register_file_ff.sv # generic FF-based - - ../../rtl/ibex_register_file_fpga.sv # FPGA - - ../../rtl/ibex_register_file_latch.sv # ASIC - - ../../rtl/ibex_top.sv - file_type: systemVerilogSource + - lowrisc:ibex:ibex_top + - "fileset_partner ? (partner:prim_generic:all)" + - "!fileset_partner ? (lowrisc:prim_generic:all)" targets: default: diff --git a/dv/formal/pyproject.toml b/dv/formal/pyproject.toml index b0ce02a306..85f6ccfc17 100644 --- a/dv/formal/pyproject.toml +++ b/dv/formal/pyproject.toml @@ -14,8 +14,8 @@ dependencies = [ "hjson == 3.1.0", "mako == 1.1.6", "pyyaml == 6.0.2", - "edalize @ git+https://github.com/lowRISC/edalize.git@v0.4.0", - "fusesoc @ git+https://github.com/lowRISC/fusesoc.git@ot-0.4", + "edalize == 0.6.1", + "fusesoc == 2.4.3", "psutil>=7.0.0", ] diff --git a/dv/formal/uv.lock b/dv/formal/uv.lock index 8399344fe9..345fe7b9fc 100644 --- a/dv/formal/uv.lock +++ b/dv/formal/uv.lock @@ -14,6 +14,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a8/65/be23d8c3ecd68d40541d49812cd94ed0f3ee37eb88669ca15df0e43daed1/anytree-2.8.0-py2.py3-none-any.whl", hash = "sha256:14c55ac77492b11532395049a03b773d14c7e30b22aa012e337b1e983de31521", size = 41717, upload-time = "2020-01-15T01:22:23.471Z" }, ] +[[package]] +name = "argcomplete" +version = "3.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/38/61/0b9ae6399dd4a58d8c1b1dc5a27d6f2808023d0b5dd3104bb99f45a33ff6/argcomplete-3.6.3.tar.gz", hash = "sha256:62e8ed4fd6a45864acc8235409461b72c9a28ee785a2011cc5eb78318786c89c", size = 73754, upload-time = "2025-10-20T03:33:34.741Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/f5/9373290775639cb67a2fce7f629a1c240dce9f12fe927bc32b2736e16dfc/argcomplete-3.6.3-py3-none-any.whl", hash = "sha256:f5007b3a600ccac5d25bbce33089211dfd49eab4a7718da3f10e3082525a92ce", size = 43846, upload-time = "2025-10-20T03:33:33.021Z" }, +] + [[package]] name = "attrs" version = "25.3.0" @@ -23,24 +32,53 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, ] +[[package]] +name = "babel" +version = "2.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, +] + [[package]] name = "edalize" -version = "0.4.0" -source = { git = "https://github.com/lowRISC/edalize.git?rev=v0.4.0#2a70c4421db186b4ec91c770addc89ec83f3818b" } +version = "0.6.1" +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jinja2" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/fc/d6/0a8e42893985ea3477b556068db112586bfe17a0406a1da8d6bc13d1ea5c/edalize-0.6.1.tar.gz", hash = "sha256:6617b6b817d0445a7eaa003f2e7906f910b4ee659f9330ec6faeee633238536b", size = 384538, upload-time = "2025-04-15T04:23:36.678Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/16/47dc8bbbefb395c275c4ba8b2e46a0b54f8c37ba6ca0757478f8139aedc8/edalize-0.6.1-py3-none-any.whl", hash = "sha256:2773339a404310b3b076ac8bcc68cadec8c937eba5a76c0a9b941064cd5ff9d7", size = 170024, upload-time = "2025-04-15T04:23:43.064Z" }, +] + +[[package]] +name = "fastjsonschema" +version = "2.21.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/b5/23b216d9d985a956623b6bd12d4086b60f0059b27799f23016af04a74ea1/fastjsonschema-2.21.2.tar.gz", hash = "sha256:b1eb43748041c880796cd077f1a07c3d94e93ae84bba5ed36800a33554ae05de", size = 374130, upload-time = "2025-08-14T18:49:36.666Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463", size = 24024, upload-time = "2025-08-14T18:49:34.776Z" }, +] [[package]] name = "fusesoc" -version = "0.4" -source = { git = "https://github.com/lowRISC/fusesoc.git?rev=ot-0.4#e20b92898f6d14574cca8d636a841845b0817585" } +version = "2.4.3" +source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "argcomplete" }, { name = "edalize" }, + { name = "fastjsonschema" }, + { name = "jsonschema2md" }, { name = "pyparsing" }, { name = "pyyaml" }, { name = "simplesat" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/b4/c6/32532ef324c628f41628070dfb4b63c4cbb7a28b0ad72c618d79bcaba952/fusesoc-2.4.3.tar.gz", hash = "sha256:fc25b06cb52f516cd00c6d04c9f638205e46f3e35e840fc3f8ec00bb3a6405d5", size = 179652, upload-time = "2025-04-18T20:22:19.493Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/a8/10f62458dda2ca07c49477448e643b10f30825b7741fdb6ec3e6188b6999/fusesoc-2.4.3-py3-none-any.whl", hash = "sha256:9ab4a82a5b7d4decbeb8f76049673a1b0806732ab8f807fee285bbc0452b3dc3", size = 60947, upload-time = "2025-04-18T20:22:17.505Z" }, +] [[package]] name = "hjson" @@ -69,8 +107,8 @@ dependencies = [ [package.metadata] requires-dist = [ { name = "anytree", specifier = "==2.8.0" }, - { name = "edalize", git = "https://github.com/lowRISC/edalize.git?rev=v0.4.0" }, - { name = "fusesoc", git = "https://github.com/lowRISC/fusesoc.git?rev=ot-0.4" }, + { name = "edalize", specifier = "==0.6.1" }, + { name = "fusesoc", specifier = "==2.4.3" }, { name = "hjson", specifier = "==3.1.0" }, { name = "mako", specifier = "==1.1.6" }, { name = "packaging", specifier = "==24.2" }, @@ -90,6 +128,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, ] +[[package]] +name = "jsonschema2md" +version = "1.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "babel" }, + { name = "markdown" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/aa/c3/056bfe8d6360750ed4a13eeafd37d5ace8859b69c9fdb8d6aac82dad7d58/jsonschema2md-1.7.0.tar.gz", hash = "sha256:d69a5b011bf355c005e3c18be4515ae46d2689b38b593ced8d03c5ab66ddbaf3", size = 20017, upload-time = "2025-08-14T11:55:42.67Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/c5/0f9bd3ac958f8136e24e980ecd23e02de929eed9946fc4bf91e057142483/jsonschema2md-1.7.0-cp313-cp313-manylinux_2_39_x86_64.whl", hash = "sha256:06c327866a845827bc08b98cbea70ec96f46c0f8b67cb5a6d9833078a78764d3", size = 22991, upload-time = "2025-08-14T11:55:41.556Z" }, +] + [[package]] name = "mako" version = "1.1.6" @@ -102,6 +154,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b4/4d/e03d08f16ee10e688bde9016bc80af8b78c7f36a8b37c7194da48f72207e/Mako-1.1.6-py2.py3-none-any.whl", hash = "sha256:afaf8e515d075b22fad7d7b8b30e4a1c90624ff2f3733a06ec125f5a5f043a57", size = 75702, upload-time = "2021-11-17T15:40:48.625Z" }, ] +[[package]] +name = "markdown" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/7dd27d9d863b3376fcf23a5a13cb5d024aed1db46f963f1b5735ae43b3be/markdown-3.10.tar.gz", hash = "sha256:37062d4f2aa4b2b6b32aefb80faa300f82cc790cb949a35b8caede34f2b68c0e", size = 364931, upload-time = "2025-11-03T19:51:15.007Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/81/54e3ce63502cd085a0c556652a4e1b919c45a446bd1e5300e10c44c8c521/markdown-3.10-py3-none-any.whl", hash = "sha256:b5b99d6951e2e4948d939255596523444c0e677c669700b1d17aa4a8a464cb7c", size = 107678, upload-time = "2025-11-03T19:51:13.887Z" }, +] + [[package]] name = "markupsafe" version = "3.0.2" diff --git a/dv/formal/verify.tcl b/dv/formal/verify.tcl index 0d8c911e8a..7ea25485d6 100644 --- a/dv/formal/verify.tcl +++ b/dv/formal/verify.tcl @@ -16,7 +16,7 @@ set_prove_cache_mode coi set_prove_per_property_time_limit 10s # Load all Ibex RTL, using the filelist generated by fusesoc -analyze -sv12 +define+SYNTHESIS -f_relative_to_file_location build/fusesoc/default-vcs/lowrisc_ibex_ibex_formal_0.1.scr +analyze -sv12 +define+SYNTHESIS -f_relative_to_file_location build/fusesoc/lowrisc_ibex_ibex_formal_0.1/default-vcs/lowrisc_ibex_ibex_formal_0.1.scr set sail_lib_dir $env(LOWRISC_SAIL_SRC)/lib/sv analyze -sv12 -incdir $sail_lib_dir build/ibexspec.sv diff --git a/dv/riscv_compliance/ibex_riscv_compliance.cc b/dv/riscv_compliance/ibex_riscv_compliance.cc index 8a32b22a96..ce52b685a4 100644 --- a/dv/riscv_compliance/ibex_riscv_compliance.cc +++ b/dv/riscv_compliance/ibex_riscv_compliance.cc @@ -13,9 +13,7 @@ int main(int argc, char **argv) { simctrl.SetTop(&top, &top.IO_CLK, &top.IO_RST_N, VerilatorSimCtrlFlags::ResetPolarityNegative); - MemArea ram( - "TOP.ibex_riscv_compliance.u_ram.u_ram.gen_generic.u_impl_generic", - 64 * 1024 / 4, 4); + MemArea ram("TOP.ibex_riscv_compliance.u_ram.u_ram", 64 * 1024 / 4, 4); memutil.RegisterMemoryArea("ram", 0x0, &ram); simctrl.RegisterExtension(&memutil); diff --git a/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv b/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv index 10d0bb053d..7483d6404c 100644 --- a/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv +++ b/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv @@ -160,57 +160,60 @@ module ibex_riscv_compliance ( .DmHaltAddr (32'h00000000 ), .DmExceptionAddr (32'h00000000 ) ) u_top ( - .clk_i (clk_sys ), - .rst_ni (rst_sys_n ), + .clk_i (clk_sys ), + .rst_ni (rst_sys_n ), - .test_en_i ('b0 ), - .scan_rst_ni (1'b1 ), - .ram_cfg_i ('b0 ), + .test_en_i ('b0 ), + .scan_rst_ni (1'b1 ), + .ram_cfg_icache_tag_i ('b0 ), + .ram_cfg_rsp_icache_tag_o ( ), + .ram_cfg_icache_data_i ('b0 ), + .ram_cfg_rsp_icache_data_o ( ), - .hart_id_i (32'b0 ), + .hart_id_i (32'b0 ), // First instruction executed is at 0x0 + 0x80 - .boot_addr_i (32'h00000000 ), - - .instr_req_o (host_req[CoreI] ), - .instr_gnt_i (host_gnt[CoreI] ), - .instr_rvalid_i (host_rvalid[CoreI] ), - .instr_addr_o (host_addr[CoreI] ), - .instr_rdata_i (host_rdata[CoreI] ), - .instr_rdata_intg_i (ibex_instr_rdata_intg), - .instr_err_i (host_err[CoreI] ), - - .data_req_o (host_req[CoreD] ), - .data_gnt_i (host_gnt[CoreD] ), - .data_rvalid_i (host_rvalid[CoreD] ), - .data_we_o (host_we[CoreD] ), - .data_be_o (host_be[CoreD] ), - .data_addr_o (host_addr[CoreD] ), - .data_wdata_o (host_wdata[CoreD] ), - .data_wdata_intg_o ( ), - .data_rdata_i (host_rdata[CoreD] ), - .data_rdata_intg_i (ibex_data_rdata_intg ), - .data_err_i (host_err[CoreD] ), - - .irq_software_i (1'b0 ), - .irq_timer_i (1'b0 ), - .irq_external_i (1'b0 ), - .irq_fast_i (15'b0 ), - .irq_nm_i (1'b0 ), - - .scramble_key_valid_i ('0 ), - .scramble_key_i ('0 ), - .scramble_nonce_i ('0 ), - .scramble_req_o ( ), - - .debug_req_i ('b0 ), - .crash_dump_o ( ), - .double_fault_seen_o ( ), - - .fetch_enable_i (ibex_pkg::IbexMuBiOn ), - .alert_minor_o ( ), - .alert_major_internal_o ( ), - .alert_major_bus_o ( ), - .core_sleep_o ( ) + .boot_addr_i (32'h00000000 ), + + .instr_req_o (host_req[CoreI] ), + .instr_gnt_i (host_gnt[CoreI] ), + .instr_rvalid_i (host_rvalid[CoreI] ), + .instr_addr_o (host_addr[CoreI] ), + .instr_rdata_i (host_rdata[CoreI] ), + .instr_rdata_intg_i (ibex_instr_rdata_intg), + .instr_err_i (host_err[CoreI] ), + + .data_req_o (host_req[CoreD] ), + .data_gnt_i (host_gnt[CoreD] ), + .data_rvalid_i (host_rvalid[CoreD] ), + .data_we_o (host_we[CoreD] ), + .data_be_o (host_be[CoreD] ), + .data_addr_o (host_addr[CoreD] ), + .data_wdata_o (host_wdata[CoreD] ), + .data_wdata_intg_o ( ), + .data_rdata_i (host_rdata[CoreD] ), + .data_rdata_intg_i (ibex_data_rdata_intg ), + .data_err_i (host_err[CoreD] ), + + .irq_software_i (1'b0 ), + .irq_timer_i (1'b0 ), + .irq_external_i (1'b0 ), + .irq_fast_i (15'b0 ), + .irq_nm_i (1'b0 ), + + .scramble_key_valid_i ('0 ), + .scramble_key_i ('0 ), + .scramble_nonce_i ('0 ), + .scramble_req_o ( ), + + .debug_req_i ('b0 ), + .crash_dump_o ( ), + .double_fault_seen_o ( ), + + .fetch_enable_i (ibex_pkg::IbexMuBiOn ), + .alert_minor_o ( ), + .alert_major_internal_o ( ), + .alert_major_bus_o ( ), + .core_sleep_o ( ) ); // SRAM block for instruction and data storage diff --git a/dv/uvm/core_ibex/common/prim/prim_and2.sv b/dv/uvm/core_ibex/common/prim/prim_and2.sv deleted file mode 100644 index 157d4dba67..0000000000 --- a/dv/uvm/core_ibex/common/prim/prim_and2.sv +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -// Abstract primitives wrapper. -// -// This file is a stop-gap until the DV file list is generated by FuseSoC. -// Its contents are taken from the file which would be generated by FuseSoC. -// https://github.com/lowRISC/ibex/issues/893 - -module prim_and2 #( - parameter int Width = 1 -) ( - input [Width-1:0] in0_i, - input [Width-1:0] in1_i, - output logic [Width-1:0] out_o -); - -if (1) begin : gen_generic - prim_generic_and2 #( - .Width(Width) - ) u_impl_generic ( - .* - ); -end - -endmodule diff --git a/dv/uvm/core_ibex/common/prim/prim_buf.sv b/dv/uvm/core_ibex/common/prim/prim_buf.sv deleted file mode 100644 index 39cde3d858..0000000000 --- a/dv/uvm/core_ibex/common/prim/prim_buf.sv +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -// Abstract primitives wrapper. -// -// This file is a stop-gap until the DV file list is generated by FuseSoC. -// Its contents are taken from the file which would be generated by FuseSoC. -// https://github.com/lowRISC/ibex/issues/893 - -module prim_buf #( - parameter int Width = 1 -) ( - input [Width-1:0] in_i, - output logic [Width-1:0] out_o -); - - if (1) begin : gen_generic - prim_generic_buf#(.Width(Width)) u_impl_generic ( - .* - ); - end - -endmodule diff --git a/dv/uvm/core_ibex/common/prim/prim_clock_gating.sv b/dv/uvm/core_ibex/common/prim/prim_clock_gating.sv deleted file mode 100644 index f60ae0a02c..0000000000 --- a/dv/uvm/core_ibex/common/prim/prim_clock_gating.sv +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -// Abstract primitives wrapper. -// -// This file is a stop-gap until the DV file list is generated by FuseSoC. -// Its contents are taken from the file which would be generated by FuseSoC. -// https://github.com/lowRISC/ibex/issues/893 - -`ifndef PRIM_DEFAULT_IMPL - `define PRIM_DEFAULT_IMPL prim_pkg::ImplGeneric -`endif - -module prim_clock_gating ( - input clk_i, - input en_i, - input test_en_i, - output logic clk_o -); - parameter prim_pkg::impl_e Impl = `PRIM_DEFAULT_IMPL; - - if (Impl == prim_pkg::ImplGeneric) begin : gen_generic - prim_generic_clock_gating u_impl_generic ( - .* - ); - end else if (Impl == prim_pkg::ImplXilinx) begin : gen_xilinx - prim_xilinx_clock_gating u_impl_xilinx ( - .* - ); - end else begin : gen_failure - // TODO: Find code that works across tools and causes a compile failure - end - -endmodule diff --git a/dv/uvm/core_ibex/common/prim/prim_clock_mux2.sv b/dv/uvm/core_ibex/common/prim/prim_clock_mux2.sv deleted file mode 100644 index 92d3679129..0000000000 --- a/dv/uvm/core_ibex/common/prim/prim_clock_mux2.sv +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -// Abstract primitives wrapper. -// -// This file is a stop-gap until the DV file list is generated by FuseSoC. -// Its contents are taken from the file which would be generated by FuseSoC. -// https://github.com/lowRISC/ibex/issues/893 - -module prim_clock_mux2 #( - parameter bit NoFpgaBufG = 1'b0 -) ( - input clk0_i, - input clk1_i, - input sel_i, - output logic clk_o -); - -if (1) begin : gen_generic - prim_generic_clock_mux2 #( - .NoFpgaBufG(NoFpgaBufG) - ) u_impl_generic ( - .* - ); -end - -endmodule diff --git a/dv/uvm/core_ibex/common/prim/prim_flop.sv b/dv/uvm/core_ibex/common/prim/prim_flop.sv deleted file mode 100644 index 52e982a2c9..0000000000 --- a/dv/uvm/core_ibex/common/prim/prim_flop.sv +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -// Abstract primitives wrapper. -// -// This file is a stop-gap until the DV file list is generated by FuseSoC. -// Its contents are taken from the file which would be generated by FuseSoC. -// https://github.com/lowRISC/ibex/issues/893 - -module prim_flop #( - parameter int Width = 1, - parameter logic [Width-1:0] ResetValue = 0 -) ( - input clk_i, - input rst_ni, - input [Width-1:0] d_i, - output logic [Width-1:0] q_o -); - -if (1) begin : gen_generic - prim_generic_flop #( - .ResetValue(ResetValue), - .Width(Width) - ) u_impl_generic ( - .* - ); -end - -endmodule diff --git a/dv/uvm/core_ibex/common/prim/prim_pkg.sv b/dv/uvm/core_ibex/common/prim/prim_pkg.sv deleted file mode 100644 index 620f24050b..0000000000 --- a/dv/uvm/core_ibex/common/prim/prim_pkg.sv +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 -// -// Constants for use in primitives -// -// This file is a stop-gap until the DV file list is generated by FuseSoC. -// Its contents are taken from the file which would be generated by FuseSoC. -// https://github.com/lowRISC/ibex/issues/893 - -package prim_pkg; - - // Implementation target specialization - typedef enum integer { - ImplGeneric, - ImplXilinx - } impl_e; -endpackage : prim_pkg diff --git a/dv/uvm/core_ibex/common/prim/prim_ram_1p.sv b/dv/uvm/core_ibex/common/prim/prim_ram_1p.sv deleted file mode 100644 index c44af5068b..0000000000 --- a/dv/uvm/core_ibex/common/prim/prim_ram_1p.sv +++ /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 - -// Abstract primitives wrapper. -// -// This file is a stop-gap until the DV file list is generated by FuseSoC. -// Its contents are taken from the file which would be generated by FuseSoC. -// https://github.com/lowRISC/ibex/issues/893 - -module prim_ram_1p import prim_ram_1p_pkg::*; - -#( - - parameter int Width = 32, // bit - parameter int Depth = 128, - parameter int DataBitsPerMask = 1, // Number of data bits per bit of write mask - parameter MemInitFile = "", // VMEM file to initialize the memory width - - localparam int Aw = $clog2(Depth) // derived parameter - -) ( - input logic clk_i, - input ram_1p_cfg_t cfg_i, - - input logic req_i, - input logic write_i, - input logic [Aw-1:0] addr_i, - input logic [Width-1:0] wdata_i, - input logic [Width-1:0] wmask_i, - output logic [Width-1:0] rdata_o // Read data. Data is returned one cycle after req_i is high. -); - - if (1) begin : gen_generic - prim_generic_ram_1p #( - .Depth(Depth), - .MemInitFile(MemInitFile), - .Width(Width), - .DataBitsPerMask(DataBitsPerMask) - ) u_impl_generic ( - .* - ); - - end - -endmodule diff --git a/dv/uvm/core_ibex/ibex_dv.f b/dv/uvm/core_ibex/ibex_dv.f index 1b63a74ba6..8b2cd34cac 100644 --- a/dv/uvm/core_ibex/ibex_dv.f +++ b/dv/uvm/core_ibex/ibex_dv.f @@ -6,7 +6,7 @@ // wrappers around the prim_* modules to instantiate the prim_generic_* ones, // see https://github.com/lowRISC/ibex/issues/893. +incdir+${LOWRISC_IP_DIR}/ip/prim/rtl -${PRJ_DIR}/dv/uvm/core_ibex/common/prim/prim_pkg.sv +${LOWRISC_IP_DIR}/ip/prim_generic/rtl/prim_pkg.sv ${LOWRISC_IP_DIR}/ip/prim/rtl/prim_assert.sv ${LOWRISC_IP_DIR}/ip/prim/rtl/prim_util_pkg.sv ${LOWRISC_IP_DIR}/ip/prim/rtl/prim_count_pkg.sv @@ -23,21 +23,15 @@ ${LOWRISC_IP_DIR}/ip/prim/rtl/prim_secded_hamming_72_64_dec.sv ${LOWRISC_IP_DIR}/ip/prim/rtl/prim_secded_hamming_72_64_enc.sv ${LOWRISC_IP_DIR}/ip/prim/rtl/prim_mubi_pkg.sv -${LOWRISC_IP_DIR}/ip/prim/rtl/prim_ram_1p_pkg.sv +${LOWRISC_IP_DIR}/ip/prim_generic/rtl/prim_ram_1p_pkg.sv ${LOWRISC_IP_DIR}/ip/prim/rtl/prim_ram_1p_adv.sv ${LOWRISC_IP_DIR}/ip/prim/rtl/prim_ram_1p_scr.sv -${LOWRISC_IP_DIR}/ip/prim_generic/rtl/prim_generic_ram_1p.sv -${PRJ_DIR}/dv/uvm/core_ibex/common/prim/prim_ram_1p.sv -${LOWRISC_IP_DIR}/ip/prim_generic/rtl/prim_generic_clock_gating.sv -${PRJ_DIR}/dv/uvm/core_ibex/common/prim/prim_clock_gating.sv -${LOWRISC_IP_DIR}/ip/prim_generic/rtl/prim_generic_buf.sv -${PRJ_DIR}/dv/uvm/core_ibex/common/prim/prim_buf.sv -${LOWRISC_IP_DIR}/ip/prim_generic/rtl/prim_generic_clock_mux2.sv -${PRJ_DIR}/dv/uvm/core_ibex/common/prim/prim_clock_mux2.sv -${LOWRISC_IP_DIR}/ip/prim_generic/rtl/prim_generic_flop.sv -${PRJ_DIR}/dv/uvm/core_ibex/common/prim/prim_flop.sv -${LOWRISC_IP_DIR}/ip/prim_generic/rtl/prim_generic_and2.sv -${PRJ_DIR}/dv/uvm/core_ibex/common/prim/prim_and2.sv +${LOWRISC_IP_DIR}/ip/prim_generic/rtl/prim_ram_1p.sv +${LOWRISC_IP_DIR}/ip/prim_generic/rtl/prim_clock_gating.sv +${LOWRISC_IP_DIR}/ip/prim_generic/rtl/prim_buf.sv +${LOWRISC_IP_DIR}/ip/prim_generic/rtl/prim_clock_mux2.sv +${LOWRISC_IP_DIR}/ip/prim_generic/rtl/prim_flop.sv +${LOWRISC_IP_DIR}/ip/prim_generic/rtl/prim_and2.sv // Shared lowRISC code ${LOWRISC_IP_DIR}/ip/prim/rtl/prim_cipher_pkg.sv diff --git a/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv b/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv index 6e1199e8f4..b4107f41ac 100644 --- a/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv +++ b/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv @@ -116,56 +116,59 @@ module core_ibex_tb_top; .DmExceptionAddr (DmExceptionAddr ) ) dut ( - .clk_i (clk ), - .rst_ni (rst_n ), - - .test_en_i (1'b0 ), - .scan_rst_ni (1'b1 ), - .ram_cfg_i ('b0 ), - - .hart_id_i (32'b0 ), - .boot_addr_i (BootAddr ), - - .instr_req_o (instr_mem_vif.request ), - .instr_gnt_i (instr_mem_vif.grant ), - .instr_rvalid_i (instr_mem_vif.rvalid ), - .instr_addr_o (instr_mem_vif.addr ), - .instr_rdata_i (instr_mem_vif.rdata ), - .instr_rdata_intg_i (instr_mem_vif.rintg ), - .instr_err_i (instr_mem_vif.error ), - - .data_req_o (data_mem_vif.request ), - .data_gnt_i (data_mem_vif.grant ), - .data_rvalid_i (data_mem_vif.rvalid ), - .data_addr_o (data_mem_vif.addr ), - .data_we_o (data_mem_vif.we ), - .data_be_o (data_mem_vif.be ), - .data_rdata_i (data_mem_vif.rdata ), - .data_rdata_intg_i (data_mem_vif.rintg ), - .data_wdata_o (data_mem_vif.wdata ), - .data_wdata_intg_o (data_mem_vif.wintg ), - .data_err_i (data_mem_vif.error ), - - .irq_software_i (irq_vif.irq_software ), - .irq_timer_i (irq_vif.irq_timer ), - .irq_external_i (irq_vif.irq_external ), - .irq_fast_i (irq_vif.irq_fast ), - .irq_nm_i (irq_vif.irq_nm ), - - .scramble_key_valid_i (scrambling_key_if.ack ), - .scramble_key_i (scramble_key ), - .scramble_nonce_i (scramble_nonce ), - .scramble_req_o (scrambling_key_if.req ), - - .debug_req_i (dut_if.debug_req ), - .crash_dump_o ( ), - .double_fault_seen_o (dut_if.double_fault_seen ), - - .fetch_enable_i (dut_if.fetch_enable ), - .alert_minor_o (dut_if.alert_minor ), - .alert_major_internal_o (dut_if.alert_major_internal), - .alert_major_bus_o (dut_if.alert_major_bus ), - .core_sleep_o (dut_if.core_sleep ) + .clk_i (clk ), + .rst_ni (rst_n ), + + .test_en_i (1'b0 ), + .scan_rst_ni (1'b1 ), + .ram_cfg_icache_tag_i ('b0 ), + .ram_cfg_rsp_icache_tag_o ( ), + .ram_cfg_icache_data_i ('b0 ), + .ram_cfg_rsp_icache_data_o ( ), + + .hart_id_i (32'b0 ), + .boot_addr_i (BootAddr ), + + .instr_req_o (instr_mem_vif.request ), + .instr_gnt_i (instr_mem_vif.grant ), + .instr_rvalid_i (instr_mem_vif.rvalid ), + .instr_addr_o (instr_mem_vif.addr ), + .instr_rdata_i (instr_mem_vif.rdata ), + .instr_rdata_intg_i (instr_mem_vif.rintg ), + .instr_err_i (instr_mem_vif.error ), + + .data_req_o (data_mem_vif.request ), + .data_gnt_i (data_mem_vif.grant ), + .data_rvalid_i (data_mem_vif.rvalid ), + .data_addr_o (data_mem_vif.addr ), + .data_we_o (data_mem_vif.we ), + .data_be_o (data_mem_vif.be ), + .data_rdata_i (data_mem_vif.rdata ), + .data_rdata_intg_i (data_mem_vif.rintg ), + .data_wdata_o (data_mem_vif.wdata ), + .data_wdata_intg_o (data_mem_vif.wintg ), + .data_err_i (data_mem_vif.error ), + + .irq_software_i (irq_vif.irq_software ), + .irq_timer_i (irq_vif.irq_timer ), + .irq_external_i (irq_vif.irq_external ), + .irq_fast_i (irq_vif.irq_fast ), + .irq_nm_i (irq_vif.irq_nm ), + + .scramble_key_valid_i (scrambling_key_if.ack ), + .scramble_key_i (scramble_key ), + .scramble_nonce_i (scramble_nonce ), + .scramble_req_o (scrambling_key_if.req ), + + .debug_req_i (dut_if.debug_req ), + .crash_dump_o ( ), + .double_fault_seen_o (dut_if.double_fault_seen ), + + .fetch_enable_i (dut_if.fetch_enable ), + .alert_minor_o (dut_if.alert_minor ), + .alert_major_internal_o (dut_if.alert_major_internal), + .alert_major_bus_o (dut_if.alert_major_bus ), + .core_sleep_o (dut_if.core_sleep ) ); `define IBEX_RF_PATH core_ibex_tb_top.dut.u_ibex_top.gen_regfile_ff.register_file_i diff --git a/dv/uvm/core_ibex/yaml/rtl_simulation.yaml b/dv/uvm/core_ibex/yaml/rtl_simulation.yaml index d62b84c6fa..e3877babdf 100644 --- a/dv/uvm/core_ibex/yaml/rtl_simulation.yaml +++ b/dv/uvm/core_ibex/yaml/rtl_simulation.yaml @@ -267,7 +267,7 @@ wave_opts: > -access rwc -linedebug cosim_opts: > - -f ibex_dv_cosim_dpi.f + -f /ibex_dv_cosim_dpi.f -I/dv/cosim diff --git a/dv/uvm/icache/dv/ibex_icache_sim.core b/dv/uvm/icache/dv/ibex_icache_sim.core index 473007cf67..54221d0499 100644 --- a/dv/uvm/icache/dv/ibex_icache_sim.core +++ b/dv/uvm/icache/dv/ibex_icache_sim.core @@ -20,17 +20,8 @@ filesets: targets: sim: - parameters: - - PRIM_DEFAULT_IMPL=prim_pkg::ImplBadbit filesets: - files_rtl - files_dv toplevel: tb default_tool: vcs - -parameters: - PRIM_DEFAULT_IMPL: - datatype: str - paramtype: vlogdefine - description: Primitives implementation to use, e.g. "prim_pkg::ImplGeneric". - default: prim_pkg::ImplBadbit diff --git a/dv/uvm/icache/dv/ibex_icache_sim_cfg.hjson b/dv/uvm/icache/dv/ibex_icache_sim_cfg.hjson index f1135870c1..e6617cc2c9 100644 --- a/dv/uvm/icache/dv/ibex_icache_sim_cfg.hjson +++ b/dv/uvm/icache/dv/ibex_icache_sim_cfg.hjson @@ -36,6 +36,15 @@ } ] + overrides: [ + // Override the search paths to prioritize the selection of + // packages (with the same VLNV). The last one wins. + { + name: fusesoc_cores_root_dirs + value: ["--cores-root {proj_root}"] + } + ] + // Default iterations for all tests - each test entry can override this. reseed: 50 diff --git a/dv/uvm/icache/dv/prim_badbit/README.md b/dv/uvm/icache/dv/prim_badbit/README.md deleted file mode 100644 index 689f913ab7..0000000000 --- a/dv/uvm/icache/dv/prim_badbit/README.md +++ /dev/null @@ -1,11 +0,0 @@ -Badbit RAM -========== - -This is an SRAM wrapper that allows a testbench to force bit errors on the read interface. - -This works as a dummy technology library. -Instantiate it by adding setting `PRIM_DEFAULT_IMPL` to prim_pkg::ImplBadbit (see the README.md in the prim directory for details). -To use it, bind a module or interface into an instance of `prim_badbit_ram_1p` and force the value of `bad_bit_mask`, which is XOR'd with rdata. - -To make this easier to use, we don't vary the width of `bad_bit_mask` with the `Width` parameter: it's a constant 128. -This means that the bound interface doesn't need to be parameterised. diff --git a/dv/uvm/icache/dv/prim_badbit/prim_badbit_ram_1p.core b/dv/uvm/icache/dv/prim_badbit/prim_badbit_ram_1p.core deleted file mode 100644 index df81ec5dd3..0000000000 --- a/dv/uvm/icache/dv/prim_badbit/prim_badbit_ram_1p.core +++ /dev/null @@ -1,20 +0,0 @@ -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_badbit:ram_1p" -description: "Single-port RAM which allows a bound interface to inject errors" -filesets: - files_rtl: - depend: - - lowrisc:prim_generic:ram_1p - - lowrisc:prim:assert - files: - - prim_badbit_ram_1p.sv - file_type: systemVerilogSource - -targets: - default: - filesets: - - files_rtl diff --git a/dv/uvm/icache/dv/prim_badbit/prim_badbit_ram_1p.sv b/dv/uvm/icache/dv/prim_badbit/prim_badbit_ram_1p.sv deleted file mode 100644 index 7fa4678f02..0000000000 --- a/dv/uvm/icache/dv/prim_badbit/prim_badbit_ram_1p.sv +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 -// -// Single-port SRAM model which allows a test to corrupt read responses from the underlying memory. -// -// To use this, instantiate it then bind in a module or interface that has bad_bit_mask as an -// output. A nonzero bit in bad_bit_mask will cause the corresponding bit to be flipped in the -// response. - -`include "prim_assert.sv" - -module prim_badbit_ram_1p #( - parameter int Width = 32, // bit - parameter int Depth = 128, - parameter int DataBitsPerMask = 1, // Number of data bits per bit of write mask - parameter MemInitFile = "", // VMEM file to initialize the memory with - - localparam int Aw = $clog2(Depth) // derived parameter -) ( - input logic clk_i, - - input logic req_i, - input logic write_i, - input logic [Aw-1:0] addr_i, - input logic [Width-1:0] wdata_i, - input logic [Width-1:0] wmask_i, - output logic [Width-1:0] rdata_o // Read data. Data is returned one cycle after req_i is high. -); - - logic [Width-1:0] sram_rdata; - - prim_generic_ram_1p #( - .Width (Width), - .Depth (Depth), - .DataBitsPerMask(DataBitsPerMask), - .MemInitFile (MemInitFile) - ) u_mem ( - .clk_i(clk_i), - - .cfg_i ('0), - .req_i (req_i), - .write_i(write_i), - .addr_i (addr_i), - .wdata_i(wdata_i), - .wmask_i(wmask_i), - .rdata_o(sram_rdata) - ); - - // This module doesn't work with Verilator (because of the wired-or). Because we define the - // "badbit" ram as a technology library, it gets picked up and parsed by any tool using the Ibex - // repo. Rather than telling Verilator to ignore the whole lot (which causes NOTFOUNDMODULE - // warnings), we just hide the actual guts. -`ifdef VERILATOR - assign rdata_o = sram_rdata; -`else - // Making bad_bit_mask a constant size makes this easier to use (because you don't need to faff - // around with parameterised interfaces in your UVM database). Check that rdata_o is actually - // controllable. Similarly, we make the address a constant width: make sure that's large enough. - `ASSERT_INIT(WidthSmallEnough, Width <= 128) - `ASSERT_INIT(AddrSmallEnough, Aw <= 32) - - // Make the Width parameter easily accessible to bound-in modules. - logic [31:0] width; - assign width = Width; - - // Similarly, extend addr, wdata, wmask and sram_rdata (the un-fiddled value) - logic [31:0] addr; - logic [127:0] wdata, wmask, rdata; - assign addr = {{32 - Aw{1'b0}}, addr_i}; - assign wdata = {{128 - Width{1'b0}}, wdata_i}; - assign wmask = {{128 - Width{1'b0}}, wmask_i}; - assign rdata = {{128 - Width{1'b0}}, sram_rdata}; - - // To inject errors, bind in an interface with bad_bit_mask as an output and assign one of the - // bits in bad_bit_mask[Width-1:0] to one. The wired-OR together with an assignment to zero means - // this acts like a weak pull-down. - wor [127:0] bad_bit_mask; - assign bad_bit_mask = 128'b0; - - assign rdata_o = sram_rdata ^ bad_bit_mask; -`endif // VERILATOR - -endmodule diff --git a/dv/verilator/simple_system_cosim/ibex_cosim_setup_check.core b/dv/verilator/simple_system_cosim/ibex_cosim_setup_check.core index ae93716270..61c196c044 100644 --- a/dv/verilator/simple_system_cosim/ibex_cosim_setup_check.core +++ b/dv/verilator/simple_system_cosim/ibex_cosim_setup_check.core @@ -8,7 +8,7 @@ description: "Check that Spike is installed properly for cosim" filesets: files_ibex_cosim_setup_check: files: - - ./util/ibex_cosim_setup_check.sh : { copyto: util/ibex_cosim_setup_check.sh } + - util/ibex_cosim_setup_check.sh : { copyto: util/ibex_cosim_setup_check.sh } scripts: ibex_cosim_setup_check: diff --git a/dv/verilator/simple_system_cosim/simple_system_cosim.cc b/dv/verilator/simple_system_cosim/simple_system_cosim.cc index d765636d07..c3827bc3f0 100644 --- a/dv/verilator/simple_system_cosim/simple_system_cosim.cc +++ b/dv/verilator/simple_system_cosim/simple_system_cosim.cc @@ -84,8 +84,7 @@ void create_cosim(svBit secure_ibex, svBit icache_en, int main(int argc, char **argv) { simple_system_cosim = new SimpleSystemCosim( - "TOP.ibex_simple_system.u_ram.u_ram.gen_generic.u_impl_generic", - (1024 * 1024) / 4); + "TOP.ibex_simple_system.u_ram.u_ram", (1024 * 1024) / 4); int ret_code = simple_system_cosim->Main(argc, argv); diff --git a/examples/simple_system/ibex_simple_system_main.cc b/examples/simple_system/ibex_simple_system_main.cc index 0ade75bdd9..5ac1e0a951 100644 --- a/examples/simple_system/ibex_simple_system_main.cc +++ b/examples/simple_system/ibex_simple_system_main.cc @@ -5,9 +5,8 @@ #include "ibex_simple_system.h" int main(int argc, char **argv) { - SimpleSystem simple_system( - "TOP.ibex_simple_system.u_ram.u_ram.gen_generic.u_impl_generic", - SimpleSystem::kRAM_SizeBytes / 4); + SimpleSystem simple_system("TOP.ibex_simple_system.u_ram.u_ram", + SimpleSystem::kRAM_SizeBytes / 4); return simple_system.Main(argc, argv); } diff --git a/examples/simple_system/rtl/ibex_simple_system.sv b/examples/simple_system/rtl/ibex_simple_system.sv index e466ac286d..a6239965c1 100644 --- a/examples/simple_system/rtl/ibex_simple_system.sv +++ b/examples/simple_system/rtl/ibex_simple_system.sv @@ -209,57 +209,60 @@ module ibex_simple_system ( .DmHaltAddr ( 32'h00100000 ), .DmExceptionAddr ( 32'h00100000 ) ) u_top ( - .clk_i (clk_sys), - .rst_ni (rst_sys_n), + .clk_i (clk_sys), + .rst_ni (rst_sys_n), - .test_en_i (1'b0), - .scan_rst_ni (1'b1), - .ram_cfg_i (prim_ram_1p_pkg::RAM_1P_CFG_DEFAULT), + .test_en_i (1'b0), + .scan_rst_ni (1'b1), + .ram_cfg_icache_tag_i (prim_ram_1p_pkg::RAM_1P_CFG_DEFAULT), + .ram_cfg_rsp_icache_tag_o (), + .ram_cfg_icache_data_i (prim_ram_1p_pkg::RAM_1P_CFG_DEFAULT), + .ram_cfg_rsp_icache_data_o (), - .hart_id_i (32'b0), + .hart_id_i (32'b0), // First instruction executed is at 0x0 + 0x80 - .boot_addr_i (32'h00100000), - - .instr_req_o (instr_req), - .instr_gnt_i (instr_gnt), - .instr_rvalid_i (instr_rvalid), - .instr_addr_o (instr_addr), - .instr_rdata_i (instr_rdata), - .instr_rdata_intg_i (instr_rdata_intg), - .instr_err_i (instr_err), - - .data_req_o (host_req[CoreD]), - .data_gnt_i (host_gnt[CoreD]), - .data_rvalid_i (host_rvalid[CoreD]), - .data_we_o (host_we[CoreD]), - .data_be_o (host_be[CoreD]), - .data_addr_o (host_addr[CoreD]), - .data_wdata_o (host_wdata[CoreD]), - .data_wdata_intg_o (), - .data_rdata_i (host_rdata[CoreD]), - .data_rdata_intg_i (data_rdata_intg), - .data_err_i (host_err[CoreD]), - - .irq_software_i (1'b0), - .irq_timer_i (timer_irq), - .irq_external_i (1'b0), - .irq_fast_i (15'b0), - .irq_nm_i (1'b0), - - .scramble_key_valid_i ('0), - .scramble_key_i ('0), - .scramble_nonce_i ('0), - .scramble_req_o (), - - .debug_req_i (1'b0), - .crash_dump_o (), - .double_fault_seen_o (), - - .fetch_enable_i (ibex_pkg::IbexMuBiOn), - .alert_minor_o (), - .alert_major_internal_o (), - .alert_major_bus_o (), - .core_sleep_o () + .boot_addr_i (32'h00100000), + + .instr_req_o (instr_req), + .instr_gnt_i (instr_gnt), + .instr_rvalid_i (instr_rvalid), + .instr_addr_o (instr_addr), + .instr_rdata_i (instr_rdata), + .instr_rdata_intg_i (instr_rdata_intg), + .instr_err_i (instr_err), + + .data_req_o (host_req[CoreD]), + .data_gnt_i (host_gnt[CoreD]), + .data_rvalid_i (host_rvalid[CoreD]), + .data_we_o (host_we[CoreD]), + .data_be_o (host_be[CoreD]), + .data_addr_o (host_addr[CoreD]), + .data_wdata_o (host_wdata[CoreD]), + .data_wdata_intg_o (), + .data_rdata_i (host_rdata[CoreD]), + .data_rdata_intg_i (data_rdata_intg), + .data_err_i (host_err[CoreD]), + + .irq_software_i (1'b0), + .irq_timer_i (timer_irq), + .irq_external_i (1'b0), + .irq_fast_i (15'b0), + .irq_nm_i (1'b0), + + .scramble_key_valid_i ('0), + .scramble_key_i ('0), + .scramble_nonce_i ('0), + .scramble_req_o (), + + .debug_req_i (1'b0), + .crash_dump_o (), + .double_fault_seen_o (), + + .fetch_enable_i (ibex_pkg::IbexMuBiOn), + .alert_minor_o (), + .alert_major_internal_o (), + .alert_major_bus_o (), + .core_sleep_o () ); // SRAM block for instruction and data storage diff --git a/flake.nix b/flake.nix index f34cf8724e..8666407de0 100644 --- a/flake.nix +++ b/flake.nix @@ -117,6 +117,12 @@ (inputs.lowrisc-nix.lib.pyprojectOverrides { inherit pkgs; }) + (final: prev: { + jsonschema2md = prev.jsonschema2md.overrideAttrs (old: { + # Manually add babel to the build inputs + nativeBuildInputs = (old.nativeBuildInputs or []) ++ [ final.babel ]; + }); + }) ] ); in diff --git a/ibex_top_tracing.core b/ibex_top_tracing.core index f52c5c005f..21ca91a0b0 100644 --- a/ibex_top_tracing.core +++ b/ibex_top_tracing.core @@ -9,6 +9,8 @@ filesets: depend: - lowrisc:ibex:ibex_top - lowrisc:ibex:ibex_tracer + - "fileset_partner ? (partner:prim_generic:all)" + - "!fileset_partner ? (lowrisc:prim_generic:all)" files: - rtl/ibex_top_tracing.sv file_type: systemVerilogSource diff --git a/python-requirements.txt b/python-requirements.txt index e631f29e56..00bb2bd3c7 100644 --- a/python-requirements.txt +++ b/python-requirements.txt @@ -2,11 +2,7 @@ # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -# Development version of edalize until all our changes are upstream -git+https://github.com/lowRISC/edalize.git@ot - -# Development version with OT-specific changes -git+https://github.com/lowRISC/fusesoc.git@ot +fusesoc == 2.4.3 packaging pyyaml diff --git a/rtl/ibex_ex_block.sv b/rtl/ibex_ex_block.sv index 1a21017ebb..462f2fcfdc 100644 --- a/rtl/ibex_ex_block.sv +++ b/rtl/ibex_ex_block.sv @@ -197,8 +197,8 @@ module ibex_ex_block #( assign ex_valid_o = multdiv_sel ? multdiv_valid : ~(|alu_imd_val_we); `ifdef INC_ASSERT - // This is intended to be accessed via hierarchical references so isn't output from this module nor - // used in any logic in this module + // This is intended to be accessed via hierarchical references, so it is neither output from this + // module nor used in any logic in this module logic sva_multdiv_fsm_idle; if (RV32M == RV32MSlow) begin : gen_multdiv_sva_idle_slow diff --git a/rtl/ibex_multdiv_fast.sv b/rtl/ibex_multdiv_fast.sv index 4cfe11c143..7f7f046366 100644 --- a/rtl/ibex_multdiv_fast.sv +++ b/rtl/ibex_multdiv_fast.sv @@ -536,8 +536,8 @@ module ibex_multdiv_fast #( logic sva_fsm_idle; logic unused_sva_fsm_idle; - // This is intended to be accessed via hierarchical references so isn't output from this module nor - // used in any logic in this module + // This is intended to be accessed via hierarchical references, so it is neither output from this + // module nor used in any logic in this module assign sva_fsm_idle = (md_state_q == MD_IDLE) && sva_mul_fsm_idle; // Mark the sva_fsm_idle as unused to avoid lint issues assign unused_sva_fsm_idle = sva_fsm_idle; diff --git a/rtl/ibex_top.sv b/rtl/ibex_top.sv index 823fa792fc..f846b13039 100644 --- a/rtl/ibex_top.sv +++ b/rtl/ibex_top.sv @@ -55,105 +55,110 @@ module ibex_top import ibex_pkg::*; #( parameter logic [31:0] CsrMimpId = 32'b0 ) ( // Clock and Reset - input logic clk_i, - input logic rst_ni, + input logic clk_i, + input logic rst_ni, - input logic test_en_i, // enable all clock gates for testing - input prim_ram_1p_pkg::ram_1p_cfg_t ram_cfg_i, + // enable all clock gates for testing + input logic test_en_i, + input prim_ram_1p_pkg::ram_1p_cfg_t ram_cfg_icache_tag_i, + output prim_ram_1p_pkg::ram_1p_cfg_rsp_t [ibex_pkg::IC_NUM_WAYS-1:0] ram_cfg_rsp_icache_tag_o, + input prim_ram_1p_pkg::ram_1p_cfg_t ram_cfg_icache_data_i, + output prim_ram_1p_pkg::ram_1p_cfg_rsp_t [ibex_pkg::IC_NUM_WAYS-1:0] ram_cfg_rsp_icache_data_o, - input logic [31:0] hart_id_i, - input logic [31:0] boot_addr_i, + input logic [31:0] hart_id_i, + input logic [31:0] boot_addr_i, // Instruction memory interface - output logic instr_req_o, - input logic instr_gnt_i, - input logic instr_rvalid_i, - output logic [31:0] instr_addr_o, - input logic [31:0] instr_rdata_i, - input logic [6:0] instr_rdata_intg_i, - input logic instr_err_i, + output logic instr_req_o, + input logic instr_gnt_i, + input logic instr_rvalid_i, + output logic [31:0] instr_addr_o, + input logic [31:0] instr_rdata_i, + input logic [6:0] instr_rdata_intg_i, + input logic instr_err_i, // Data memory interface - output logic data_req_o, - input logic data_gnt_i, - input logic data_rvalid_i, - output logic data_we_o, - output logic [3:0] data_be_o, - output logic [31:0] data_addr_o, - output logic [31:0] data_wdata_o, - output logic [6:0] data_wdata_intg_o, - input logic [31:0] data_rdata_i, - input logic [6:0] data_rdata_intg_i, - input logic data_err_i, + output logic data_req_o, + input logic data_gnt_i, + input logic data_rvalid_i, + output logic data_we_o, + output logic [3:0] data_be_o, + output logic [31:0] data_addr_o, + output logic [31:0] data_wdata_o, + output logic [6:0] data_wdata_intg_o, + input logic [31:0] data_rdata_i, + input logic [6:0] data_rdata_intg_i, + input logic data_err_i, // Interrupt inputs - input logic irq_software_i, - input logic irq_timer_i, - input logic irq_external_i, - input logic [14:0] irq_fast_i, - input logic irq_nm_i, // non-maskable interrupt + input logic irq_software_i, + input logic irq_timer_i, + input logic irq_external_i, + input logic [14:0] irq_fast_i, + // non-maskeable interrupt + input logic irq_nm_i, // Scrambling Interface - input logic scramble_key_valid_i, - input logic [SCRAMBLE_KEY_W-1:0] scramble_key_i, - input logic [SCRAMBLE_NONCE_W-1:0] scramble_nonce_i, - output logic scramble_req_o, + input logic scramble_key_valid_i, + input logic [SCRAMBLE_KEY_W-1:0] scramble_key_i, + input logic [SCRAMBLE_NONCE_W-1:0] scramble_nonce_i, + output logic scramble_req_o, // Debug Interface - input logic debug_req_i, - output crash_dump_t crash_dump_o, - output logic double_fault_seen_o, + input logic debug_req_i, + output crash_dump_t crash_dump_o, + output logic double_fault_seen_o, // RISC-V Formal Interface // Does not comply with the coding standards of _i/_o suffixes, but follows // the convention of RISC-V Formal Interface Specification. `ifdef RVFI - output logic rvfi_valid, - output logic [63:0] rvfi_order, - output logic [31:0] rvfi_insn, - output logic rvfi_trap, - output logic rvfi_halt, - output logic rvfi_intr, - output logic [ 1:0] rvfi_mode, - output logic [ 1:0] rvfi_ixl, - output logic [ 4:0] rvfi_rs1_addr, - output logic [ 4:0] rvfi_rs2_addr, - output logic [ 4:0] rvfi_rs3_addr, - output logic [31:0] rvfi_rs1_rdata, - output logic [31:0] rvfi_rs2_rdata, - output logic [31:0] rvfi_rs3_rdata, - output logic [ 4:0] rvfi_rd_addr, - output logic [31:0] rvfi_rd_wdata, - output logic [31:0] rvfi_pc_rdata, - output logic [31:0] rvfi_pc_wdata, - output logic [31:0] rvfi_mem_addr, - output logic [ 3:0] rvfi_mem_rmask, - output logic [ 3:0] rvfi_mem_wmask, - output logic [31:0] rvfi_mem_rdata, - output logic [31:0] rvfi_mem_wdata, - output logic [31:0] rvfi_ext_pre_mip, - output logic [31:0] rvfi_ext_post_mip, - output logic rvfi_ext_nmi, - output logic rvfi_ext_nmi_int, - output logic rvfi_ext_debug_req, - output logic rvfi_ext_debug_mode, - output logic rvfi_ext_rf_wr_suppress, - output logic [63:0] rvfi_ext_mcycle, - output logic [31:0] rvfi_ext_mhpmcounters [10], - output logic [31:0] rvfi_ext_mhpmcountersh [10], - output logic rvfi_ext_ic_scr_key_valid, - output logic rvfi_ext_irq_valid, + output logic rvfi_valid, + output logic [63:0] rvfi_order, + output logic [31:0] rvfi_insn, + output logic rvfi_trap, + output logic rvfi_halt, + output logic rvfi_intr, + output logic [ 1:0] rvfi_mode, + output logic [ 1:0] rvfi_ixl, + output logic [ 4:0] rvfi_rs1_addr, + output logic [ 4:0] rvfi_rs2_addr, + output logic [ 4:0] rvfi_rs3_addr, + output logic [31:0] rvfi_rs1_rdata, + output logic [31:0] rvfi_rs2_rdata, + output logic [31:0] rvfi_rs3_rdata, + output logic [ 4:0] rvfi_rd_addr, + output logic [31:0] rvfi_rd_wdata, + output logic [31:0] rvfi_pc_rdata, + output logic [31:0] rvfi_pc_wdata, + output logic [31:0] rvfi_mem_addr, + output logic [ 3:0] rvfi_mem_rmask, + output logic [ 3:0] rvfi_mem_wmask, + output logic [31:0] rvfi_mem_rdata, + output logic [31:0] rvfi_mem_wdata, + output logic [31:0] rvfi_ext_pre_mip, + output logic [31:0] rvfi_ext_post_mip, + output logic rvfi_ext_nmi, + output logic rvfi_ext_nmi_int, + output logic rvfi_ext_debug_req, + output logic rvfi_ext_debug_mode, + output logic rvfi_ext_rf_wr_suppress, + output logic [63:0] rvfi_ext_mcycle, + output logic [31:0] rvfi_ext_mhpmcounters [10], + output logic [31:0] rvfi_ext_mhpmcountersh [10], + output logic rvfi_ext_ic_scr_key_valid, + output logic rvfi_ext_irq_valid, `endif // CPU Control Signals - input ibex_mubi_t fetch_enable_i, - output logic alert_minor_o, - output logic alert_major_internal_o, - output logic alert_major_bus_o, - output logic core_sleep_o, + input ibex_mubi_t fetch_enable_i, + output logic alert_minor_o, + output logic alert_major_internal_o, + output logic alert_major_bus_o, + output logic core_sleep_o, // DFT bypass controls - input logic scan_rst_ni + input logic scan_rst_ni ); localparam bit Lockstep = SecureIbex; @@ -614,7 +619,8 @@ module ibex_top import ibex_pkg::*; #( .rvalid_o (), .raddr_o (), .rerror_o (), - .cfg_i (ram_cfg_i), + .cfg_i (ram_cfg_icache_tag_i), + .cfg_rsp_o (ram_cfg_rsp_icache_tag_o[way]), .wr_collision_o (), .write_pending_o (), @@ -651,7 +657,8 @@ module ibex_top import ibex_pkg::*; #( .rvalid_o (), .raddr_o (), .rerror_o (), - .cfg_i (ram_cfg_i), + .cfg_i (ram_cfg_icache_data_i), + .cfg_rsp_o (ram_cfg_rsp_icache_data_o[way]), .wr_collision_o (), .write_pending_o (), @@ -697,6 +704,7 @@ module ibex_top import ibex_pkg::*; #( .DataBitsPerMask (TagSizeECC) ) tag_bank ( .clk_i, + .rst_ni, .req_i (ic_tag_req[way]), @@ -706,7 +714,8 @@ module ibex_top import ibex_pkg::*; #( .wmask_i ({TagSizeECC{1'b1}}), .rdata_o (ic_tag_rdata[way]), - .cfg_i (ram_cfg_i) + .cfg_i (ram_cfg_icache_tag_i), + .cfg_rsp_o (ram_cfg_rsp_icache_tag_o[way]) ); // Data RAM instantiation @@ -716,6 +725,7 @@ module ibex_top import ibex_pkg::*; #( .DataBitsPerMask (LineSizeECC) ) data_bank ( .clk_i, + .rst_ni, .req_i (ic_data_req[way]), @@ -725,7 +735,8 @@ module ibex_top import ibex_pkg::*; #( .wmask_i ({LineSizeECC{1'b1}}), .rdata_o (ic_data_rdata[way]), - .cfg_i (ram_cfg_i) + .cfg_i (ram_cfg_icache_data_i), + .cfg_rsp_o (ram_cfg_rsp_icache_data_o[way]) ); assign icache_tag_alert = '{default:'b0}; @@ -735,10 +746,12 @@ module ibex_top import ibex_pkg::*; #( end else begin : gen_norams - prim_ram_1p_pkg::ram_1p_cfg_t unused_ram_cfg; + logic unused_ram_cfg; logic unused_ram_inputs; - assign unused_ram_cfg = ram_cfg_i; + assign unused_ram_cfg = |{ram_cfg_icache_tag_i, ram_cfg_icache_data_i}; + assign ram_cfg_rsp_icache_tag_o = '0; + assign ram_cfg_rsp_icache_data_o = '0; assign unused_ram_inputs = (|ic_tag_req) & ic_tag_write & (|ic_tag_addr) & (|ic_tag_wdata) & (|ic_data_req) & ic_data_write & (|ic_data_addr) & (|ic_data_wdata) & (|scramble_key_q) & (|scramble_nonce_q) & scramble_key_valid_q & @@ -1156,7 +1169,8 @@ module ibex_top import ibex_pkg::*; #( // X check for top-level inputs `ASSERT_KNOWN(IbexTestEnX, test_en_i) - `ASSERT_KNOWN(IbexRamCfgX, ram_cfg_i) + `ASSERT_KNOWN(IbexRamCfgTagX, ram_cfg_icache_tag_i) + `ASSERT_KNOWN(IbexRamCfgDataX, ram_cfg_icache_data_i) `ASSERT_KNOWN(IbexHartIdX, hart_id_i) `ASSERT_KNOWN(IbexBootAddrX, boot_addr_i) diff --git a/rtl/ibex_top_tracing.sv b/rtl/ibex_top_tracing.sv index 4af5b5b8aa..88586484d4 100644 --- a/rtl/ibex_top_tracing.sv +++ b/rtl/ibex_top_tracing.sv @@ -33,63 +33,68 @@ module ibex_top_tracing import ibex_pkg::*; #( parameter int unsigned DmExceptionAddr = 32'h1A110808 ) ( // Clock and Reset - input logic clk_i, - input logic rst_ni, + input logic clk_i, + input logic rst_ni, - input logic test_en_i, // enable all clock gates for testing - input logic scan_rst_ni, - input prim_ram_1p_pkg::ram_1p_cfg_t ram_cfg_i, + // enable all clock gates for testing + input logic test_en_i, + input logic scan_rst_ni, + input prim_ram_1p_pkg::ram_1p_cfg_t ram_cfg_icache_tag_i, + output prim_ram_1p_pkg::ram_1p_cfg_rsp_t [ibex_pkg::IC_NUM_WAYS-1:0] ram_cfg_rsp_icache_tag_o, + input prim_ram_1p_pkg::ram_1p_cfg_t ram_cfg_icache_data_i, + output prim_ram_1p_pkg::ram_1p_cfg_rsp_t [ibex_pkg::IC_NUM_WAYS-1:0] ram_cfg_rsp_icache_data_o, - input logic [31:0] hart_id_i, - input logic [31:0] boot_addr_i, + input logic [31:0] hart_id_i, + input logic [31:0] boot_addr_i, // Instruction memory interface - output logic instr_req_o, - input logic instr_gnt_i, - input logic instr_rvalid_i, - output logic [31:0] instr_addr_o, - input logic [31:0] instr_rdata_i, - input logic [6:0] instr_rdata_intg_i, - input logic instr_err_i, + output logic instr_req_o, + input logic instr_gnt_i, + input logic instr_rvalid_i, + output logic [31:0] instr_addr_o, + input logic [31:0] instr_rdata_i, + input logic [6:0] instr_rdata_intg_i, + input logic instr_err_i, // Data memory interface - output logic data_req_o, - input logic data_gnt_i, - input logic data_rvalid_i, - output logic data_we_o, - output logic [3:0] data_be_o, - output logic [31:0] data_addr_o, - output logic [31:0] data_wdata_o, - output logic [6:0] data_wdata_intg_o, - input logic [31:0] data_rdata_i, - input logic [6:0] data_rdata_intg_i, - input logic data_err_i, + output logic data_req_o, + input logic data_gnt_i, + input logic data_rvalid_i, + output logic data_we_o, + output logic [3:0] data_be_o, + output logic [31:0] data_addr_o, + output logic [31:0] data_wdata_o, + output logic [6:0] data_wdata_intg_o, + input logic [31:0] data_rdata_i, + input logic [6:0] data_rdata_intg_i, + input logic data_err_i, // Interrupt inputs - input logic irq_software_i, - input logic irq_timer_i, - input logic irq_external_i, - input logic [14:0] irq_fast_i, - input logic irq_nm_i, // non-maskable interrupt + input logic irq_software_i, + input logic irq_timer_i, + input logic irq_external_i, + input logic [14:0] irq_fast_i, + // non-maskable interrupt + input logic irq_nm_i, // Scrambling Interface - input logic scramble_key_valid_i, - input logic [SCRAMBLE_KEY_W-1:0] scramble_key_i, - input logic [SCRAMBLE_NONCE_W-1:0] scramble_nonce_i, - output logic scramble_req_o, + input logic scramble_key_valid_i, + input logic [SCRAMBLE_KEY_W-1:0] scramble_key_i, + input logic [SCRAMBLE_NONCE_W-1:0] scramble_nonce_i, + output logic scramble_req_o, // Debug Interface - input logic debug_req_i, - output crash_dump_t crash_dump_o, - output logic double_fault_seen_o, + input logic debug_req_i, + output crash_dump_t crash_dump_o, + output logic double_fault_seen_o, // CPU Control Signals - input ibex_mubi_t fetch_enable_i, - output logic alert_minor_o, - output logic alert_major_internal_o, - output logic alert_major_bus_o, - output logic core_sleep_o + input ibex_mubi_t fetch_enable_i, + output logic alert_minor_o, + output logic alert_major_internal_o, + output logic alert_major_bus_o, + output logic core_sleep_o ); @@ -196,7 +201,10 @@ module ibex_top_tracing import ibex_pkg::*; #( .test_en_i, .scan_rst_ni, - .ram_cfg_i, + .ram_cfg_icache_tag_i, + .ram_cfg_rsp_icache_tag_o, + .ram_cfg_icache_data_i, + .ram_cfg_rsp_icache_data_o, .hart_id_i, .boot_addr_i, diff --git a/shared/rtl/ram_1p.sv b/shared/rtl/ram_1p.sv index a4ea197495..1b8ced0539 100644 --- a/shared/rtl/ram_1p.sv +++ b/shared/rtl/ram_1p.sv @@ -58,12 +58,14 @@ module ram_1p #( .MemInitFile(MemInitFile) ) u_ram ( .clk_i (clk_i), - .cfg_i ('0), + .rst_ni (rst_ni), .req_i (req_i), .write_i (we_i), - .wmask_i (wmask), .addr_i (addr_idx), .wdata_i (wdata_i), - .rdata_o (rdata_o) + .wmask_i (wmask), + .rdata_o (rdata_o), + .cfg_i ('0), + .cfg_rsp_o () ); endmodule diff --git a/shared/rtl/ram_2p.sv b/shared/rtl/ram_2p.sv index 52ff15598e..20ef1ff154 100644 --- a/shared/rtl/ram_2p.sv +++ b/shared/rtl/ram_2p.sv @@ -73,7 +73,6 @@ module ram_2p #( ) u_ram ( .clk_a_i (clk_i), .clk_b_i (clk_i), - .cfg_i ('0), .a_req_i (a_req_i), .a_write_i (a_we_i), .a_addr_i (a_addr_idx), @@ -82,10 +81,12 @@ module ram_2p #( .a_rdata_o (a_rdata_o), .b_req_i (b_req_i), .b_write_i (b_we_i), - .b_wmask_i (b_wmask), .b_addr_i (b_addr_idx), .b_wdata_i (b_wdata_i), - .b_rdata_o (b_rdata_o) + .b_wmask_i (b_wmask), + .b_rdata_o (b_rdata_o), + .cfg_i ('0), + .cfg_rsp_o () ); endmodule diff --git a/shared/sim_shared.core b/shared/sim_shared.core index 648f1942bb..a2b851f319 100644 --- a/shared/sim_shared.core +++ b/shared/sim_shared.core @@ -11,11 +11,11 @@ filesets: - lowrisc:prim:ram_1p - lowrisc:prim:ram_2p files: - - ./rtl/ram_1p.sv - - ./rtl/ram_2p.sv - - ./rtl/bus.sv - - ./rtl/sim/simulator_ctrl.sv - - ./rtl/timer.sv + - rtl/ram_1p.sv + - rtl/ram_2p.sv + - rtl/bus.sv + - rtl/sim/simulator_ctrl.sv + - rtl/timer.sv file_type: systemVerilogSource targets: diff --git a/util/check_tool_requirements.py b/util/check_tool_requirements.py index bc9e32f6e1..7281dbc24c 100755 --- a/util/check_tool_requirements.py +++ b/util/check_tool_requirements.py @@ -4,7 +4,6 @@ # SPDX-License-Identifier: Apache-2.0 import argparse -from importlib.metadata import version import logging as log import os from packaging.version import Version @@ -16,14 +15,21 @@ # Display INFO log messages and up. log.basicConfig(level=log.INFO, format="%(levelname)s: %(message)s") +try: + import importlib +except ModuleNotFoundError: + log.error("importlib cannot be found. " + "This likely means that you're using a very old version of Python. " + "Please update Python to the version defined in tool_requirements.py and retry.") + sys.exit(1) + def get_tool_requirements_path(): - '''Return the path to tool_requirements.py, at the top of the repo''' - # top_src_dir is the top of the repository - top_src_dir = os.path.normpath(os.path.join(os.path.dirname(__file__), - '..')) + '''Return the path to tool_requirements.py, in the same dir as this file''' + # tool_src_dir is the directory containing this file + tool_src_dir = os.path.normpath(os.path.join(os.path.dirname(__file__))) - return os.path.join(top_src_dir, 'tool_requirements.py') + return os.path.join(tool_src_dir, 'tool_requirements.py') class ReqErr(Exception): @@ -223,6 +229,22 @@ def to_semver(self, version, from_req): return '.'.join(m.group(1, 2, 3)) +class VivadoToolReq(ToolReq): + tool_cmd = ['vivado', '-version'] + version_regex = re.compile(r'Vivado v(.*)\s') + + def to_semver(self, version, from_req): + # Regular Vivado releases just have a major and minor version. + # Therefore, the patch number is optional + m = re.fullmatch(r'([0-9]+)\.([0-9]+)(?:\.([0-9]+))?', version) + if m is None: + raise ValueError("{} has invalid version string format." + .format(version)) + + # If there is no patch level, we set it to 0. + return '.'.join((m.group(1), m.group(2), m.group(3) or '0')) + + class VcsToolReq(ToolReq): tool_cmd = ['vcs', '-full64', '-ID'] tool_env = {'VCS_ARCH_OVERRIDE': 'linux'} @@ -260,13 +282,36 @@ def to_semver(self, version, from_req): return '{}.{}{}'.format(major, minor, comb) -class PyModuleToolReq(ToolReq): - '''A tool in a Python module (its version can be found by running pip)''' +class NinjaToolReq(ToolReq): + tool_cmd = ['ninja', '--version'] + + def to_semver(self, version, from_req): + # There exist different version string variants that we need to be + # able to parse. Some only contain the semantic version, e.g. "1.10.0", + # while others contain an additional suffix, e.g. + # "1.10.0.git.kitware.jobserver-1". To allow this trailing suffix, + # NinjaToolReq uses re.match instead of re.fullmatch. + m = re.match(r'([0-9]+)\.([0-9]+)\.([0-9]+)', version) + if m is None: + raise ValueError("{} has invalid version string format." + .format(version)) + + return '.'.join(m.group(1, 2, 3)) + + +class EdalizeToolReq(ToolReq): + '''A specialised version extractor for Edalize''' - # For Python modules, use metadata directly instead of call into pip3, which - # may not always be available for some systems. + # The upstream versions of edalize and fusesoc don't use the standard + # versioning mechanism that can be discovered through importlib.metadata. + # Instead of using that, try to import the package. Note that an error will + # be propagated to top-level, which is what we want. def get_version(self): - return version(self.tool) + try: + return importlib.import_module(self.tool + '.version').version + except ModuleNotFoundError: + raise RuntimeError(f'Unable to import {self.tool} to check version') + def dict_to_tool_req(path, tool, raw): '''Parse a dict (as read from Python) as a ToolReq @@ -305,10 +350,12 @@ def dict_to_tool_req(path, tool, raw): .format(where, ', '.join(raw.keys()))) classes = { - 'edalize': PyModuleToolReq, + 'edalize': EdalizeToolReq, 'vcs': VcsToolReq, 'verible': VeribleToolReq, - 'verilator': VerilatorToolReq + 'verilator': VerilatorToolReq, + 'vivado': VivadoToolReq, + 'ninja': NinjaToolReq } cls = classes.get(tool, ToolReq) diff --git a/tool_requirements.py b/util/tool_requirements.py similarity index 100% rename from tool_requirements.py rename to util/tool_requirements.py diff --git a/vendor/lowrisc_ip.lock.hjson b/vendor/lowrisc_ip.lock.hjson index 9c3698bbcf..799d0a5bdd 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: d268f271f4f75aeb8f3bf9624a497ae5bfb9c47e + rev: 3424e7fb4bc3ac92eb640d6af070055d293bc710 } } diff --git a/vendor/lowrisc_ip/dv/sv/common_ifs/clk_if.sv b/vendor/lowrisc_ip/dv/sv/common_ifs/clk_if.sv index 1ec154bb46..4729a5445e 100644 --- a/vendor/lowrisc_ip/dv/sv/common_ifs/clk_if.sv +++ b/vendor/lowrisc_ip/dv/sv/common_ifs/clk_if.sv @@ -16,7 +16,7 @@ interface clk_if(input logic clk); clocking cbn @(negedge clk); endclocking - // Wait for 'n' clocks based of postive clock edge + // Wait for 'n' clocks based of positive clock edge task automatic wait_clks(int num_clks); repeat (num_clks) @cb; endtask diff --git a/vendor/lowrisc_ip/dv/sv/common_ifs/clk_rst_if.sv b/vendor/lowrisc_ip/dv/sv/common_ifs/clk_rst_if.sv index 2f5c3b4082..ae99c0a4dc 100644 --- a/vendor/lowrisc_ip/dv/sv/common_ifs/clk_rst_if.sv +++ b/vendor/lowrisc_ip/dv/sv/common_ifs/clk_rst_if.sv @@ -73,7 +73,7 @@ interface clk_rst_if #( // Maximum jitter applied to each period of the clock - this is expected to be about 20% or less // than the clock period. // The jitter is divided to two values - plus-jitter and minus-jitter. - // Plus jitter is the possible time can be added to the clock period, while the minus jittter is + // Plus jitter is the possible time can be added to the clock period, while the minus jitter is // the possible time can be subtracted from the clock period. // _________ // _____:_| : : |_:_______ @@ -122,10 +122,13 @@ interface clk_rst_if #( // Wait for 'num_clks' clocks based on the positive clock edge or reset, whichever comes first. task automatic wait_clks_or_rst(int num_clks); - fork - wait_clks(num_clks); - wait_for_reset(.wait_negedge(1'b1), .wait_posedge(1'b0)); - join_any + fork begin : isolation_fork + fork + wait_clks(num_clks); + wait_for_reset(.wait_negedge(1'b1), .wait_posedge(1'b0)); + join_any + disable fork; + end join endtask // wait for rst_n to assert and then deassert @@ -257,15 +260,12 @@ interface clk_rst_if #( endtask // apply reset with specified scheme - // Note: for power on reset, please ensure pre_reset_dly_clks is set to 0 - task automatic apply_reset(int pre_reset_dly_clks = 0, - int reset_width_clks = $urandom_range(50, 100), + task automatic apply_reset(int reset_width_clks = $urandom_range(50, 100), int post_reset_dly_clks = 0, rst_scheme_e rst_n_scheme = RstAssertAsyncDeassertSync); if (drive_rst_n) begin int dly_ps; dly_ps = $urandom_range(0, clk_period_ps); - wait_clks(pre_reset_dly_clks); case (rst_n_scheme) RstAssertSyncDeassertSync: begin o_rst_n <= 1'b0; diff --git a/vendor/lowrisc_ip/dv/sv/common_ifs/entropy_subsys_fifo_exception_if.sv b/vendor/lowrisc_ip/dv/sv/common_ifs/entropy_subsys_fifo_exception_if.sv index 41cdd15b74..07dd244fcd 100644 --- a/vendor/lowrisc_ip/dv/sv/common_ifs/entropy_subsys_fifo_exception_if.sv +++ b/vendor/lowrisc_ip/dv/sv/common_ifs/entropy_subsys_fifo_exception_if.sv @@ -32,7 +32,7 @@ interface entropy_subsys_fifo_exception_if#( assign error_pulses[FIFO_WRITE_ERR] = write_err_pulse; assign error_pulses[FIFO_STATE_ERR] = state_err_pulse; - // Error conidtions map to the types of events that cause errors in the + // Error conditions map to the types of events that cause errors in the // entropy subsystem IPs assign write_forbidden = IsPackerFifo ? !wready_o : full_o; diff --git a/vendor/lowrisc_ip/dv/sv/csr_utils/README.md b/vendor/lowrisc_ip/dv/sv/csr_utils/README.md index 2652d90ba0..24c937b175 100644 --- a/vendor/lowrisc_ip/dv/sv/csr_utils/README.md +++ b/vendor/lowrisc_ip/dv/sv/csr_utils/README.md @@ -149,7 +149,7 @@ Examples of useful functions in this class are: csr_excl.add_excl({scope, ".", "key?"}, CsrExclWrite); ``` -* `has_excl`: Check if the CSR has a match in the existing exclusions loopup, +* `has_excl`: Check if the CSR has a match in the existing exclusions lookup, and is not intended to use externally ### CSR sequence framework 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 1ef67731c0..8fab5f42e6 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 @@ -2,8 +2,8 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -// CSR suite of sequences that do writes and reads to csrs -// includes hw_reset, rw, bit_bash and aliasing tests for csrs, and mem_walk for uvm_mems +// CSR suite of sequences that do writes and reads to CSRs +// includes hw_reset, rw, bit_bash and aliasing tests for CSRs, and mem_walk for uvm_mems // The sequences perform csr writes and reads and follow the standard csr test suite. If external // checker is enabled, then the external entity is required to update the mirrored value on // writes. If not enabled, the sequences themselves call predict function to update the mirrored @@ -12,10 +12,10 @@ // register and field access policies. Also, we use csr_rd_check task instead of csr_mirror to take // field exclusions into account. // -// Csrs to be tested is accumulated and shuffled from the supplied reg models. -// What / how many csrs to test can be further controlled in 3 ways - -// 1. Externally add specific csrs to test_csrs queue (highest prio) -// 2. Set num_test_csrs test a randomly picked set of csrs from the supplied models +// CSRs to be tested is accumulated and shuffled from the supplied reg models. +// What / how many CSRs to test can be further controlled in 3 ways - +// 1. Externally add specific CSRs to test_csrs queue (highest prio) +// 2. Set num_test_csrs test a randomly picked set of CSRs from the supplied models // 3. Set / pass via plusarg, num_csr_chunks / test_csr_chunk // // Exclusions are to be provided using the csr_excl_item item (see class for more details). @@ -33,7 +33,7 @@ class csr_base_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item)); // In either case, we should be able to do completely non-blocking writes and reads. bit external_checker = 1'b0; - // either use num_test_csrs or {test_csr_chunk, num_csr_chunks} to test slice of all csrs + // either use num_test_csrs or {test_csr_chunk, num_csr_chunks} to test slice of all CSRs int num_test_csrs = 0; int test_csr_chunk = 1; int num_csr_chunks = 1; @@ -88,14 +88,14 @@ class csr_base_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item)); end_idx = test_csr_chunk * chunk_size; if (end_idx >= all_csrs.size()) end_idx = all_csrs.size() - 1; - `uvm_info(`gtn, $sformatf("Testing %0d csrs [%0d - %0d] in all supplied models.", - test_csrs.size(), start_idx, end_idx), UVM_MEDIUM) test_csrs.delete(); for (int i = start_idx; i <= end_idx; i++) begin test_csrs.push_back(all_csrs[i]); `uvm_info(`gtn, $sformatf("Testing CSR %0s, reset: 0x%0x.", all_csrs[i].get_full_name(), all_csrs[i].get_mirrored_value()), UVM_HIGH) end + `uvm_info(`gtn, $sformatf("Testing %0d csrs [%0d - %0d] in all supplied models.", + test_csrs.size(), start_idx, end_idx), UVM_MEDIUM) test_csrs.shuffle(); endfunction @@ -350,78 +350,97 @@ class csr_bit_bash_seq extends csr_base_seq; continue; end - begin - uvm_reg_field fields[$]; - string mode[`UVM_REG_DATA_WIDTH]; - uvm_reg_data_t dc_mask; // dont write or read - uvm_reg_data_t cmp_mask; // read but dont compare - int n_bits; - string field_access; - int next_lsb; - - n_bits = test_csrs[i].get_n_bytes() * 8; - - // Let's see what kind of bits we have... - test_csrs[i].get_fields(fields); - - next_lsb = 0; - dc_mask = 0; - cmp_mask = 0; - - foreach (fields[j]) begin - int lsb, w, dc, cmp; - - field_access = fields[j].get_access(test_csrs[i].get_default_map()); - cmp = (fields[j].get_compare() == UVM_NO_CHECK); - lsb = fields[j].get_lsb_pos(); - w = fields[j].get_n_bits(); - - // Exclude write-only fields from compare because you are not supposed to read them - case (field_access) - "WO", "WOC", "WOS", "WO1", "NOACCESS", "": cmp = 1; - endcase - - // skip fields that are wr-excluded - if (is_excl(fields[j], CsrExclWrite, CsrBitBashTest)) begin - `uvm_info(`gtn, $sformatf("Skipping field %0s due to CsrExclWrite exclusion", - fields[j].get_full_name()), UVM_MEDIUM) - dc = 1; - end + bash_register(test_csrs[i]); + end - // ignore fields that are init or rd-excluded - cmp = is_excl(fields[j], CsrExclInitCheck, CsrBitBashTest) || - is_excl(fields[j], CsrExclWriteCheck, CsrBitBashTest) ; + endtask - // Any unused bits on the right side of the LSB? - while (next_lsb < lsb) mode[next_lsb++] = "RO"; + // Run bit bash test on the given register. + // + // The basic idea is that we test each bit of the register with the bash_kth_bit task, checking + // that we can set and clear the register as expected. This task takes field exclusions and + // read/write masks into account when calculating how to run the bash_kth_bit task across the + // register. + virtual task bash_register(uvm_reg csr); + uvm_reg_field fields[$]; + string mode[`UVM_REG_DATA_WIDTH]; + uvm_reg_data_t dc_mask; // dont write or read + uvm_reg_data_t no_cmp_mask; // read but dont compare + int n_bits; + string field_access; + int next_lsb; + + n_bits = csr.get_n_bytes() * 8; + + // Let's see what kind of bits we have... + csr.get_fields(fields); + + next_lsb = 0; + dc_mask = 0; + no_cmp_mask = 0; + + foreach (fields[j]) begin + int lsb, w, dc, no_cmp; + + field_access = fields[j].get_access(csr.get_default_map()); + no_cmp = (fields[j].get_compare() == UVM_NO_CHECK); + lsb = fields[j].get_lsb_pos(); + w = fields[j].get_n_bits(); + + // Exclude write-only fields from compare because you are not supposed to read them + case (field_access) + "WO", "WOC", "WOS", "WO1", "NOACCESS", "": no_cmp = 1; + default: no_cmp = 0; + endcase + + // skip fields that are wr-excluded + if (is_excl(fields[j], CsrExclWrite, CsrBitBashTest)) begin + `uvm_info(`gtn, $sformatf("Skipping field %0s due to CsrExclWrite exclusion", + fields[j].get_full_name()), UVM_MEDIUM) + dc = 1; + end - repeat (w) begin - mode[next_lsb] = field_access; - dc_mask[next_lsb] = dc; - cmp_mask[next_lsb] = cmp; - next_lsb++; - end - end + // ignore fields that are init or rd-excluded + no_cmp = is_excl(fields[j], CsrExclInitCheck, CsrBitBashTest) || + is_excl(fields[j], CsrExclWriteCheck, CsrBitBashTest) ; - // Any unused bits on the left side of the MSB? - while (next_lsb < `UVM_REG_DATA_WIDTH) - mode[next_lsb++] = "RO"; + // Any unused bits below the LSB of this field? + while (next_lsb < lsb) mode[next_lsb++] = "RO"; - // Bash the kth bit - for (int k = 0; k < n_bits; k++) begin - // Cannot test unpredictable bit behavior - if (dc_mask[k]) continue; - bash_kth_bit(test_csrs[i], k, mode[k], cmp_mask); - end + repeat (w) begin + mode[next_lsb] = field_access; + dc_mask[next_lsb] = dc; + no_cmp_mask[next_lsb] = no_cmp; + next_lsb++; end end + // Any unused bits above the top field, but that we will still look at with bash_kth_bit? + while (next_lsb < n_bits) begin + mode[next_lsb++] = "RO"; + end + + // Bash the kth bit + for (int k = 0; k < n_bits; k++) begin + // Cannot test unpredictable bit behavior + if (dc_mask[k]) continue; + bash_kth_bit(csr, k, mode[k], no_cmp_mask); + end endtask - task bash_kth_bit(uvm_reg rg, - int k, - string mode, - uvm_reg_data_t mask); + // A bit bashing sequence for bit k of register rg. + // + // This works by writing the bit as one value and reading it back, then writing the other value + // and reading that back, checking that each write sets the value as expected. + // + // The mask argument gives bits that won't be compared when reading the value back. Note that this + // task is still worth running even if the k'th bit of mask is set: it might be that writes to + // that bit of the register mess up other bits/fields in the register, and this task will spot if + // that happens. + task bash_kth_bit(uvm_reg rg, + int k, + string mode, + uvm_reg_data_t mask); uvm_reg_data_t val; string err_msg; @@ -468,8 +487,10 @@ class csr_aliasing_seq extends csr_base_seq; continue; end - `uvm_info(`gtn, $sformatf("Verifying register aliasing for %0s", - test_csrs[i].get_full_name()), UVM_MEDIUM) + `uvm_info(`gtn, + $sformatf("Verifying register aliasing for %0s (register %0d / %0d)", + test_csrs[i].get_full_name(), i + 1, test_csrs.size()), + UVM_MEDIUM) `DV_CHECK_STD_RANDOMIZE_FATAL(wdata) wdata = get_csr_wdata_with_write_excl(test_csrs[i], wdata, CsrAliasingTest); @@ -488,7 +509,7 @@ class csr_aliasing_seq extends csr_base_seq; if (is_excl(all_csrs[j], CsrExclInitCheck, CsrAliasingTest) || is_excl(all_csrs[j], CsrExclWriteCheck, CsrAliasingTest)) begin `uvm_info(`gtn, $sformatf("Skipping register %0s due to CsrExclInit/WriteCheck exclusion", - all_csrs[j].get_full_name()), UVM_MEDIUM) + all_csrs[j].get_full_name()), UVM_HIGH) continue; end 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 94ce5d15c8..d4ed0800a7 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 @@ -17,7 +17,6 @@ package csr_utils_pkg; uint outstanding_accesses = 0; uint default_timeout_ns = 2_000_000; // 2ms 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; @@ -26,14 +25,12 @@ package csr_utils_pkg; function automatic void increment_outstanding_access(); outstanding_accesses++; - `uvm_info("csr_utils_pkg", $sformatf("increment_outstanding_access %0d", outstanding_accesses), - UVM_HIGH) + `uvm_info($sformatf("%m"), $sformatf("%0d", outstanding_accesses), UVM_HIGH) endfunction function automatic void decrement_outstanding_access(); outstanding_accesses--; - `uvm_info("csr_utils_pkg", $sformatf("decrement_outstanding_access %0d", outstanding_accesses), - UVM_HIGH) + `uvm_info($sformatf("%m"), $sformatf("%0d", outstanding_accesses), UVM_HIGH) endfunction task automatic wait_no_outstanding_access(); @@ -67,7 +64,8 @@ package csr_utils_pkg; uvm_mem mem; addr[1:0] = 0; mem = ral.default_map.get_mem_by_offset(addr); - `DV_CHECK_NE_FATAL(mem, null, $sformatf("Can't find any mem with addr 0x%0h", addr), msg_id) + `DV_CHECK_NE_FATAL(mem, null, + $sformatf("Can't find any mem with addr 0x%0h", addr), $sformatf("%m")) return mem; endfunction @@ -84,13 +82,12 @@ package csr_utils_pkg; uvm_reg csr; uvm_reg_field fld; uvm_reg_data_t result; - string msg_id = {csr_utils_pkg::msg_id, "::get_reg_fld_mirror_value"}; csr = ral.get_reg_by_name(reg_name); - `DV_CHECK_NE_FATAL(csr, null, "", msg_id) + `DV_CHECK_NE_FATAL(csr, null, "", $sformatf("%m")) // return field mirror value if field_name is passed, else return reg mirror value if (field_name != "") begin fld = csr.get_field_by_name(field_name); - `DV_CHECK_NE_FATAL(fld, null, "", msg_id) + `DV_CHECK_NE_FATAL(fld, null, "", $sformatf("%m")) result = fld.get_mirrored_value(); end else begin @@ -111,11 +108,11 @@ package csr_utils_pkg; // wait until current csr op is complete task automatic csr_wait(input uvm_reg csr); - `uvm_info(msg_id, $sformatf("%0s: wait_busy: %0b", - csr.get_full_name(), csr.m_is_busy), UVM_HIGH) + `uvm_info($sformatf("%m"), $sformatf("%0s: wait_busy: %0b", + csr.get_full_name(), csr.m_is_busy), UVM_HIGH) wait(csr.m_is_busy == 1'b0); - `uvm_info(msg_id, $sformatf("%0s: done wait_busy: %0b", - csr.get_full_name(), csr.m_is_busy), UVM_HIGH) + `uvm_info($sformatf("%m"), $sformatf("%0s: done wait_busy: %0b", + csr.get_full_name(), csr.m_is_busy), UVM_HIGH) endtask // Use `csr_wr` to construct `csr_update` to avoid replicated codes to handle nonblocking, @@ -196,12 +193,10 @@ package csr_utils_pkg; input bit en_shadow_wr = 1); fork begin : isolation_fork - string msg_id = {csr_utils_pkg::msg_id, "::csr_wr"}; - fork begin dv_base_reg dv_reg; - `downcast(dv_reg, csr, "", fatal, msg_id) + `downcast(dv_reg, csr, "", fatal, $sformatf("%m")) increment_outstanding_access(); csr_pre_write_sub(csr, en_shadow_wr); @@ -217,7 +212,7 @@ package csr_utils_pkg; decrement_outstanding_access(); end begin - `DV_WAIT_TIMEOUT(timeout_ns, msg_id, + `DV_WAIT_TIMEOUT(timeout_ns, $sformatf("%m"), $sformatf("Timeout waiting to csr_wr %0s (addr=0x%0h)", csr.get_full_name(), csr.get_address())) end @@ -246,7 +241,7 @@ package csr_utils_pkg; if (check == UVM_CHECK) begin `DV_CHECK_EQ(status, UVM_IS_OK, $sformatf("trying to write csr %0s", csr.get_full_name()), - error, msg_id) + error, $sformatf("%m")) 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) @@ -257,7 +252,7 @@ package csr_utils_pkg; task automatic csr_pre_write_sub(uvm_reg csr, bit en_shadow_wr); dv_base_reg dv_reg; - `downcast(dv_reg, csr, "", fatal, msg_id) + `downcast(dv_reg, csr, "", fatal, $sformatf("%m")) if (dv_reg.get_is_shadowed() && en_shadow_wr) begin dv_reg.atomic_en_shadow_wr.get(1); end @@ -265,7 +260,7 @@ package csr_utils_pkg; task automatic csr_post_write_sub(uvm_reg csr, bit en_shadow_wr); dv_base_reg dv_reg; - `downcast(dv_reg, csr, "", fatal, msg_id) + `downcast(dv_reg, csr, "", fatal, $sformatf("%m")) if (dv_reg.get_is_shadowed() && en_shadow_wr) begin dv_reg.atomic_en_shadow_wr.put(1); end @@ -279,7 +274,6 @@ package csr_utils_pkg; input bkdr_reg_path_e kind = BkdrRegPathRtl); csr_field_t csr_or_fld = decode_csr_or_field(ptr); uvm_status_e status; - string msg_id = {csr_utils_pkg::msg_id, "::csr_poke"}; uvm_reg_data_t old_mirrored_val; if (csr_or_fld.field != null) begin @@ -294,8 +288,8 @@ package csr_utils_pkg; uvm_hdl_path_concat paths[$]; csr_or_fld.csr.get_full_hdl_path(paths, kind.name); foreach (paths[0].slices[i]) str = $sformatf("%0s\n%0s", str, paths[0].slices[i].path); - `uvm_fatal(msg_id, $sformatf("poke failed for %0s, check below paths %0s", - ptr.get_full_name(), str)) + `uvm_fatal($sformatf("%m"), $sformatf("poke failed for %0s, check below paths %0s", + ptr.get_full_name(), str)) end // poke always updates predict value, if predict == 0, revert back to old mirrored value if (!predict || kind == BkdrRegPathRtlShadow) begin @@ -323,7 +317,7 @@ package csr_utils_pkg; csr_rd_sub(.ptr(ptr), .value(value), .status(status), .check(check), .path(path), .backdoor(backdoor), .timeout_ns(timeout_ns), .map(map), .user_ftdr(user_ftdr)); end else begin - `DV_CHECK_EQ(backdoor, 0, "Don't enable backdoor with blocking = 0", error, msg_id) + `DV_CHECK_EQ(backdoor, 0, "Don't enable backdoor with blocking = 0", error, $sformatf("%m")) fork csr_rd_sub(.ptr(ptr), .value(value), .status(status), .check(check), .path(path), .backdoor(backdoor), .timeout_ns(timeout_ns), .map(map), .user_ftdr(user_ftdr)); @@ -351,8 +345,6 @@ package csr_utils_pkg; fork begin : isolation_fork csr_field_t csr_or_fld; - string msg_id = {csr_utils_pkg::msg_id, "::csr_rd"}; - fork begin increment_outstanding_access(); @@ -370,12 +362,12 @@ package csr_utils_pkg; if (check == UVM_CHECK && !under_reset) begin `DV_CHECK_EQ(status, UVM_IS_OK, $sformatf("trying to read csr/field %0s", ptr.get_full_name()), - error, msg_id) + error, $sformatf("%m")) end decrement_outstanding_access(); end begin - `DV_WAIT_TIMEOUT(timeout_ns, msg_id, + `DV_WAIT_TIMEOUT(timeout_ns, $sformatf("%m"), $sformatf("Timeout waiting to csr_rd %0s (addr=0x%0h)", ptr.get_full_name(), csr_or_fld.csr.get_address())) end @@ -390,7 +382,6 @@ package csr_utils_pkg; function automatic uvm_reg_data_t csr_peek(uvm_object ptr, uvm_check_e check = default_csr_check, 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; uvm_reg_data_t value = 0; @@ -401,15 +392,15 @@ package csr_utils_pkg; `DV_CHECK_FATAL(paths.size() > 0, $sformatf("No backdoor defined for %0s path's %0s", csr.get_full_name(), kind.name), - msg_id) + $sformatf("%m")) foreach (paths[0].slices[i]) begin uvm_reg_data_t field_val; `DV_CHECK_FATAL(uvm_hdl_read(paths[0].slices[i].path, field_val), $sformatf("Failed to read %s, slice %d, at path %s", csr.get_full_name(), i, paths[0].slices[i].path), - msg_id) - if (check == UVM_CHECK) `DV_CHECK_EQ($isunknown(field_val), 0, "", error, msg_id) + $sformatf("%m")) + if (check == UVM_CHECK) `DV_CHECK_EQ($isunknown(field_val), 0, "", error, $sformatf("%m")) value |= field_val << paths[0].slices[i].offset; end @@ -444,7 +435,6 @@ package csr_utils_pkg; uvm_reg_data_t obs; uvm_reg_data_t exp; uvm_reg_data_t reset_val; - string msg_id = {csr_utils_pkg::msg_id, "::csr_rd_check"}; csr_or_fld = decode_csr_or_field(ptr); @@ -465,7 +455,7 @@ package csr_utils_pkg; exp = (compare_vs_ral ? exp : compare_value) & compare_mask; `DV_CHECK_EQ(obs, exp, $sformatf("Regname: %0s reset value: 0x%0h %0s", ptr.get_full_name(), reset_val, err_msg), - error, msg_id) + error, $sformatf("%m")) end end join_none @@ -500,8 +490,9 @@ package csr_utils_pkg; // 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) + `uvm_info($sformatf("%m"), + $sformatf("Skipping register %0s due to CsrExclWriteCheck exclusion", + csr.get_full_name()), UVM_MEDIUM) return; end @@ -530,7 +521,20 @@ package csr_utils_pkg; end endtask - // poll a csr or csr field continuously until it reads the expected value. + // Poll a csr or csr field continuously until its value is as expected. + // + // The CSR or field is polled by performing reads at the given ptr and its current value is + // compared with exp_data using the comparison in compare_op. The task exits when the comparison + // becomes true. + // + // To avoid this task waiting forever, there is an upper bound given with timeout_ns. If the task + // does not finish for another reason in that time, the test will fail. + // + // CSR reads are performed using frontdoor access. If the backdoor argument is true, then they + // will be performed with a backdoor access instead. + // + // Successive CSR reads are back-to-back unless spinwait_delay_ns is positive. If backdoor is + // true, the delay between successive reads is made to be at least 1ns. task automatic csr_spinwait(input uvm_object ptr, input uvm_reg_data_t exp_data, input uvm_check_e check = default_csr_check, @@ -542,22 +546,55 @@ package csr_utils_pkg; input compare_op_e compare_op = CompareOpEq, input bit backdoor = 0, input uvm_verbosity verbosity = UVM_HIGH); + static int count; + automatic int lcount; + + // Increment count so that each call to csr_spinwait has a different index (to help debugging) + count++; + + // Take an (automatic) copy of lcount. This will act as a snapshot of the value that the count + // had when this task started, giving the index of *this* call. + lcount = count; + + `uvm_info($sformatf("%m"), $sformatf( + "- (call_count=%0d, backdoor=%0d, exp_data=%0d, ptr=%s)", + lcount, backdoor, exp_data, ptr.get_name()), verbosity) fork begin : isolation_fork csr_field_t csr_or_fld; uvm_reg_data_t read_data; - string msg_id = {csr_utils_pkg::msg_id, "::csr_spinwait"}; csr_or_fld = decode_csr_or_field(ptr); if (backdoor && spinwait_delay_ns == 0) spinwait_delay_ns = 1; fork - while (!under_reset) begin - if (spinwait_delay_ns) #(spinwait_delay_ns * 1ns); - `uvm_info("csr_utils_pkg", "In csr_spinwait", verbosity) + // Repeatedly do reads of the value at path and stop when the value satisfies the supplied + // comparison. If it is positive, wait spinwait_delay_ns nanoseconds between reads. If we + // enter reset, stop immediately (once the current csr_rd call has finished). + forever begin + `uvm_info($sformatf("%m"), $sformatf("In csr_spinwait - call_count = %0d", lcount), + verbosity) + + // Wait spinwait_delay_ns nanoseconds between each read (and before the first one), but + // stop waiting immediately if we see a reset. Note that we can't wait for a reset in + // parallel with the csr_rd below, because we use disable fork when a process finishes + // and csr_rd has internal state that it must clean up without being killed. + if (spinwait_delay_ns) begin + fork begin : iso_fork + fork + #(spinwait_delay_ns * 1ns); + wait (under_reset); + join_any + disable fork; + end : iso_fork join + end + + // If we are in reset, stop the wait immediately. + if (under_reset) break; + csr_rd(.ptr(ptr), .value(read_data), .check(check), .path(path), .blocking(1), .map(map), .user_ftdr(user_ftdr), .backdoor(backdoor)); - `uvm_info(msg_id, $sformatf("ptr %0s == 0x%0h", - ptr.get_full_name(), read_data), verbosity) + `uvm_info($sformatf("%m"), + $sformatf("ptr %0s == 0x%0h", ptr.get_full_name(), read_data), verbosity) case (compare_op) CompareOpEq: if (read_data == exp_data) break; CompareOpCaseEq: if (read_data === exp_data) break; @@ -572,10 +609,13 @@ package csr_utils_pkg; end endcase end - begin - `DV_WAIT_TIMEOUT(timeout_ns, msg_id, $sformatf("timeout %0s (addr=0x%0h) == 0x%0h", - ptr.get_full_name(), csr_or_fld.csr.get_address(), exp_data)) - end + // Wait for timeout_ns nanoseconds and then fail with an error (because this process + // should have been killed before then) + `DV_WAIT_TIMEOUT(timeout_ns, $sformatf("%m"), + $sformatf({"timeout %0s (addr=0x%0h, Comparison=%s, ", + "exp_data=0x%0h, call_count=%0d)"}, + ptr.get_full_name(), csr_or_fld.csr.get_address(), + compare_op.name, exp_data, lcount)) join_any disable fork; end : isolation_fork @@ -611,7 +651,6 @@ package csr_utils_pkg; fork begin : isolating_fork uvm_status_e status; - string msg_id = {csr_utils_pkg::msg_id, "::mem_rd"}; fork begin @@ -622,12 +661,13 @@ package csr_utils_pkg; // but this doesn't work: if (user_ftdr != null) ptr.set_frontdoor(null); if (check == UVM_CHECK && !under_reset) begin `DV_CHECK_EQ(status, UVM_IS_OK, - $sformatf("trying to read mem %0s", ptr.get_full_name()), error, msg_id) + $sformatf("trying to read mem %0s", ptr.get_full_name()), + error, $sformatf("%m")) end decrement_outstanding_access(); end begin : mem_rd_timeout - `DV_WAIT_TIMEOUT(timeout_ns, msg_id, + `DV_WAIT_TIMEOUT(timeout_ns, $sformatf("%m"), $sformatf("Timeout waiting to mem_rd %0s (addr=0x%0h)", ptr.get_full_name(), offset)) end @@ -666,7 +706,6 @@ package csr_utils_pkg; fork begin : isolation_fork uvm_status_e status; - string msg_id = {csr_utils_pkg::msg_id, "::mem_wr"}; fork begin @@ -678,12 +717,12 @@ package csr_utils_pkg; if (check == UVM_CHECK && !under_reset) begin `DV_CHECK_EQ(status, UVM_IS_OK, $sformatf("trying to write mem %0s", ptr.get_full_name()), - error, msg_id) + error, $sformatf("%m")) end decrement_outstanding_access(); end begin - `DV_WAIT_TIMEOUT(timeout_ns, msg_id, + `DV_WAIT_TIMEOUT(timeout_ns, $sformatf("%m"), $sformatf("Timeout waiting to mem_wr %0s (addr=0x%0h)", ptr.get_full_name(), offset)) end @@ -707,8 +746,8 @@ package csr_utils_pkg; 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) + `uvm_info($sformatf("%m"), $sformatf("Skipping field %0s due to %0s exclusion", + flds[i].get_full_name(), csr_excl_type.name()), UVM_HIGH) get_mask_excl_fields &= ~(fld_params.mask << fld_params.shift); end end @@ -730,9 +769,9 @@ package csr_utils_pkg; foreach (flds[i]) begin if (m_csr_excl_item.is_excl(flds[i], CsrExclWrite, csr_test_type)) begin - `uvm_info(msg_id, $sformatf( - "Retain mirrored value 0x%0h for field %0s due to CsrExclWrite exclusion", - `gmv(flds[i]), flds[i].get_full_name()), UVM_MEDIUM) + `uvm_info($sformatf("%m"), + $sformatf("Retain mirrored 0x%0h for field %0s due to CsrExclWrite exclusion", + `gmv(flds[i]), flds[i].get_full_name()), UVM_MEDIUM) wdata = get_csr_val_with_updated_field(flds[i], wdata, `gmv(flds[i])); end end @@ -743,21 +782,21 @@ package csr_utils_pkg; // // If an exclusion item for the immediate block (parent of the CSR if ptr is a CSR or a field) is // not found, it recurses through the block's ancestors to find an available exclusion item. - // arg ptr: An extention of one of dv_base_reg{, _block or _field} classes. + // arg ptr: An extension of one of dv_base_reg{, _block or _field} classes. function automatic csr_excl_item get_excl_item(uvm_object ptr); dv_base_reg_block blk; // Attempt cast to blk. If it fails, then attempt to cast to CSR or field. if (!$cast(blk, ptr)) begin csr_field_t csr_or_fld = decode_csr_or_field(ptr); - `downcast(blk, csr_or_fld.csr.get_parent(), , , msg_id) + `downcast(blk, csr_or_fld.csr.get_parent(), , , $sformatf("%m")) end // Recurse through block's ancestors. do begin csr_excl_item csr_excl = blk.get_excl_item(); if (csr_excl != null) return csr_excl; - `downcast(blk, blk.get_parent(), , , msg_id) + `downcast(blk, blk.get_parent(), , , $sformatf("%m")) end while (blk != null); return null; endfunction diff --git a/vendor/lowrisc_ip/dv/sv/dv_base_reg/csr_excl_item.sv b/vendor/lowrisc_ip/dv/sv/dv_base_reg/csr_excl_item.sv index fa6f57774c..49847a9856 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_base_reg/csr_excl_item.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_base_reg/csr_excl_item.sv @@ -83,7 +83,7 @@ class csr_excl_item extends uvm_object; end else begin if (has_excl(csr_or_fld.csr.`gfn, csr_excl_type, csr_test_type, is_excl)) return is_excl; end - `downcast(blk, csr_or_fld.csr.get_parent(), , , msg_id) + `downcast(blk, csr_or_fld.csr.get_parent(), , , `gfn) end // Recurse through block's ancestors. diff --git a/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_mem.sv b/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_mem.sv index 631c457bd7..d32f6c5f26 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_mem.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_mem.sv @@ -1,12 +1,10 @@ // Copyright lowRISC contributors (OpenTitan project). // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -// + // base register reg class which will be used to generate the reg mem -class dv_base_mem extends uvm_mem; - // uvm_mem::m_access is local variable. Create it again in order to use "access" in current class - local string m_access; +class dv_base_mem extends uvm_mem; // if mem doesn't support partial write, doing that will result d_error = 1 local bit mem_partial_write_support; @@ -20,75 +18,98 @@ class dv_base_mem extends uvm_mem; // data integrity local bit data_intg_passthru; - function new(string name, - longint unsigned size, - int unsigned n_bits, - string access = "RW", - int has_coverage = UVM_NO_COVERAGE); - super.new(name, size, n_bits, access, has_coverage); - m_access = access; - endfunction : new + // Create a new instance of the memory abstraction class. + // + // The only access types supported are RW, RO and WO. + extern function new(string name, + longint unsigned size, + int unsigned n_bits, + string access = "RW", + int has_coverage = UVM_NO_COVERAGE); - function void set_mem_partial_write_support(bit enable); - mem_partial_write_support = enable; - endfunction : set_mem_partial_write_support + extern function void set_mem_partial_write_support(bit enable); + extern function bit get_mem_partial_write_support(); - function bit get_mem_partial_write_support(); - return mem_partial_write_support; - endfunction : get_mem_partial_write_support + extern function void set_data_intg_passthru(bit enable); + extern function bit get_data_intg_passthru(); - function void set_data_intg_passthru(bit enable); - data_intg_passthru = enable; - endfunction : set_data_intg_passthru + extern function void set_write_to_ro_mem_ok(bit ok); + extern function bit get_write_to_ro_mem_ok(); - function bit get_data_intg_passthru(); - return data_intg_passthru; - endfunction : get_data_intg_passthru + extern function void set_read_to_wo_mem_ok(bit ok); + extern function bit get_read_to_wo_mem_ok(); - function void set_write_to_ro_mem_ok(bit ok); - write_to_ro_mem_ok = ok; - endfunction + // This overrides uvm_mem::configure (which is *not* a virtual function), removing the check that + // the requested "access" is RW or RO, because we want to support WO as well. + // + // *That* check is now done in the constructor, where we can see the requested "access". + extern function void configure(uvm_reg_block parent, string hdl_path=""); +endclass - function bit get_write_to_ro_mem_ok(); - return write_to_ro_mem_ok; - endfunction +function dv_base_mem::new(string name, + longint unsigned size, + int unsigned n_bits, + string access = "RW", + int has_coverage = UVM_NO_COVERAGE); + super.new(name, size, n_bits, access, has_coverage); + if (!(access inside {"RW", "RO", "WO"})) + `uvm_error(`gfn, $sformatf("Memory can only be RW, RO or WO (saw %s)", access)) +endfunction - function void set_read_to_wo_mem_ok(bit ok); - read_to_wo_mem_ok = ok; - endfunction +function void dv_base_mem::set_mem_partial_write_support(bit enable); + mem_partial_write_support = enable; +endfunction - function bit get_read_to_wo_mem_ok(); - return read_to_wo_mem_ok; - endfunction +function bit dv_base_mem::get_mem_partial_write_support(); + return mem_partial_write_support; +endfunction - // rewrite this function to support "WO" access type for mem - function void configure(uvm_reg_block parent, - string hdl_path=""); - if (parent == null) - `uvm_fatal("REG/NULL_PARENT","configure: parent argument is null") +function void dv_base_mem::set_data_intg_passthru(bit enable); + data_intg_passthru = enable; +endfunction - set_parent(parent); +function bit dv_base_mem::get_data_intg_passthru(); + return data_intg_passthru; +endfunction - if (!(m_access inside {"RW", "RO", "WO"})) begin - `uvm_error("RegModel", {"Memory '",get_full_name(),"' can only be RW, RO or WO"}) - end +function void dv_base_mem::set_write_to_ro_mem_ok(bit ok); + write_to_ro_mem_ok = ok; +endfunction - begin - uvm_mem_mam_cfg cfg = new; +function bit dv_base_mem::get_write_to_ro_mem_ok(); + return write_to_ro_mem_ok; +endfunction - cfg.n_bytes = ((get_n_bits() - 1) / 8) + 1; - cfg.start_offset = 0; - cfg.end_offset = get_size() - 1; +function void dv_base_mem::set_read_to_wo_mem_ok(bit ok); + read_to_wo_mem_ok = ok; +endfunction - cfg.mode = uvm_mem_mam::GREEDY; - cfg.locality = uvm_mem_mam::BROAD; +function bit dv_base_mem::get_read_to_wo_mem_ok(); + return read_to_wo_mem_ok; +endfunction - mam = new(get_full_name(), cfg, this); - end +// Note: This is a copied version of uvm_mem::configure, but tweaked to remove the check on m_access +// (loosened slightly and now moved to the constructor) +function void dv_base_mem::configure(uvm_reg_block parent, string hdl_path=""); + if (parent == null) + `uvm_fatal(`gfn, "configure: parent argument is null") - parent.add_mem(this); + set_parent(parent); - if (hdl_path != "") add_hdl_path_slice(hdl_path, -1, -1); - endfunction: configure + begin + uvm_mem_mam_cfg cfg = new; -endclass + cfg.n_bytes = ((get_n_bits() - 1) / 8) + 1; + cfg.start_offset = 0; + cfg.end_offset = get_size() - 1; + + cfg.mode = uvm_mem_mam::GREEDY; + cfg.locality = uvm_mem_mam::BROAD; + + mam = new(get_full_name(), cfg, this); + end + + parent.add_mem(this); + + if (hdl_path != "") add_hdl_path_slice(hdl_path, -1, -1); +endfunction diff --git a/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_mubi_cov.sv b/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_mubi_cov.sv index 2cbe9fe55d..ffce1ef7a2 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_mubi_cov.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_mubi_cov.sv @@ -30,6 +30,36 @@ class mubi_cov #(parameter int Width = 4, endfunction : sample endclass : mubi_cov +// TODO(#24142): This is a bit silly: it's just mubi_cov above, specialised to Width=32. But that +// doesn't work properly with VCS (tried with version 2023.03) because it ends up creating an +// enormous number of bins. Setting an explicit width here works around the problem. Fix this up +// properly if we change tool version. +class mubi32_cov extends uvm_object; + `uvm_object_param_utils(mubi32_cov) + + // Collect true, false and at least N other values (N = 32) + covergroup mubi_cg(string name) with function sample(bit [32-1:0] value); + option.per_instance = 1; + option.name = name; + + cp_value: coverpoint value { + bins true = {prim_mubi_pkg::MuBi32True}; + bins false = {prim_mubi_pkg::MuBi32False}; + bins others[32] = {[0:{32{1'b1}}]} with (!(item inside {prim_mubi_pkg::MuBi32True, + prim_mubi_pkg::MuBi32False})); + } + endgroup : mubi_cg + + // use reg_field name as this name + function new(string name = ""); + mubi_cg = new($sformatf("mubi%0d_cov_of_%s", 32, name)); + endfunction : new + + virtual function void sample(bit [32-1:0] value); + mubi_cg.sample(value); + endfunction : sample +endclass + typedef mubi_cov #(.Width(4), .ValueTrue(prim_mubi_pkg::MuBi4True), .ValueFalse(prim_mubi_pkg::MuBi4False)) mubi4_cov; @@ -51,9 +81,6 @@ typedef mubi_cov #(.Width(24), typedef mubi_cov #(.Width(28), .ValueTrue(prim_mubi_pkg::MuBi28True), .ValueFalse(prim_mubi_pkg::MuBi28False)) mubi28_cov; -typedef mubi_cov #(.Width(32), - .ValueTrue(prim_mubi_pkg::MuBi32True), - .ValueFalse(prim_mubi_pkg::MuBi32False)) mubi32_cov; // a mubi coverage object, which allows to dynamically select the width of mubi class dv_base_mubi_cov extends uvm_object; 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 f25f6abd1b..e3dc21234c 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 @@ -19,6 +19,13 @@ class dv_base_reg extends uvm_reg; local string update_err_alert_name; local string storage_err_alert_name; + // This should be set if the register can be affected by a write even if that write also causes an + // error (because of an invalid mask, for example). + // + // TODO: This is really here as a workaround for a minor RTL bug, tracked in issue #24053. Once + // that issue is closed, remove this flag again. + bit writes_ignore_errors; + // This is used for get_alias_name string alias_name = ""; // Lookup table for alias fields (used for get_field_by_name) @@ -28,11 +35,25 @@ class dv_base_reg extends uvm_reg; // through the 1st/2nd (or both) writes semaphore atomic_en_shadow_wr; + // A semaphore that's used to control processes that wish to write to the register (using + // uvm_reg::write). This was originally a workaround for a rather silly UVM bug that was only + // fixed in version 2020-2.0. It caused multiple processes to collide in a critical section if + // more than two are trying to write a register at once. + // + // Note that this semaphore controls reads as well as writes, because both operations use the + // m_is_busy flag. + // + // However, the lock is also useful if a process wishes to use predict(), in which case the + // m_is_busy flag should be false. To allow sequences to do that safely, the take_lock and + // release_lock methods that control this lock are not local. + local semaphore access_lock; + function new(string name = "", int unsigned n_bits, int has_coverage); super.new(name, n_bits, has_coverage); atomic_en_shadow_wr = new(1); + access_lock = new(1); endfunction : new // Create this register and its fields' IP-specific functional coverage. @@ -66,6 +87,21 @@ class dv_base_reg extends uvm_reg; `downcast(get_dv_base_reg_block, get_parent()) endfunction + function uvm_reg_data_t get_predicted_mask(); + uvm_reg_data_t mask = 0; + dv_base_reg_field fields_q[$]; + this.get_dv_base_reg_fields(fields_q); + + foreach (fields_q[i]) begin + if (fields_q[i].has_prediction) begin + for (int j = 0; j < fields_q[i].get_n_bits(); j++) + mask[j+fields_q[i].get_lsb_pos()] = 1'b1; + end + end + + return mask; + endfunction + // get_n_bits will return number of all the bits in the csr // while this function will return actual number of bits used in reg field function uint get_n_used_bits(); @@ -135,7 +171,7 @@ class dv_base_reg extends uvm_reg; end endfunction - // Wen reg/fld can lock specific groups of fields' write acces. The lockable fields are called + // Wen reg/fld can lock specific groups of fields' write access. The lockable fields are called // lockable flds. function void add_lockable_reg_or_fld(uvm_object lockable_obj); dv_base_reg_field wen_fld; @@ -321,31 +357,64 @@ class dv_base_reg extends uvm_reg; // access policy. For register write via csr_wr(), this function is included in post_write(). // For register write via tl_access(), user will need to call this function manually. virtual function void lock_lockable_flds(uvm_reg_data_t val, uvm_predict_e kind); - if (is_wen_reg()) begin - `uvm_info(`gfn, $sformatf("lock_lockable_flds %d val", val), UVM_LOW); - foreach (m_fields[i]) begin - dv_base_reg_field fld; - `downcast(fld, m_fields[i]) - if (fld.is_wen_fld()) begin - uvm_reg_data_t field_val = val & fld.get_field_mask(); - string field_access = fld.get_access(); - case (field_access) - // discussed in issue #1922: enable register is standarized to W0C or RO (if HW has - // write access). - "W0C": begin - // This is the regular behavior with W0C access policy enabled (i.e., only - // clearing is possible). - if (kind == UVM_PREDICT_WRITE && field_val == 1'b0) begin - fld.set_lockable_flds_access(1); - // In this case we are using direct prediction where the access policy is not - // applied. I.e., a regwen bit that has been set to 0 can be set to 1 again. - end else if (kind == UVM_PREDICT_DIRECT) begin - fld.set_lockable_flds_access((~field_val) & fld.get_field_mask()); - end - end - "RO": ; // if RO, it's updated by design, need to predict in scb - default:`uvm_fatal(`gfn, $sformatf("lock register invalid access %s", field_access)) + if (!is_wen_reg()) return; + + foreach (m_fields[i]) begin + dv_base_reg_field fld; + `downcast(fld, m_fields[i]) + + if (fld.is_wen_fld()) begin + uvm_reg_data_t field_val = val & fld.get_field_mask(); + string field_access = fld.get_access(); + + // Check whether this field of the regwen is writeable at all (the regwen might not be + // writeable by software, in which case we can ignore it) + if (field_access == "RO") + continue; + + if (fld.get_mubi_width() == 0) begin + // This field is not encoded with a mubi value, and the only access type that we support + // is W0C. Check that it has been set up properly. + if (field_access != "W0C") begin + `uvm_fatal(`gfn, $sformatf("Field has access %0s (not W0C) and is not a mubi type.", + field_access)) + end + + // Because this field is W0C, software is allowed to clear it (disabling the write-enable) + // by writing a zero. Writing any other value will have no effect. + // + // A UVM_PREDICT_DIRECT prediction is a way for DV code to directly inform the RAL of a + // write coming through (not necessarily from software). This works by setting each bit if + // that bit of the write value is zero. + if (kind == UVM_PREDICT_WRITE && field_val == 1'b0) begin + fld.set_lockable_flds_access(1); + end else if (kind == UVM_PREDICT_DIRECT) begin + fld.set_lockable_flds_access((~field_val) & fld.get_field_mask()); + end + end else begin + // This field is encoded as a mubi value of the given width. + uvm_reg_data_t encoded_true; + + // Mubi fields only support the RW access value in UVM (because the bitwise operation to + // clear a mubi will set some bits and clear others!) + if (field_access != "RW") begin + `uvm_fatal(`gfn, $sformatf("Field has access %0s (not RW) but is a mubi type.", + field_access)) + end + + case (fld.get_mubi_width()) + 4: encoded_true = prim_mubi_pkg::MuBi4True; + 8: encoded_true = prim_mubi_pkg::MuBi8True; + 16: encoded_true = prim_mubi_pkg::MuBi16True; + 32: encoded_true = prim_mubi_pkg::MuBi32True; + default: `uvm_fatal(`gfn, $sformatf("Unknown mubi width: %0d", fld.get_mubi_width())) endcase + + // Process the write as having locked the field if the value being written is anything + // other than encoded_true. A write of encoded_true is a nop. + if (field_val != encoded_true) begin + fld.set_lockable_flds_access(1); + end end end end @@ -370,7 +439,9 @@ class dv_base_reg extends uvm_reg; backdoor_write_shadow_val = 1; end end + take_lock(); super.poke(status, value, kind, parent, extension, fname, lineno); + release_lock(); backdoor_write_shadow_val = 0; endtask @@ -388,9 +459,9 @@ class dv_base_reg extends uvm_reg; shadow_update_err = 0; shadow_wr_staged = 0; shadow_fatal_lock = 0; - // in case reset is issued during shadowed writes - void'(atomic_en_shadow_wr.try_get(1)); - atomic_en_shadow_wr.put(1); + // Make a new copy of the shadow write semaphore, so that we don't need a shadowed write + // operation to complete if a reset happens in the middle of one. + atomic_en_shadow_wr = new(1); end endfunction @@ -439,4 +510,82 @@ class dv_base_reg extends uvm_reg; return retval; endfunction + // Take the register's lock (see the documentation above access_lock for more details) + // + // This is mostly used in the wrappers around read, write etc. (working around a UVM bug). But the + // task is not local, because another class might want to use the predict method, which musn't + // overlap with the m_is_busy flag in uvm_reg. Taking this lock ensures it won't. + task take_lock(); + access_lock.get(); + endtask + + // Release the register's lock (see the documentation above access_lock for more details). This + // should only be called by a process that has already taken the lock with take_lock. + function void release_lock(); + access_lock.put(); + endfunction + + // A thin wrapper around uvm_reg::write that takes access_lock. See notes above access_lock that + // explain why it's needed. + task write(output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_path_e path = UVM_DEFAULT_PATH, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + take_lock(); + super.write(status, value, path, map, parent, prior, extension, fname, lineno); + release_lock(); + endtask + + // A thin wrapper around uvm_reg::read that takes access_lock. See notes above access_lock that + // explain why it's needed. + task read(output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_path_e path = UVM_DEFAULT_PATH, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + take_lock(); + super.read(status, value, path, map, parent, prior, extension, fname, lineno); + release_lock(); + endtask + + // A thin wrapper around uvm_reg::peek that takes access_lock. See notes above access_lock that + // explain why it's needed. + task peek(output uvm_status_e status, + output uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + take_lock(); + super.peek(status, value, kind, parent, extension, fname, lineno); + release_lock(); + endtask + + // A thin wrapper around uvm_reg::mirror that takes access_lock. See notes above access_lock that + // explain why it's needed. + task mirror(output uvm_status_e status, + input uvm_check_e check = UVM_NO_CHECK, + input uvm_path_e path = UVM_DEFAULT_PATH, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + take_lock(); + super.mirror(status, check, path, map, parent, prior, extension, fname, lineno); + release_lock(); + endtask + + endclass 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 74c3f733fc..e1e29c537a 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 @@ -76,9 +76,9 @@ class dv_base_reg_block extends uvm_reg_block; endfunction function string get_ip_name(); - // `DV_CHECK_NE_FATAL can't take "" as an input + // `DV_CHECK_FATAL can't take "" as an input string empty_str = ""; - `DV_CHECK_NE_FATAL(ip_name, empty_str, "ip_name hasn't been set yet") + `DV_CHECK_FATAL(ip_name != empty_str, "ip_name hasn't been set yet") return ip_name; endfunction diff --git a/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_field.sv b/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_field.sv index f20f832e03..009cdfda9b 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_field.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_field.sv @@ -31,6 +31,9 @@ class dv_base_reg_field extends uvm_reg_field; // variable for shadowed coverage, which is only created when this is a shadowed reg local dv_base_shadowed_field_cov shadowed_cov; + // Set to 1 if prediction is intended to be carried out in the cip_base_scoreboard + bit has_prediction = 0; + `uvm_object_utils(dv_base_reg_field) `uvm_object_new 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 95fe70dd0e..e64f2deab1 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 @@ -13,7 +13,6 @@ package dv_base_reg_pkg; // global paramters for number of csr tests (including memory test) parameter uint NUM_CSR_TESTS = 4; - string msg_id = "dv_base_reg_pkg"; // csr field struct - hold field specific params typedef struct { @@ -65,7 +64,6 @@ package dv_base_reg_pkg; uvm_reg csr; uvm_reg_field fld; csr_field_t result; - string msg_id = {dv_base_reg_pkg::msg_id, "::decode_csr_or_field"}; if ($cast(csr, ptr)) begin // return csr object with null field; set the mask to the width's all 1s and shift to 0 @@ -81,8 +79,8 @@ package dv_base_reg_pkg; result.shift = fld.get_lsb_pos(); end else begin - `uvm_fatal(msg_id, $sformatf("ptr %0s is not of type uvm_reg or uvm_reg_field", - ptr.get_full_name())) + `uvm_fatal($sformatf("%m"), $sformatf("ptr %0s is not of type uvm_reg or uvm_reg_field", + ptr.get_full_name())) end return result; endfunction : decode_csr_or_field @@ -99,8 +97,8 @@ package dv_base_reg_pkg; end else if ($cast(fld, obj)) begin flds.push_back(fld); end else begin - `uvm_fatal(msg, $sformatf("obj %0s is not of type uvm_reg or uvm_reg_field", - obj.get_full_name())) + `uvm_fatal($sformatf("%m"), $sformatf("obj %0s is not of type uvm_reg or uvm_reg_field", + obj.get_full_name())) end endfunction : get_flds_from_uvm_object @@ -122,9 +120,10 @@ package dv_base_reg_pkg; uint fshift; if (csr == null) csr = fields[i].get_parent(); else if (csr != fields[i].get_parent()) begin - `uvm_fatal(msg_id, $sformatf({"The provided fields belong to at least two different CSRs: ", - "%s, %s. All fields must belong to the same CSR"}, - fields[i-1].`gfn, fields[i].`gfn)) + `uvm_fatal($sformatf("%m") , $sformatf({"The provided fields belong to at least two" + ," different CSRs: ", + "%s, %s. All fields must belong to the same CSR"}, + fields[i-1].`gfn, fields[i].`gfn)) end fmask = (1 << fields[i].get_n_bits()) - 1; fshift = fields[i].get_lsb_pos(); diff --git a/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_agent_cfg.sv b/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_agent_cfg.sv index 0caf0f7860..79dc674033 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_agent_cfg.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_agent_cfg.sv @@ -9,11 +9,11 @@ class dv_base_agent_cfg extends uvm_object; bit en_cov = 1'b1; // enable coverage if_mode_e if_mode; // interface mode - Host or Device - // indicate to create and connet driver to sequencer or not + // indicate to create and connect driver to sequencer or not // if this is a high-level agent, we may just call lower-level agent to send item in seq, then // driver isn't needed bit has_driver = 1'b1; - // indicate if these fifo and ports exist or not + // indicate if these FIFO and ports exist or not bit has_req_fifo = 1'b0; bit has_rsp_fifo = 1'b0; diff --git a/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_driver.sv b/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_driver.sv index 264f5e9364..2a09c6ac83 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_driver.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_driver.sv @@ -17,6 +17,7 @@ class dv_base_driver #(type ITEM_T = uvm_sequence_item, `uvm_component_new virtual task run_phase(uvm_phase phase); + super.run_phase(phase); fork reset_signals(); get_and_drive(); @@ -25,12 +26,12 @@ class dv_base_driver #(type ITEM_T = uvm_sequence_item, // reset signals virtual task reset_signals(); - `uvm_fatal(`gfn, "this is implemented as pure virtual task - please extend") + // Empty - to be populated in child class endtask // drive trans received from sequencer virtual task get_and_drive(); - `uvm_fatal(`gfn, "this is implemented as pure virtual task - please extend") + // Empty - to be populated in child class endtask 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 106d812f7c..73eae99d1b 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 @@ -180,11 +180,13 @@ class dv_base_env_cfg #(type RAL_T = dv_base_reg_block) extends uvm_object; if (obj == null) begin // print factory overrides to help debug factory.print(); - `uvm_fatal(msg_id, $sformatf("could not create %0s as a RAL model, see above for a list of \ - type/instance overrides", name)) + `uvm_fatal(`gfn, + $sformatf({"Could not create %0s as a RAL model. ", + "See above for a list of type/instance overrides"}, + name)) end if (!$cast(ral, obj)) begin - `uvm_fatal(msg_id, $sformatf("cast failed - %0s is not a dv_base_reg_block", name)) + `uvm_fatal(`gfn, $sformatf("Cast failed - %0s is not a dv_base_reg_block", name)) end return ral; endfunction diff --git a/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_monitor.sv b/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_monitor.sv index b535934a26..8f4c1ec931 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_monitor.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_monitor.sv @@ -7,7 +7,7 @@ class dv_base_monitor #(type ITEM_T = uvm_sequence_item, type RSP_ITEM_T = ITEM_T, type CFG_T = dv_base_agent_cfg, type COV_T = dv_base_agent_cov) extends uvm_monitor; - `uvm_component_param_utils(dv_base_monitor #(ITEM_T, CFG_T, COV_T)) + `uvm_component_param_utils(dv_base_monitor #(ITEM_T, REQ_ITEM_T, RSP_ITEM_T, CFG_T, COV_T)) CFG_T cfg; COV_T cov; @@ -37,6 +37,7 @@ class dv_base_monitor #(type ITEM_T = uvm_sequence_item, endfunction virtual task run_phase(uvm_phase phase); + super.run_phase(phase); fork collect_trans(); join @@ -44,7 +45,7 @@ class dv_base_monitor #(type ITEM_T = uvm_sequence_item, // collect transactions forever virtual protected task collect_trans(); - `uvm_fatal(`gfn, "this method is not supposed to be called directly!") + // Empty - to be overridden in the child class endtask // UVM callback which is invoked during phase sequencing. diff --git a/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_sequencer.sv b/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_sequencer.sv index 33d4310948..38d4393b16 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_sequencer.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_sequencer.sv @@ -11,10 +11,10 @@ class dv_base_sequencer #(type ITEM_T = uvm_sequence_item, .CFG_T (CFG_T), .RSP_ITEM_T (RSP_ITEM_T))) - // These fifos collects items when req/rsp is received, which are used to communicate between - // monitor and sequences. These fifos are optional + // These FIFOs collect items when req/rsp is received, which are used to communicate between + // monitor and sequences. These FIFOs are optional // When device is re-active, it gets items from req_analysis_fifo and send rsp to driver - // When this is a high-level agent, monitors put items to these 2 fifos for high-level seq + // When this is a high-level agent, monitors put items to these 2 FIFOs for high-level seq uvm_tlm_analysis_fifo #(ITEM_T) req_analysis_fifo; uvm_tlm_analysis_fifo #(RSP_ITEM_T) rsp_analysis_fifo; @@ -24,8 +24,14 @@ class dv_base_sequencer #(type ITEM_T = uvm_sequence_item, function void build_phase(uvm_phase phase); super.build_phase(phase); - if (cfg.has_req_fifo) req_analysis_fifo = new("req_analysis_fifo", this); - if (cfg.has_rsp_fifo) rsp_analysis_fifo = new("rsp_analysis_fifo", this); + + // Avoid null pointer if the cfg is not defined. + if (cfg == null) begin + `uvm_fatal(`gfn, "cfg handle is null.") + end else begin + if (cfg.has_req_fifo) req_analysis_fifo = new("req_analysis_fifo", this); + if (cfg.has_rsp_fifo) rsp_analysis_fifo = new("rsp_analysis_fifo", this); + end endfunction : build_phase endclass diff --git a/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_test.sv b/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_test.sv index d4c564a272..9bb2286d2a 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_test.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_test.sv @@ -70,6 +70,7 @@ class dv_base_test #(type CFG_T = dv_base_env_cfg, endfunction : end_of_elaboration_phase virtual task run_phase(uvm_phase phase); + super.run_phase(phase); void'($value$plusargs("drain_time_ns=%0d", drain_time_ns)); phase.phase_done.set_drain_time(this, (drain_time_ns * 1ns)); void'($value$plusargs("poll_for_stop=%0b", poll_for_stop)); @@ -88,10 +89,8 @@ class dv_base_test #(type CFG_T = dv_base_env_cfg, virtual task run_seq(string test_seq_s, uvm_phase phase); uvm_sequence test_seq = create_seq_by_name(test_seq_s); - // Setting the sequencer before the sequence is randomized is mandatory. We do this so that the - // sequence has access to the UVM environment's cfg handle via the p_sequencer handle within the - // randomization constraints. - test_seq.set_sequencer(env.virtual_sequencer); + configure_sequence(test_seq); + `DV_CHECK_RANDOMIZE_FATAL(test_seq) `uvm_info(`gfn, {"Starting test sequence ", test_seq_s}, UVM_MEDIUM) @@ -100,4 +99,16 @@ class dv_base_test #(type CFG_T = dv_base_env_cfg, phase.drop_objection(this, $sformatf("%s objection dropped", `gn)); `uvm_info(`gfn, {"Finished test sequence ", test_seq_s}, UVM_MEDIUM) endtask + + // A virtual function that allows the test to set up the sequence to know about the sequencer + // where it should run. This runs before the sequence is randomised, which allows the sequence to + // constrain its randomisation using the environment's cfg handle (getting it through p_sequencer). + // + // The base class version of this function registers env.virtual_sequencer. If a testbench wishes + // to register multiple sequencers with a virtual sequence, it can do so by overriding this + // function. + virtual function void configure_sequence(uvm_sequence seq); + seq.set_sequencer(env.virtual_sequencer); + endfunction + endclass : dv_base_test diff --git a/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_virtual_sequencer.sv b/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_virtual_sequencer.sv index 1b39b874eb..1fc4c7d8a7 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_virtual_sequencer.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_virtual_sequencer.sv @@ -9,6 +9,24 @@ class dv_base_virtual_sequencer #(type CFG_T = dv_base_env_cfg, CFG_T cfg; COV_T cov; - `uvm_component_new + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction + // Dynamic associative array to store sub-sequencers + uvm_sequencer_base sub_sequencers[string]; + + // Method to dynamically register a sub-sequencer + function void register_sequencer(string name, uvm_sequencer_base sequencer); + // Check if the sub_sequencer name does not exists before register it. + `DV_CHECK_FATAL(!sub_sequencers.exists(name)) + sub_sequencers[name] = sequencer; + endfunction + + // Method to retrieve a sequencer by name + function uvm_sequencer_base get_sequencer(string name); + // Check if the sub_sequencer name is registered before return it. + `DV_CHECK_FATAL(sub_sequencers.exists(name)) + return sub_sequencers[name]; + endfunction endclass 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 d196fe462b..25986920f9 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 @@ -65,10 +65,6 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block, num_trans.rand_mode(0); endtask - task body(); - `uvm_fatal(`gtn, "Need to override this when you extend from this class!") - endtask : body - task post_start(); super.post_start(); if (do_dut_shutdown) dut_shutdown(); @@ -120,21 +116,33 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block, // optional input `reset_duration_ps` if the DUT has additional resets. The task uses this input // to compute the minimal time required to keep all resets asserted. virtual task apply_resets_concurrently(int reset_duration_ps = 0); + int slowest_clk_period_ps = 0; + int reset_duration_from_clks_ps; - // Has one or more RAL models in DUT. + // Calculate the slowest clock that we see with a RAL model or fall back to the default + // clk_rst_if if there is no RAL model. if (cfg.clk_rst_vifs.size() > 0) begin foreach (cfg.clk_rst_vifs[i]) begin - cfg.clk_rst_vifs[i].drive_rst_pin(0); - reset_duration_ps = max2(reset_duration_ps, cfg.clk_rst_vifs[i].clk_period_ps); + slowest_clk_period_ps = max2(slowest_clk_period_ps, cfg.clk_rst_vifs[i].clk_period_ps); end - #(reset_duration_ps * $urandom_range(2, 10) * 1ps); - foreach (cfg.clk_rst_vifs[i]) cfg.clk_rst_vifs[i].drive_rst_pin(1); + end else begin + slowest_clk_period_ps = cfg.clk_rst_vif.clk_period_ps; + end + + // Pick the reset duration by picking a random number of (slowest) clock cycles, taking at least + // two. Then use the maximum of that value and the reset_duration_ps argument. + reset_duration_from_clks_ps = $urandom_range(2, 10) * slowest_clk_period_ps; + reset_duration_ps = max2(reset_duration_ps, reset_duration_from_clks_ps); - // No RAL model and only has default clk_rst_vif. + // Now apply the reset by driving any reset pins to zero, waiting a while, and then driving the + // back to one. + if (cfg.clk_rst_vifs.size() > 0) begin + foreach (cfg.clk_rst_vifs[i]) cfg.clk_rst_vifs[i].drive_rst_pin(0); + #(reset_duration_ps * 1ps); + foreach (cfg.clk_rst_vifs[i]) cfg.clk_rst_vifs[i].drive_rst_pin(1); end else begin cfg.clk_rst_vif.drive_rst_pin(0); - reset_duration_ps = max2(reset_duration_ps, cfg.clk_rst_vif.clk_period_ps); - #(reset_duration_ps * $urandom_range(2, 10) * 1ps); + #(reset_duration_ps * 1ps); cfg.clk_rst_vif.drive_rst_pin(1); end endtask @@ -271,4 +279,13 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block, uvm_config_db#(bit)::set(null, path, "csr_assert_en", enable); endfunction + // Use the factory to create a sequence by name and return the resulting uvm_sequence. + // + // The created sequence should be an instance of the class where this function is defined. + // Creating the sequence through this method rather than the underlying function, + // dv_utils_pkg::create_seq_by_name, allows subclasses of dv_base_seq to copy information about + // themselves (such as sequencers or other configuration) to the new sequence. + virtual function uvm_sequence create_seq_by_name(string name); + return dv_utils_pkg::create_seq_by_name(name); + endfunction endclass diff --git a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_fcov_macros.svh b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_fcov_macros.svh index 6b5111eb77..eaae3937f2 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_fcov_macros.svh +++ b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_fcov_macros.svh @@ -48,7 +48,7 @@ `endif // Creates a coverpoint for an expression where only the expression true case is of interest for -// coverage (e.g. where the expression indicates an event has occured). +// coverage (e.g. where the expression indicates an event has occurred). `ifndef DV_FCOV_EXPR_SEEN `ifdef DV_FCOV_DISABLE_CP `define DV_FCOV_EXPR_SEEN(NAME_, EXPR_) 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 f922b1a926..f6f69cb1d0 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh +++ b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh @@ -61,7 +61,7 @@ `ifndef uvm_component_new `define uvm_component_new \ - function new (string name="", uvm_component parent=null); \ + function new (string name, uvm_component parent); \ super.new(name, parent); \ endfunction : new `endif @@ -293,19 +293,19 @@ end `endif -// print non-empty tlm fifos that were uncompared at end of test +// print non-empty tlm FIFOs that were uncompared at end of test `ifndef DV_EOT_PRINT_TLM_FIFO_CONTENTS -`define DV_EOT_PRINT_TLM_FIFO_CONTENTS(TYP_, FIFO_, SEV_=error, ID_=`gfn) \ - begin \ - while (!FIFO_.is_empty()) begin \ - TYP_ item; \ - void'(FIFO_.try_get(item)); \ - `dv_``SEV_($sformatf("%s item uncompared:\n%s", `"FIFO_`", item.sprint()), ID_) \ - end \ +`define DV_EOT_PRINT_TLM_FIFO_CONTENTS(TYP_, FIFO_, SEV_=error, ID_=`gfn) \ + forever begin \ + TYP_ item; \ + int res = FIFO_.try_get(item); \ + if (res == 0) break; \ + if (res < 0) `dv_fatal($sformatf("Cannot read item from %s (type mismatch)", `"FIFO_`"), ID_) \ + `dv_``SEV_($sformatf("%s item uncompared:\n%s", `"FIFO_`", item.sprint()), ID_) \ end `endif -// print non-empty tlm fifos that were uncompared at end of test +// print non-empty tlm FIFOs that were uncompared at end of test `ifndef DV_EOT_PRINT_TLM_FIFO_ARR_CONTENTS `define DV_EOT_PRINT_TLM_FIFO_ARR_CONTENTS(TYP_, FIFO_, SEV_=error, ID_=`gfn) \ begin \ @@ -319,7 +319,7 @@ end `endif -// print non-empty tlm fifos that were uncompared at end of test +// print non-empty tlm FIFOs that were uncompared at end of test `ifndef DV_EOT_PRINT_Q_CONTENTS `define DV_EOT_PRINT_Q_CONTENTS(TYP_, Q_, SEV_=error, ID_=`gfn) \ begin \ @@ -330,7 +330,7 @@ end `endif -// print non-empty tlm fifos that were uncompared at end of test +// print non-empty tlm FIFOs that were uncompared at end of test `ifndef DV_EOT_PRINT_Q_ARR_CONTENTS `define DV_EOT_PRINT_Q_ARR_CONTENTS(TYP_, Q_, SEV_=error, ID_=`gfn) \ begin \ @@ -387,26 +387,55 @@ end `endif +// Wait for one of two statements but stop early if the EXIT statement completes. +// +// Example usage: +// +// `DV_SPINWAIT_EXIT_MULTI(do_something_time_consuming();, +// do_something_else_time_consuming();, +// wait(stop_now_flag);, +// "The stop flag was set when we were working") +`ifndef DV_SPINWAIT_EXIT_MULTI +`define DV_SPINWAIT_EXIT_MULTI(WAIT_1_, WAIT_2_, EXIT_, MSG_ = "exit condition occurred!", ID_ =`gfn) \ + `DV_SPINWAIT_EXIT(fork begin \ + fork \ + begin WAIT_1_ end \ + begin WAIT_2_ end \ + join_any \ + disable fork; \ + end join, \ + EXIT_, MSG_, ID_) +`endif + // macro that waits for a given delay and then reports an error `ifndef DV_WAIT_TIMEOUT `define DV_WAIT_TIMEOUT(TIMEOUT_NS_, ID_ = `gfn, ERROR_MSG_ = "timeout occurred!", REPORT_FATAL_ = 1) \ begin \ #(TIMEOUT_NS_ * 1ns); \ - if (REPORT_FATAL_) `dv_fatal(ERROR_MSG_, ID_) \ - else `dv_error(ERROR_MSG_, ID_) \ + if (REPORT_FATAL_) begin \ + `dv_fatal(ERROR_MSG_, ID_) \ + end else begin \ + `dv_error(ERROR_MSG_, ID_) \ + end \ end `endif // Wait for a statement, but exit early after a timeout `ifndef DV_SPINWAIT -`define DV_SPINWAIT(WAIT_, MSG_ = "timeout occurred!", TIMEOUT_NS_ = default_spinwait_timeout_ns, ID_ =`gfn) \ - `DV_SPINWAIT_EXIT(WAIT_, `DV_WAIT_TIMEOUT(TIMEOUT_NS_, ID_, MSG_);, "", ID_) +`define DV_SPINWAIT(WAIT_, MSG_ = "timeout occurred!", TIMEOUT_NS_ = default_spinwait_timeout_ns, ID_ =`gfn, REPORT_FATAL_ = 1) \ + `DV_SPINWAIT_EXIT(WAIT_, `DV_WAIT_TIMEOUT(TIMEOUT_NS_, ID_, MSG_, REPORT_FATAL_);, "", ID_) `endif // a shorthand of `DV_SPINWAIT(wait(...)) `ifndef DV_WAIT -`define DV_WAIT(WAIT_COND_, MSG_ = "wait timeout occurred!", TIMEOUT_NS_ = default_spinwait_timeout_ns, ID_ =`gfn) \ - `DV_SPINWAIT(wait (WAIT_COND_);, MSG_, TIMEOUT_NS_, ID_) +`define DV_WAIT(WAIT_COND_, MSG_ = "wait timeout occurred!", TIMEOUT_NS_ = default_spinwait_timeout_ns, ID_ =`gfn, REPORT_FATAL_ = 1) \ + `DV_SPINWAIT(wait (WAIT_COND_);, MSG_, TIMEOUT_NS_, ID_, REPORT_FATAL_) +`endif + +// Wait for one of two statements, but exit early after a timeout +`ifndef DV_WAIT_MULTI +`define DV_WAIT_MULTI(WAIT_COND_1_, WAIT_COND_2_, MSG_ = "wait timeout occurred!", TIMEOUT_NS_ = default_spinwait_timeout_ns, ID_ =`gfn, REPORT_FATAL_ = 1) \ + `DV_SPINWAIT_EXIT_MULTI(WAIT_COND_1_, WAIT_COND_2_, `DV_WAIT_TIMEOUT(TIMEOUT_NS_, ID_, MSG_, REPORT_FATAL_);, "", ID_) `endif // Control assertions in the DUT. @@ -492,7 +521,7 @@ // 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 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 +// is 'wrapped' into the LABEL_ instead. DV user needs to uniquify the label sufficiently enough to // reflect it. // // LABEL_ : Name of the assertion control resource bit (string). @@ -609,7 +638,7 @@ // // If there is a need to sample / force an internal signal, then it must be done in the testbench, // or in an interface bound to the DUT. This macro creates a standardized signal probe function -// meant to be invoked an interface. The generated function can then be invoked in test sequences +// to be defined in an interface. The generated function can then be invoked in test sequences // or other UVM classes. The macro takes 2 arguments - name of the function and the hierarchical // path to the signal. If invoked in an interface which is bound to the DUT, the signal can be a // partial hierarchical path within the DUT. The generated function accepts 2 arguments - the first @@ -636,7 +665,7 @@ `endif // Usage:`OTDBG(( string )) -// This macro has unque keyword 'OTDBG'and timestemp only. +// This macro has unique keyword 'OTDBG' and timestamp only. // Use for the temporary print to distinguish from `uvm_info. // Do not leave this macro in other source files in the remote repo. `ifndef OTDBG diff --git a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_report_catcher.sv b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_report_catcher.sv index 7ab687a72e..4f96279a77 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_report_catcher.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_report_catcher.sv @@ -16,7 +16,7 @@ class dv_report_catcher extends uvm_report_catcher; string id = get_id(); if (m_changed_sev.exists(id)) begin string report_msg = get_message(); - foreach (m_changed_sev[id][msg]) begin + foreach (m_changed_sev[id, msg]) begin if (uvm_re_match(msg, report_msg)) begin set_severity(m_changed_sev[id][msg]); end 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 f48f62e197..fcfe25cea0 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 @@ -4,6 +4,7 @@ // Standardize look & feel of report phase and uvm logging messages. class dv_report_server extends uvm_default_report_server; + `uvm_object_utils(dv_report_server) bit show_file_line = 1'b1; // if enabled, show the relative path of the file. By default only show file name 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 00a6cd7375..44acdf0ce7 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 @@ -90,8 +90,6 @@ package dv_utils_pkg; ClkFreqDiffAny } clk_freq_diff_e; - string msg_id = "dv_utils_pkg"; - // return the smaller value of 2 inputs function automatic int min2(int a, int b); return (a < b) ? a : b; @@ -105,7 +103,7 @@ package dv_utils_pkg; // return the biggest value within the given queue of integers. function automatic int max(const ref int int_q[$]); `DV_CHECK_GT_FATAL(int_q.size(), 0, "max function cannot accept an empty queue of integers!", - msg_id) + $sformatf("%m")) // Assign the first value from the queue in case of negative integers. max = int_q[0]; foreach (int_q[i]) max = max2(max, int_q[i]); @@ -169,10 +167,10 @@ package dv_utils_pkg; if (obj == null) begin // print factory overrides to help debug factory.print(1); - `uvm_fatal(msg_id, $sformatf("could not create %0s seq", seq_name)) + `uvm_fatal($sformatf("%m"), $sformatf("could not create %0s seq", seq_name)) end if (!$cast(seq, obj)) begin - `uvm_fatal(msg_id, $sformatf("cast failed - %0s is not a uvm_sequence", seq_name)) + `uvm_fatal($sformatf("%m"), $sformatf("cast failed - %0s is not a uvm_sequence", seq_name)) end return seq; endfunction @@ -224,12 +222,11 @@ package dv_utils_pkg; output longint unsigned addr, output longint unsigned size); - string msg_id = "sw_symbol_get_addr_size"; string escaped_symbol = ""; string symbol_for_filename = ""; - `DV_CHECK_STRNE_FATAL(elf_file, "", "Input arg \"elf_file\" cannot be an empty string", msg_id) - `DV_CHECK_STRNE_FATAL(symbol, "", "Input arg \"symbol\" cannot be an empty string", msg_id) + if (elf_file == "") `uvm_fatal($sformatf("%m"), "'elf_file' argument cannot be an empty string") + if (symbol == "") `uvm_fatal($sformatf("%m"), "'symbol' argument cannot be an empty string") // If the symbol has special characters, such as '$', escape it for the cmd below, but when // creating the file, omit the special characters entirely. @@ -256,31 +253,32 @@ package dv_utils_pkg; // TODO #3838: shell pipes are bad 'mkay? ret = $system(cmd); `DV_CHECK_EQ_FATAL(ret, 0, $sformatf("Command \"%0s\" failed with exit code %0d", cmd, ret), - msg_id) + $sformatf("%m")) out_file_d = $fopen(out_file, "r"); - `DV_CHECK_FATAL(out_file_d, $sformatf("Failed to open \"%0s\"", out_file), msg_id) + `DV_CHECK_FATAL(out_file_d, $sformatf("Failed to open \"%0s\"", out_file), $sformatf("%m")) ret = $fgets(line, out_file_d); // If the symbol did not exist in the elf (empty file), and we are ok with that, then return. if (!ret && does_not_exist_ok) return 0; - `DV_CHECK_FATAL(ret, $sformatf("Failed to read line from \"%0s\"", out_file), msg_id) + `DV_CHECK_FATAL(ret, $sformatf("Failed to read line from \"%0s\"", out_file), $sformatf("%m")) // The first line should have the addr in hex followed by its size as integer. ret = $sscanf(line, "%h %d", addr, size); `DV_CHECK_EQ_FATAL(ret, 2, $sformatf("Failed to extract {addr size} from line \"%0s\"", line), - msg_id) + $sformatf("%m")) // Attempt to read the next line should be met with EOF. void'($fgets(line, out_file_d)); ret = $feof(out_file_d); - `DV_CHECK_FATAL(ret, $sformatf("EOF expected to be reached for \"%0s\"", out_file), msg_id) + `DV_CHECK_FATAL(ret, $sformatf("EOF expected to be reached for \"%0s\"", out_file), + $sformatf("%m")) $fclose(out_file_d); ret = $system($sformatf("rm -rf %0s", out_file)); - `DV_CHECK_EQ_FATAL(ret, 0, $sformatf("Failed to delete \"%0s\"", out_file), msg_id) + `DV_CHECK_EQ_FATAL(ret, 0, $sformatf("Failed to delete \"%0s\"", out_file), $sformatf("%m")) return 1; end endfunction @@ -299,7 +297,7 @@ package dv_utils_pkg; string text, msg = "\n", lines[$]; fd = $fopen(vmem_file, "r"); - `DV_CHECK_FATAL(fd, $sformatf("Failed to open \"%0s\"", vmem_file), msg_id) + `DV_CHECK_FATAL(fd, $sformatf("Failed to open \"%0s\"", vmem_file), $sformatf("%m")) while (!$feof(fd)) begin string line; void'($fgets(line, fd)); @@ -308,7 +306,7 @@ package dv_utils_pkg; text = {text, line, "\n"}; end $fclose(fd); - `DV_CHECK_STRNE_FATAL(text, "", , msg_id) + `DV_CHECK_STRNE_FATAL(text, "", , $sformatf("%m")) // Remove all block and single comments. text = str_utils_pkg::str_remove_sections(.s(text), .start_delim("/*"), .end_delim("*/")); @@ -325,35 +323,35 @@ package dv_utils_pkg; str_utils_pkg::str_split(lines[i], tokens, " "); `DV_CHECK_FATAL(tokens.size() >= 2, $sformatf("Line \"%s\" in VMEM file %s appears to be malformed", - lines[i], vmem_file), msg_id) + lines[i], vmem_file), $sformatf("%m")) if (!str_utils_pkg::str_starts_with(tokens[0], "@")) begin - `uvm_fatal(msg_id, $sformatf({"The first word \"%s\" on line \"%s\" in the VMEM file %s ", - " does not appear to be a valid address"}, - tokens[0], lines[i], vmem_file)) + `uvm_fatal($sformatf("%m"), $sformatf({"The first word \"%s\" on line \"%s\" in the VMEM", + " file %s does not appear to be a valid address"}, + tokens[0], lines[i], vmem_file)) end tokens[0] = tokens[0].substr(1, tokens[0].len() - 1); `DV_CHECK_FATAL(tokens[0].len() <= bus_params_pkg::BUS_AW / 8 * 2, $sformatf("Address width > %0d bytes is not supported: 0x%0s", - bus_params_pkg::BUS_AW / 8, tokens[0]), msg_id) + bus_params_pkg::BUS_AW / 8, tokens[0]), $sformatf("%m")) addr = tokens[0].atohex(); tokens = tokens[1:$]; if (i > 0) begin `DV_CHECK_FATAL(addr == last_addr, $sformatf("Non-contiguous data unsupported - last_addr: 0x%0h, addr: 0x%0h", - last_addr, addr), msg_id) + last_addr, addr), $sformatf("%m")) end foreach (tokens[i]) begin logic [bus_params_pkg::BUS_DW-1:0] data; `DV_CHECK_FATAL(tokens[i].len() <= bus_params_pkg::BUS_DW / 8 * 2, $sformatf("Data width > %0d bytes is not supported: 0x%0s", - bus_params_pkg::BUS_DW / 8, tokens[i]), msg_id) + bus_params_pkg::BUS_DW / 8, tokens[i]), $sformatf("%m")) data = tokens[i].atohex(); msg = {msg, $sformatf("[0x%0h] = 0x%0h\n", addr + i, data)}; vmem_data.push_back(data); end last_addr = addr + tokens.size(); end - `uvm_info(msg_id, $sformatf("Contents of VMEM file %s:%s", vmem_file, msg), UVM_HIGH) + `uvm_info($sformatf("%m"), $sformatf("Contents of VMEM file %s:%s", vmem_file, msg), UVM_HIGH) endfunction // sources diff --git a/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util.core b/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util.core index 63e06e97d6..80fcc50375 100644 --- a/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util.core +++ b/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util.core @@ -14,19 +14,12 @@ filesets: - lowrisc:dv:crypto_dpi_present:0.1 - lowrisc:prim:cipher_pkg:0.1 - lowrisc:prim:secded:0.1 - - lowrisc:ip:otp_ctrl_pkg:1.0 - - lowrisc:ip_interfaces:flash_ctrl_pkg - lowrisc:dv:digestpp_dpi - lowrisc:ip:kmac_pkg files: - - otp_scrambler_pkg.sv - - sram_scrambler_pkg.sv - mem_bkdr_util_pkg.sv + - mem_bkdr_util_row_adapter.sv: {is_include_file: true} - mem_bkdr_util.sv: {is_include_file: true} - - mem_bkdr_util__otp.sv: {is_include_file: true} - - mem_bkdr_util__rom.sv: {is_include_file: true} - - mem_bkdr_util__sram.sv: {is_include_file: true} - - mem_bkdr_util__flash.sv: {is_include_file: true} file_type: systemVerilogSource targets: diff --git a/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util.sv b/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util.sv index c3354bb743..7b1035a483 100644 --- a/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util.sv +++ b/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util.sv @@ -16,15 +16,33 @@ class mem_bkdr_util extends uvm_object; // Hierarchical path to the memory. protected string path; + // If set to a value different to "", a path to the tile memory, based on path and tiling_path, + // is used to perform the backdoor access + protected string tiling_path; + + // Format string to provide the tiling suffix. Must contain a %d for the tile and %s for the + // tiling_path path. Can be overwritten for different hierarchies, ie., when DFT is enabled. + protected string tiling_suffix_fmt_str; + // The depth of the memory. protected uint32_t depth; - // The width of the memory. + // The depth of a single SRAM tile. + protected uint32_t tile_depth; + + // The logical width of the memory in bits, not including extra bits added by the row adapter. protected uint32_t width; + // The number of subword entries in the whole memory + protected uint32_t num_entries; + // Indicates the error detection scheme implemented for this memory. protected err_detection_e err_detection_scheme = ErrDetectionNone; + // Adapter to access the underlying memory organization + // Integrators can provide a custom row adapter for their SRAM primitives + protected mem_bkdr_util_row_adapter row_adapter; + // Convenience macro to check if ECC / parity is enabled. `define HAS_ECC (!(err_detection_scheme inside {ErrDetectionNone, ParityEven, ParityOdd})) `define HAS_PARITY (err_detection_scheme inside {ParityEven, ParityOdd}) @@ -57,23 +75,80 @@ class mem_bkdr_util extends uvm_object; event readmemh_event; event writememh_event; - // Initialize the class instance. - // `extra_bits_per_subword` is the width any additional metadata that is not captured in secded - // package. + // Number of PRINCE half rounds for scrambling, can be [1..5]. + protected uint32_t num_prince_rounds_half; + + // Construct an instance called name. + // + // Required arguments: + // + // path: A hierarchical HDL path to the memory. + // + // depth: The number memory rows. + // + // n_bits: The total size of the memory in bits. + // + // err_detection_scheme The error detection scheme that is implemented for the memory. + // + // Optional arguments: + // + // row_adapter Adapter to access the internal row of a memory. Integrators can + // provide a custom adapter for a different memory architecture. + // + // num_prince_rounds_half The number of rounds of PRINCE used to scramble the memory. This is + // used for scrambled memories. This defaults to 3. + // + // extra_bits_per_subword When ECC is enabled, the words of the memory are divided into + // separate subwords that are used for ECC checks. This gives the number + // of extra bits added to each subword (to contain additional SECDED + // metadata). This defaults to zero. + // + // system_base_addr The memory words accessed through this backdoor would normally be + // indexed from zero. If this value is non-zero, the backdoor starts at + // some higher index. + // + // tiling_path A path used for constructing HDL paths to individual tiles (used + // when tile_depth < depth). By default this is empty because there are + // no tiles that would need paths at all. + // + // tiling_suffix_fmt_str Format string to provide the tiling suffix. Must contain a %d for the + // tile and %s for the tiling_path path. If the testbench uses a + // different path, i.e., in a DFT environment, you can pass a different + // format string to construct the tiling path. + // + // tile_depth The number of rows of a single tle. By default, this is the entire + // memory. function new(string name = "", string path, int unsigned depth, longint unsigned n_bits, err_detection_e err_detection_scheme, - int extra_bits_per_subword = 0, int unsigned system_base_addr = 0); - - bit res; + mem_bkdr_util_row_adapter row_adapter = null, + uint32_t num_prince_rounds_half = 3, + uint32_t extra_bits_per_subword = 0, uint32_t system_base_addr = 0, + string tiling_path = "", string tiling_suffix_fmt_str = ".gen_ram_inst[%0d].%s", + uint32_t tile_depth = depth); super.new(name); `DV_CHECK_FATAL(!(n_bits % depth), "n_bits must be divisible by depth.") - res = uvm_hdl_check_path(path); - `DV_CHECK_EQ_FATAL(res, 1, $sformatf("Hierarchical path %0s appears to be invalid.", path)) - this.path = path; - this.depth = depth; - this.width = n_bits / depth; - this.err_detection_scheme = err_detection_scheme; + if (row_adapter != null) begin + this.row_adapter = row_adapter; + end else begin + this.row_adapter = new(); + end + + this.path = path; + this.tiling_path = tiling_path; + this.depth = depth; + this.tile_depth = tile_depth; + this.tiling_suffix_fmt_str = tiling_suffix_fmt_str; + this.width = (n_bits / depth) - this.row_adapter.get_num_extra_bits(); + this.err_detection_scheme = err_detection_scheme; + this.num_prince_rounds_half = num_prince_rounds_half; + + // Check if the inferred path to each tile (or the whole memory) really exist + for (int i = 0; i < (depth + tile_depth - 1) / tile_depth; i++) begin + string full_path = get_full_path(i); + `DV_CHECK_FATAL(uvm_hdl_check_path(get_full_path(i)) == 1, + $sformatf("Hierarchical path %0s appears to be invalid.", full_path)) + end if (`HAS_ECC) begin import prim_secded_pkg::prim_secded_e; @@ -101,8 +176,10 @@ class mem_bkdr_util extends uvm_object; subwords_per_word = (width + bits_per_subword - 1) / bits_per_subword; this.data_width = subwords_per_word * non_ecc_bits_per_subword; + this.num_entries = depth * subwords_per_word; end else begin this.data_width = width; + this.num_entries = depth; end byte_width = `HAS_PARITY ? 9 : 8; @@ -141,10 +218,28 @@ class mem_bkdr_util extends uvm_object; return path; endfunction + function string get_full_path(int unsigned tile); + string base = get_path(); + string tile_suffix = ""; + + `DV_CHECK_FATAL(tile > 0 -> tiling_path.len() > 0, + $sformatf("Positive tile index (%0d) with empty tiling path.", tile)) + + if (tiling_path != "") begin + tile_suffix = $sformatf(tiling_suffix_fmt_str, tile, tiling_path); + end + + return {base, tile_suffix}; + endfunction + function uint32_t get_depth(); return depth; endfunction + function uint32_t get_tile_depth(); + return tile_depth; + endfunction + function uint32_t get_width(); return width; endfunction @@ -153,6 +248,10 @@ class mem_bkdr_util extends uvm_object; return err_detection_scheme; endfunction + function int get_num_prince_rounds_half(); + return num_prince_rounds_half; + endfunction + function uint32_t get_data_width(); return data_width; endfunction @@ -210,12 +309,14 @@ class mem_bkdr_util extends uvm_object; // encryption is enabled. virtual function uvm_hdl_data_t read(bit [bus_params_pkg::BUS_AW-1:0] addr); bit res; - uint32_t index; - uvm_hdl_data_t data; + uint32_t index, ram_tile; + uvm_hdl_data_t encoded_row, data; if (!check_addr_valid(addr)) return 'x; - index = addr >> addr_lsb; - res = uvm_hdl_read($sformatf("%0s[%0d]", path, index), data); + index = addr >> addr_lsb; + ram_tile = index / tile_depth; + res = uvm_hdl_read($sformatf("%0s[%0d]", get_full_path(ram_tile), index), encoded_row); `DV_CHECK_EQ(res, 1, $sformatf("uvm_hdl_read failed at index %0d", index)) + data = row_adapter.decode_row(encoded_row); return data; endfunction @@ -324,10 +425,14 @@ class mem_bkdr_util extends uvm_object; // Updates the entire width of the memory at the given address, including the ECC bits. virtual function void write(bit [bus_params_pkg::BUS_AW-1:0] addr, uvm_hdl_data_t data); bit res; - uint32_t index; + uvm_hdl_data_t encoded_row; + uint32_t index, ram_tile; if (!check_addr_valid(addr)) return; - index = addr >> addr_lsb; - res = uvm_hdl_deposit($sformatf("%0s[%0d]", path, index), data); + index = addr >> addr_lsb; + ram_tile = index / tile_depth; + encoded_row = row_adapter.encode_row(data); + res = uvm_hdl_deposit($sformatf("%0s[%0d]", get_full_path(ram_tile), index), + encoded_row); `DV_CHECK_EQ(res, 1, $sformatf("uvm_hdl_deposit failed at index %0d", index)) endfunction @@ -379,9 +484,14 @@ class mem_bkdr_util extends uvm_object; // this is used to write 32bit of data plus 7 raw integrity bits. virtual function void write39integ(bit [bus_params_pkg::BUS_AW-1:0] addr, logic [38:0] data); + uvm_hdl_data_t rw_data; `_ACCESS_CHECKS(addr, 32) // this is essentially an aligned 32bit access. if (!check_addr_valid(addr)) return; - write(addr, data); + // Perform a read-modify-write to access the underlying memory architecture + rw_data = read(addr); + rw_data = row_adapter.write_row_data_39b(addr, data, rw_data); + // Note the write function takes care of interleaving, if used. + write(addr, rw_data); endfunction virtual function void write64(bit [bus_params_pkg::BUS_AW-1:0] addr, logic [63:0] data); @@ -490,13 +600,36 @@ class mem_bkdr_util extends uvm_object; endfunction // load mem from file - virtual task load_mem_from_file(string file); + virtual task load_mem_from_file(string file, bit recompute_ecc = 0); check_file(file, "r"); this.file = file; ->readmemh_event; // The delay below avoids a race condition between this mem backdoor load and a subsequent // backdoor write to a particular location. #0; + + // Recompute ECC if indicated (this allows to load an image that does not have ECC present). + if (recompute_ecc) begin + case (err_detection_scheme) + Ecc_22_16, EccHamming_22_16, EccInv_22_16, EccInvHamming_22_16: begin + for (int addr = 0; addr < depth; addr += bytes_per_word) begin + write16(addr, read(addr)); + end + end + Ecc_39_32, EccHamming_39_32, EccInv_39_32, EccInvHamming_39_32: begin + for (int addr = 0; addr < depth; addr += bytes_per_word) begin + write32(addr, read(addr)); + end + end + Ecc_72_64, EccHamming_72_64, EccInv_72_64, EccInvHamming_72_64: begin + for (int addr = 0; addr < depth; addr += bytes_per_word) begin + write64(addr, read(addr)); + end + end + // Nothing to recompute + default: ; + endcase + end endtask // save mem contents to file @@ -539,7 +672,16 @@ class mem_bkdr_util extends uvm_object; for (int i = 0; i < depth; i++) begin uvm_hdl_data_t data; `DV_CHECK_STD_RANDOMIZE_FATAL(data, "Randomization failed!", path) - data = get_ecc_computed_data(data); + if (`HAS_PARITY) begin + uvm_hdl_data_t raw_data = data; + for (int byte_idx = 0; byte_idx < bytes_per_word; byte_idx++) begin + bit raw_byte = raw_data[byte_idx * 8 +: 8]; + bit parity = (err_detection_scheme == ParityOdd) ? ~(^raw_byte) : (^raw_byte); + data[byte_idx * 9 +: 9] = {parity, raw_byte}; + end + end else begin + data = get_ecc_computed_data(data); + end write(i * bytes_per_word, data); end endfunction @@ -569,18 +711,6 @@ class mem_bkdr_util extends uvm_object; addr, rw_data, err_mask, rw_data ^ err_mask), UVM_HIGH) endfunction - // Wrapper function for backdoor write OTP partitions. - `include "mem_bkdr_util__otp.sv" - - // Wrapper functions for encrypted SRAM reads and writes. - `include "mem_bkdr_util__sram.sv" - - // Wrapper function for encrypted ROM reads. - `include "mem_bkdr_util__rom.sv" - - // Wrapper function for encrypted FLASH writes. - `include "mem_bkdr_util__flash.sv" - `undef HAS_ECC `undef HAS_PARITY @@ -595,7 +725,7 @@ endclass // memory with the contents of the file and `write_mem_to_file()` methods, to read the contents of // the memory into the file. // -// inst is the mem_bkdr_util instance created in the tesbench module. +// inst is the mem_bkdr_util instance created in the testbench module. // path is the raw path to the memory element in the design. `define MEM_BKDR_UTIL_FILE_OP(inst, path) \ fork \ diff --git a/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util__flash.sv b/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util__flash.sv deleted file mode 100644 index 56a961482d..0000000000 --- a/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util__flash.sv +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright lowRISC contributors (OpenTitan project). -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -// Wrapper functions to write different partitions in flash. -// This file is included in `mem_bkdr_util.sv` as a continuation of `mem_bkdr_util` class. - -localparam int unsigned FlashDataWidth = flash_phy_pkg::DataWidth; -localparam int unsigned FlashStagesPerCycle = FlashDataWidth / flash_phy_pkg::GfMultCycles; -localparam int unsigned FlashKeySize = flash_phy_pkg::KeySize; -localparam int unsigned FlashNumRoundsHalf = crypto_dpi_prince_pkg::NumRoundsHalf; -localparam int unsigned FlashAddrWidth = 16; - -function bit [FlashDataWidth-1:0] flash_gf_mult2(bit [FlashDataWidth-1:0] operand); - bit [FlashDataWidth-1:0] mult_out; - - mult_out = operand[FlashDataWidth-1] ? (operand << 1) ^ - flash_phy_pkg::ScrambleIPoly : (operand << 1); - return mult_out; -endfunction - -function bit [FlashStagesPerCycle-1:0][FlashDataWidth-1:0] flash_gen_matrix( - bit [FlashDataWidth-1:0] seed, bit init); - bit [FlashStagesPerCycle-1:0][FlashDataWidth-1:0] matrix_out; - - matrix_out[0] = init ? seed : flash_gf_mult2(seed); - matrix_out[FlashStagesPerCycle-1:1] = '0; - for (int i = 1; i < FlashStagesPerCycle; i++) begin - matrix_out[i] = flash_gf_mult2(matrix_out[i-1]); - end - return matrix_out; -endfunction - -function bit [FlashDataWidth-1:0] flash_galois_multiply(bit [FlashKeySize-1:0] addr_key, - bit [FlashAddrWidth-1:0] addr); - bit [FlashStagesPerCycle-1:0][FlashDataWidth-1:0] matrix[2]; - bit [FlashDataWidth-1:0] product[2]; - bit [FlashDataWidth-1:0] add_vector; - bit [FlashDataWidth-1:0] mult_out; - - // generate matrix. - matrix[0] = - flash_gen_matrix({addr_key[FlashKeySize-FlashAddrWidth-1:FlashKeySize-64], addr}, 1'b1); - matrix[1] = flash_gen_matrix(matrix[0][FlashStagesPerCycle-1], 1'b0); - // galois multiply. - for (int j = 0; j < 2; j++) begin - mult_out = '0; - for (int i = 0; i < FlashStagesPerCycle; i++) begin - add_vector = addr_key[(j*FlashStagesPerCycle)+i] ? matrix[j][i] : '0; - mult_out = mult_out ^ add_vector; - end - product[j] = mult_out; - end - product[1] = product[1] ^ product[0]; - return product[1]; -endfunction - -virtual function void flash_write_scrambled( - bit [FlashDataWidth-1:0] data, bit [FlashAddrWidth-1:0] byte_addr, - bit [FlashKeySize-1:0] flash_addr_key, bit [FlashKeySize-1:0] flash_data_key); - bit [FlashAddrWidth-1:0] word_addr; - bit [FlashDataWidth-1:0] mask; - bit [FlashDataWidth-1:0] masked_data; - bit [FlashNumRoundsHalf-1:0][FlashDataWidth-1:0] scrambled_data; - bit [71:0] ecc_72; - bit [75:0] ecc_76; - - word_addr = byte_addr >> addr_lsb; - mask = flash_galois_multiply(flash_addr_key, word_addr); - masked_data = data ^ mask; - - crypto_dpi_prince_pkg::sv_dpi_prince_encrypt(.plaintext(masked_data), .key(flash_data_key), - .old_key_schedule(0), .ciphertext(scrambled_data)); - masked_data = scrambled_data[FlashNumRoundsHalf-1] ^ mask; - // ecc functions used are hardcoded to a fixed sized. - ecc_72 = prim_secded_pkg::prim_secded_hamming_72_64_enc(data[63:0]); - ecc_76 = prim_secded_pkg::prim_secded_hamming_76_68_enc({ecc_72[67:64], masked_data[63:0]}); - write(byte_addr, ecc_76); -endfunction diff --git a/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util__otp.sv b/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util__otp.sv deleted file mode 100644 index 3ce18e438e..0000000000 --- a/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util__otp.sv +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright lowRISC contributors (OpenTitan project). -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -// Wrapper functions to write different partitions in OTP. -// This file is included in `mem_bkdr_util.sv` as a continuation of `mem_bkdr_util` class. - -virtual function void otp_write_lc_partition_state(lc_ctrl_state_pkg::lc_state_e lc_state); - for (int i = 0; i < LcStateSize; i += 4) begin - write32(i + LcStateOffset, lc_state[i*8+:32]); - end -endfunction : otp_write_lc_partition_state - -virtual function lc_ctrl_state_pkg::lc_state_e otp_read_lc_partition_state(); - lc_ctrl_state_pkg::lc_state_e lc_state; - for (int i = 0; i < LcStateSize; i += 4) begin - lc_state[i*8 +: 32] = read32(i + LcStateOffset); - end - - return lc_state; -endfunction : otp_read_lc_partition_state - -virtual function void otp_write_lc_partition_cnt(lc_ctrl_state_pkg::lc_cnt_e lc_cnt); - for (int i = 0; i < LcTransitionCntSize; i += 4) begin - write32(i + LcTransitionCntOffset, lc_cnt[i*8+:32]); - end -endfunction : otp_write_lc_partition_cnt - -function void otp_write_lc_partition(lc_ctrl_state_pkg::lc_cnt_e lc_cnt, - lc_ctrl_state_pkg::lc_state_e lc_state); - - otp_write_lc_partition_cnt(lc_cnt); - otp_write_lc_partition_state(lc_state); -endfunction : otp_write_lc_partition - -// The following steps are needed to backdoor write a secret partition: -// 1). Scramble the RAW input data. -// 2). Backdoor write the scrambled input data to OTP memory. -// 3). Calculate the correct digest for the secret partition. -// 4). Backdoor write digest data to OTP memory. -virtual function void otp_write_secret0_partition( - bit [TestUnlockTokenSize*8-1:0] unlock_token, - bit [TestExitTokenSize*8-1:0] exit_token); - bit [Secret0DigestSize*8-1:0] digest; - - bit [TestUnlockTokenSize*8-1:0] scrambled_unlock_token; - bit [TestExitTokenSize*8-1:0] scrambled_exit_token; - bit [bus_params_pkg::BUS_DW-1:0] secret_data[$]; - - for (int i = 0; i < TestUnlockTokenSize; i += 8) begin - scrambled_unlock_token[i*8+:64] = scramble_data(unlock_token[i*8+:64], Secret0Idx); - write64(i + TestUnlockTokenOffset, scrambled_unlock_token[i*8+:64]); - end - for (int i = 0; i < TestExitTokenSize; i += 8) begin - scrambled_exit_token[i*8+:64] = scramble_data(exit_token[i*8+:64], Secret0Idx); - write64(i + TestExitTokenOffset, scrambled_exit_token[i*8+:64]); - end - - secret_data = {<<32{scrambled_exit_token, scrambled_unlock_token}}; - digest = cal_digest(Secret0Idx, secret_data); - - write64(Secret0DigestOffset, digest); -endfunction - -virtual function void otp_write_secret1_partition( - bit [FlashAddrKeySeedSize*8-1:0] flash_addr_key_seed, - bit [FlashDataKeySeedSize*8-1:0] flash_data_key_seed, - bit [SramDataKeySeedSize*8-1:0] sram_data_key_seed); - bit [Secret1DigestSize*8-1:0] digest; - - bit [FlashAddrKeySeedSize*8-1:0] scrambled_flash_addr_key; - bit [FlashDataKeySeedSize*8-1:0] scrambled_flash_data_key; - bit [SramDataKeySeedSize*8-1:0] scrambled_sram_data_key; - bit [bus_params_pkg::BUS_DW-1:0] secret_data[$]; - - for (int i = 0; i < FlashAddrKeySeedSize; i += 8) begin - scrambled_flash_addr_key[i*8+:64] = scramble_data(flash_addr_key_seed[i*8+:64], Secret1Idx); - write64(i + FlashAddrKeySeedOffset, scrambled_flash_addr_key[i*8+:64]); - end - for (int i = 0; i < FlashDataKeySeedSize; i += 8) begin - scrambled_flash_data_key[i*8+:64] = scramble_data(flash_data_key_seed[i*8+:64], Secret1Idx); - write64(i + FlashDataKeySeedOffset, scrambled_flash_data_key[i*8+:64]); - end - for (int i = 0; i < SramDataKeySeedSize; i += 8) begin - scrambled_sram_data_key[i*8+:64] = scramble_data(sram_data_key_seed[i*8+:64], Secret1Idx); - write64(i + SramDataKeySeedOffset, scrambled_sram_data_key[i*8+:64]); - end - - secret_data = {<<32 {scrambled_sram_data_key, scrambled_flash_data_key, scrambled_flash_addr_key}}; - digest = cal_digest(Secret1Idx, secret_data); - - write64(Secret1DigestOffset, digest); -endfunction - -virtual function void otp_write_secret2_partition(bit [RmaTokenSize*8-1:0] rma_unlock_token, - bit [CreatorRootKeyShare0Size*8-1:0] creator_root_key0, - bit [CreatorRootKeyShare1Size*8-1:0] creator_root_key1 -); - - bit [Secret2DigestSize*8-1:0] digest; - - bit [RmaTokenSize*8-1:0] scrambled_unlock_token; - bit [CreatorRootKeyShare0Size*8-1:0] scrambled_root_key0; - bit [CreatorRootKeyShare1Size*8-1:0] scrambled_root_key1; - bit [bus_params_pkg::BUS_DW-1:0] secret_data[$]; - - for (int i = 0; i < RmaTokenSize; i+=8) begin - scrambled_unlock_token[i*8+:64] = scramble_data(rma_unlock_token[i*8+:64], Secret2Idx); - write64(i + RmaTokenOffset, scrambled_unlock_token[i*8+:64]); - end - for (int i = 0; i < CreatorRootKeyShare0Size; i+=8) begin - scrambled_root_key0[i*8+:64] = scramble_data(creator_root_key0[i*8+:64], Secret2Idx); - write64(i + CreatorRootKeyShare0Offset, scrambled_root_key0[i*8+:64]); - end - for (int i = 0; i < CreatorRootKeyShare1Size; i+=8) begin - scrambled_root_key1[i*8+:64] = scramble_data(creator_root_key1[i*8+:64], Secret2Idx); - write64(i + CreatorRootKeyShare1Offset, scrambled_root_key1[i*8+:64]); - end - - secret_data = {<<32 {scrambled_root_key1, scrambled_root_key0, scrambled_unlock_token}}; - digest = cal_digest(Secret2Idx, secret_data); - - write64(Secret2DigestOffset, digest); -endfunction - -virtual function void otp_write_hw_cfg0_partition( - bit [DeviceIdSize*8-1:0] device_id, bit [ManufStateSize*8-1:0] manuf_state); - bit [HwCfg0DigestSize*8-1:0] digest; - - bit [bus_params_pkg::BUS_DW-1:0] hw_cfg0_data[$]; - - for (int i = 0; i < DeviceIdSize; i += 4) begin - write32(i + DeviceIdOffset, device_id[i*8+:32]); - end - for (int i = 0; i < ManufStateSize; i += 4) begin - write32(i + ManufStateOffset, manuf_state[i*8+:32]); - end - - hw_cfg0_data = {<<32 {manuf_state, device_id}}; - digest = cal_digest(HwCfg0Idx, hw_cfg0_data); - - write64(HwCfg0DigestOffset, digest); -endfunction - -virtual function void otp_write_hw_cfg1_partition( - bit [EnCsrngSwAppReadSize*8-1:0] en_csrng_sw_app_read, - bit [EnSramIfetchSize*8-1:0] en_sram_ifetch, - bit [EnSramIfetchSize*8-1:0] dis_rv_dm_late_debug); - bit [HwCfg1DigestSize*8-1:0] digest; - - bit [bus_params_pkg::BUS_DW-1:0] hw_cfg1_data[$]; - - write32(EnSramIfetchOffset, {dis_rv_dm_late_debug, en_csrng_sw_app_read, en_sram_ifetch}); - - hw_cfg1_data = {<<32 {32'h0, dis_rv_dm_late_debug, en_csrng_sw_app_read, en_sram_ifetch}}; - digest = cal_digest(HwCfg1Idx, hw_cfg1_data); - - write64(HwCfg1DigestOffset, digest); -endfunction - -// Functions that clear the provisioning state of the buffered partitions. -// This is useful in tests that make front-door accesses for provisioning purposes. -virtual function void otp_clear_secret0_partition(); - for (int i = 0; i < Secret0Size; i += 4) begin - write32(i + Secret0Offset, 32'h0); - end -endfunction - -virtual function void otp_clear_secret1_partition(); - for (int i = 0; i < Secret1Size; i += 4) begin - write32(i + Secret1Offset, 32'h0); - end -endfunction - -virtual function void otp_clear_secret2_partition(); - for (int i = 0; i < Secret2Size; i += 4) begin - write32(i + Secret2Offset, 32'h0); - end -endfunction - -virtual function void otp_clear_hw_cfg0_partition(); - for (int i = 0; i < HwCfg0Size; i += 4) begin - write32(i + HwCfg0Offset, 32'h0); - end -endfunction diff --git a/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util__rom.sv b/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util__rom.sv deleted file mode 100644 index b2904435fd..0000000000 --- a/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util__rom.sv +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright lowRISC contributors (OpenTitan project). -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -// Wrapper functions for ROM's encrypted read operation. -// This file is included in `mem_bkdr_util.sv` as a continuation of `mem_bkdr_util` class. - -// The data decoding is different from SRAM, but most of the underlying SRAM functions are reused -// Also note that this function returns the raw data rather than data + syndrome + error because -// the rom_ctrl testbench needs this for checking. -virtual function bit [38:0] rom_encrypt_read32(bit [bus_params_pkg::BUS_AW-1:0] addr, - logic [SRAM_KEY_WIDTH-1:0] key, - logic [SRAM_BLOCK_WIDTH-1:0] nonce, - bit unscramble_data); - - logic [bus_params_pkg::BUS_AW-1:0] mem_addr = '0; - logic [38:0] data = '0; - - logic addr_arr [] = new[addr_width]; - logic scrambled_addr[] = new[addr_width]; - logic data_arr [] = new[39]; - logic key_arr [] = new[SRAM_KEY_WIDTH]; - logic nonce_arr [] = new[SRAM_BLOCK_WIDTH]; - logic keystream [] = new[SRAM_BLOCK_WIDTH]; - logic zero_key [] = new[39]; - - key_arr = {<<{key}}; - nonce_arr = {<<{nonce}}; - - for (int i = 0; i < addr_width; i++) begin - addr_arr[i] = addr[addr_lsb + i]; - end - - // Calculate the scrambled address - scrambled_addr = sram_scrambler_pkg::encrypt_sram_addr(addr_arr, addr_width, nonce_arr); - - for (int i = 0; i < addr_width; i++) begin - mem_addr[i] = scrambled_addr[i]; - end - - // Read memory and get the encrypted data - if (!check_addr_valid(mem_addr << addr_lsb)) begin - return 'x; - end - - // 39-bit memory word includes 32-bit data + 7-bit ECC - data = read(mem_addr << addr_lsb); - - if (!unscramble_data) begin - return data; - end - - data_arr = {<<{data}}; - - // Generate the keystream - keystream = sram_scrambler_pkg::gen_keystream(addr_arr, addr_width, key_arr, nonce_arr); - - for (int i = 0; i < 39; i++) begin - zero_key[i] = '0; - end - - for (int i = 0; i < 39; i++) begin - data[i] = data_arr[i] ^ keystream[i]; - end - - return data; -endfunction - - -virtual function void rom_encrypt_write32_integ(logic [bus_params_pkg::BUS_AW-1:0] addr, - logic [38:0] data, - logic [SRAM_KEY_WIDTH-1:0] key, - logic [SRAM_BLOCK_WIDTH-1:0] nonce, - bit scramble_data, - bit [38:0] flip_bits = 0); - logic [bus_params_pkg::BUS_AW-1:0] bus_addr = '0; - logic [38:0] integ_data; - logic [38:0] scrambled_data; - - logic wdata_arr [] = new[39]; - logic scrambled_addr [] = new[addr_width]; - logic rom_addr [] = new[addr_width]; - logic key_arr [] = new[SRAM_KEY_WIDTH]; - logic nonce_arr [] = new[SRAM_BLOCK_WIDTH]; - - key_arr = {<<{key}}; - nonce_arr = {<<{nonce}}; - - for (int i = 0; i < addr_width; i++) begin - rom_addr[i] = addr[addr_lsb + i]; - end - - // Calculate the scrambled address - scrambled_addr = sram_scrambler_pkg::encrypt_sram_addr(rom_addr, addr_width, nonce_arr); - - if (scramble_data) begin - // Calculate the integrity constant - integ_data = prim_secded_pkg::prim_secded_inv_39_32_enc(data); - - // flip some bits to inject integrity fault - integ_data ^= flip_bits; - - // Calculate the scrambled data - wdata_arr = {<<{integ_data}}; - wdata_arr = sram_scrambler_pkg::encrypt_sram_data( - wdata_arr, 39, 39, rom_addr, addr_width, key_arr, nonce_arr - ); - scrambled_data = {<<{wdata_arr}}; - end - else begin - scrambled_data = data; - end - - // Construct bus representation of the address - for (int i = 0; i < addr_lsb; i++) begin - bus_addr[i] = addr[i]; - end - for (int i = 0; i < addr_width; i++) begin - bus_addr[addr_lsb + i] = scrambled_addr[i]; - end - // Write the scrambled data to memory - write39integ(bus_addr, scrambled_data); -endfunction - -virtual function bit [7:0] rom_encrypt_read8(bit [bus_params_pkg::BUS_AW-1:0] addr, - logic [SRAM_KEY_WIDTH-1:0] key, - logic [SRAM_BLOCK_WIDTH-1:0] nonce, - bit unscramble_data = 1); - int byte_offset = addr % bytes_per_word; - bit [bus_params_pkg::BUS_AW-1:0] aligned_addr = (addr >> addr_lsb) << addr_lsb; - bit [38:0] data = rom_encrypt_read32(aligned_addr, key, nonce, unscramble_data); - return (data >> (byte_offset * byte_width)) & 8'hff; -endfunction - -virtual function void rom_encrypt_write8(bit [bus_params_pkg::BUS_AW-1:0] addr, - logic [7:0] data, - logic [SRAM_KEY_WIDTH-1:0] key, - logic [SRAM_BLOCK_WIDTH-1:0] nonce, - bit scramble_data = 1); - bit [bus_params_pkg::BUS_AW-1:0] aligned_addr = (addr >> addr_lsb) << addr_lsb; - int byte_offset = addr % bytes_per_word; - bit [31:0] rw_data = 32'(rom_encrypt_read32(addr, key, nonce, scramble_data)); - - rw_data[byte_offset * 8 +: 8] = data; - rom_encrypt_write32_integ(aligned_addr, rw_data, key, nonce, scramble_data); -endfunction - -virtual function void update_rom_digest(logic [SRAM_KEY_WIDTH-1:0] key, - logic [SRAM_BLOCK_WIDTH-1:0] nonce); - bit [63:0] kmac_data[$]; - bit [7:0] kmac_data_arr[]; - bit [7:0] dpi_digest[kmac_pkg::AppDigestW / 8]; - int kmac_data_bytes = size_bytes - ROM_DIGEST_BYTES; - int digest_start_addr = kmac_data_bytes; - bit scramble_data = 0; // digest and kmac data aren't scrambled - - // Each 4 byte of data is transferred as 5 bytes - int xfer_bytes = kmac_data_bytes * 5 / 4; - kmac_data_arr = new[xfer_bytes]; - `uvm_info(`gfn, $sformatf("Actual bytes: %d, xfer'd: %d", kmac_data_bytes, xfer_bytes), UVM_DEBUG) - - for (int i = 0; i < kmac_data_bytes; i += 4) begin - bit [39:0] data40; - - // it returns 39 bits, including integrity. and the 39 bits data will be sent to 40 bits bus to - // the kmac. The kmac bus has byte strobes that are used to indicate 5 bytes instead of the full - // 8. - data40 = 40'(rom_encrypt_read32(i, key, nonce, scramble_data)); - for (int j = 0; j < 5; j++) begin - // At byte position 0, we want bytes 0, 1, 2, 3, 4 - // At byte position 4, we want bytes 5, 6, 7, 8, 9 - // At byte position 8, we want bytes 10, 11, 12, 13, 14 - int idx = i + (i / 4) + j; - kmac_data_arr[idx] = data40[j * 8 +: 8]; - end - end - digestpp_dpi_pkg::c_dpi_cshake256(kmac_data_arr, "", "ROM_CTRL", kmac_data_arr.size, - kmac_pkg::AppDigestW / 8, dpi_digest); - - for (int i = 0; i < ROM_DIGEST_BYTES; i++) begin - rom_encrypt_write8(digest_start_addr + i, dpi_digest[i], key, nonce, scramble_data); - end -endfunction diff --git a/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util__sram.sv b/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util__sram.sv deleted file mode 100644 index 9fe8a69ce4..0000000000 --- a/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util__sram.sv +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright lowRISC contributors (OpenTitan project). -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -// Wrapper functions for SRAM's encrypted read/write operations. -// This file is included in `mem_bkdr_util.sv` as a continuation of `mem_bkdr_util` class. - -// Returns the address after scrambling it using the given nonce. -function logic [bus_params_pkg::BUS_AW-1:0] get_sram_encrypt_addr ( - logic [bus_params_pkg::BUS_AW-1:0] addr, - logic [SRAM_BLOCK_WIDTH-1:0] nonce, - logic [31:0] extra_addr_bits); - - int full_addr_width = addr_width + extra_addr_bits; - - logic [bus_params_pkg::BUS_AW-1:0] scr_addr; - logic scr_addr_arr [] = new[full_addr_width]; - logic addr_arr [] = new[full_addr_width]; - logic nonce_arr [] = new[SRAM_BLOCK_WIDTH]; - - nonce_arr = {<<{nonce}}; - for (int i = 0; i < full_addr_width; i++) begin - addr_arr[i] = addr[addr_lsb + i]; - end - - scr_addr_arr = sram_scrambler_pkg::encrypt_sram_addr(addr_arr, full_addr_width, nonce_arr); - - // Convert to bus address output. - for (int i = 0; i < addr_lsb; i++) begin - scr_addr[i] = addr[i]; - end - for (int i = 0; i < full_addr_width; i++) begin - scr_addr[addr_lsb + i] = scr_addr_arr[i]; - end - return scr_addr; -endfunction : get_sram_encrypt_addr - -// Returns the data after adding integrity bits and encrypting it with the given key and nonce. -// If flip_bits is non-zero it may introduce integrity errors, but notice there is a small chance -// after descrambling the data the errors will not be detected. -function logic [38:0] get_sram_encrypt32_intg_data ( - logic [bus_params_pkg::BUS_AW-1:0] addr, - logic [31:0] data, - logic [SRAM_KEY_WIDTH-1:0] key, - logic [SRAM_BLOCK_WIDTH-1:0] nonce, - int extra_addr_bits, - bit [38:0] flip_bits = '0); - - logic [38:0] integ_data; - logic [38:0] scrambled_data; - - int full_addr_width = addr_width + extra_addr_bits; - logic wdata_arr [] = new[39]; - logic addr_arr [] = new[full_addr_width]; - logic key_arr [] = new[SRAM_KEY_WIDTH]; - logic nonce_arr [] = new[SRAM_BLOCK_WIDTH]; - - key_arr = {<<{key}}; - nonce_arr = {<<{nonce}}; - - for (int i = 0; i < full_addr_width; i++) begin - addr_arr[i] = addr[addr_lsb + i]; - end - - integ_data = prim_secded_pkg::prim_secded_inv_39_32_enc(data); - integ_data ^= flip_bits; - - wdata_arr = {<<{integ_data}}; - wdata_arr = sram_scrambler_pkg::encrypt_sram_data( - wdata_arr, 39, 39, addr_arr, full_addr_width, key_arr, nonce_arr - ); - scrambled_data = {<<{wdata_arr}}; - return scrambled_data; -endfunction : get_sram_encrypt32_intg_data - -// Returns the data at the given address after descrambling the address and decrypting the data. -// It simply ignores the integrity bits. -virtual function logic [38:0] sram_encrypt_read32_integ(logic [bus_params_pkg::BUS_AW-1:0] addr, - logic [SRAM_KEY_WIDTH-1:0] key, - logic [SRAM_BLOCK_WIDTH-1:0] nonce, - int extra_addr_bits); - logic [bus_params_pkg::BUS_AW-1:0] scr_addr = get_sram_encrypt_addr(addr, nonce, extra_addr_bits); - logic [38:0] rdata39 = _sram_decrypt_read39(addr, scr_addr, key, nonce, extra_addr_bits); - return rdata39[31:0]; -endfunction : sram_encrypt_read32_integ - -// This reads the data at a scrambled address and decrypts it. It returns the data and -// integrity bits. -local function logic [38:0] _sram_decrypt_read39( - logic [bus_params_pkg::BUS_AW-1:0] addr, - logic [bus_params_pkg::BUS_AW-1:0] scr_addr, - logic [SRAM_KEY_WIDTH-1:0] key, - logic [SRAM_BLOCK_WIDTH-1:0] nonce, - int extra_addr_bits); - logic [38:0] rdata39 = '0; - - logic rdata_arr [] = new[39]; - logic addr_arr [] = new[addr_width]; - logic key_arr [] = new[SRAM_KEY_WIDTH]; - logic nonce_arr [] = new[SRAM_BLOCK_WIDTH]; - int full_addr_width = addr_width + extra_addr_bits; - - key_arr = {<<{key}}; - nonce_arr = {<<{nonce}}; - for (int i = 0; i < full_addr_width; i++) begin - addr_arr[i] = addr[addr_lsb + i]; - end - - rdata39 = read39integ(scr_addr); - `uvm_info(`gfn, $sformatf("scr data: 0x%0x", rdata39), UVM_HIGH) - rdata_arr = {<<{rdata39}}; - rdata_arr = sram_scrambler_pkg::decrypt_sram_data( - rdata_arr, 39, 39, addr_arr, full_addr_width, key_arr, nonce_arr - ); - rdata39 = {<<{rdata_arr}}; - return rdata39; -endfunction : _sram_decrypt_read39 - -// Writes the data at the given address. It scrambles the address and encrypts the data after -// adding integrity bits. If flip_bits is non-zero it may introduce ecc errors. -virtual function void sram_encrypt_write32_integ(logic [bus_params_pkg::BUS_AW-1:0] addr, - logic [31:0] data, - logic [SRAM_KEY_WIDTH-1:0] key, - logic [SRAM_BLOCK_WIDTH-1:0] nonce, - int extra_addr_bits, - bit [38:0] flip_bits = 0); - logic [bus_params_pkg::BUS_AW-1:0] scr_addr = get_sram_encrypt_addr(addr, nonce, extra_addr_bits); - _sram_encrypt_write39(addr, scr_addr, data, key, nonce, extra_addr_bits, flip_bits); -endfunction : sram_encrypt_write32_integ - - -// This encrypts, possibly flips some bits to inject errors, and writes the resulting data -// to a scrambled address. -local function void _sram_encrypt_write39(logic [bus_params_pkg::BUS_AW-1:0] addr, - logic [bus_params_pkg::BUS_AW-1:0] scr_addr, - logic [31:0] data, - logic [SRAM_KEY_WIDTH-1:0] key, - logic [SRAM_BLOCK_WIDTH-1:0] nonce, - int extra_addr_bits, - bit [38:0] flip_bits); - logic [38:0] scrambled_data = get_sram_encrypt32_intg_data(addr, data, key, nonce, extra_addr_bits, flip_bits); - write39integ(scr_addr, scrambled_data); -endfunction : _sram_encrypt_write39 - -// This injects integrity errors in sram for an original address and the corresponding -// scrambled address. It needs to pass both addresses even though only the scrambled address -// is affected, since the original address is used to encrypt the data. -// -// This code needs to try multiple random data since it is possible after encryption the -// bit pattern will not result in a data error, as described in issue #10976 -virtual function void sram_inject_integ_error(logic [bus_params_pkg::BUS_AW-1:0] addr, - logic [bus_params_pkg::BUS_AW-1:0] scr_addr, - logic [SRAM_KEY_WIDTH-1:0] key, - logic [SRAM_BLOCK_WIDTH-1:0] nonce, - int extra_addr_bits); - int max_attempts = 40; - int attempt = 0; - - while (attempt < max_attempts) begin - bit [31:0] data = $urandom(); - bit [38:0] rdata_integ; - prim_secded_pkg::secded_inv_39_32_t dec; - // The specific bits to be flipped should be irrelevant. - _sram_encrypt_write39(addr, scr_addr, data, key, nonce, extra_addr_bits, 39'h1001); - rdata_integ = _sram_decrypt_read39(addr, scr_addr, key, nonce, extra_addr_bits); - dec = prim_secded_pkg::prim_secded_inv_39_32_dec(rdata_integ); - if (dec.err) begin - `uvm_info(`gfn, $sformatf( - "sram_inject_integ_error addr 0x%x, data 0x%x injects error %b after %0d attempts", - addr, rdata_integ, dec.err, attempt), - UVM_MEDIUM) - break; - end - ++attempt; - end - `DV_CHECK_LT(attempt, max_attempts, "Too many attempts in sram_inject_ecc_error") -endfunction : sram_inject_integ_error diff --git a/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util_pkg.sv b/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util_pkg.sv index b9bc489062..1a7f60307f 100644 --- a/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util_pkg.sv +++ b/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util_pkg.sv @@ -7,11 +7,7 @@ package mem_bkdr_util_pkg; import bus_params_pkg::BUS_AW; import dv_utils_pkg::uint32_t, dv_utils_pkg::addr_range_t; import lc_ctrl_state_pkg::*; - import otp_ctrl_part_pkg::*; - import otp_ctrl_reg_pkg::*; - import otp_scrambler_pkg::*; import prim_secded_pkg::*; - import sram_scrambler_pkg::*; import uvm_pkg::*; // Represents the various forms of error detection / correction supported. @@ -39,13 +35,11 @@ package mem_bkdr_util_pkg; ParityOdd } err_detection_e; - parameter int ROM_DIGEST_SIZE = 256; - parameter int ROM_DIGEST_BYTES = ROM_DIGEST_SIZE / 8; // macro includes `include "uvm_macros.svh" `include "dv_macros.svh" // sources + `include "mem_bkdr_util_row_adapter.sv" `include "mem_bkdr_util.sv" - endpackage diff --git a/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util_row_adapter.sv b/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util_row_adapter.sv new file mode 100644 index 0000000000..4121a616fd --- /dev/null +++ b/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util_row_adapter.sv @@ -0,0 +1,57 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Provide an abstract way to access the memory rows +// +// Integrators can subclass this to provide a specfic way of accessing a memory row +// and incorporate the phyical architecture. +// +class mem_bkdr_util_row_adapter; + + // A row might have additional extra bits + protected uint32_t num_extra_bits = 0; + + // Return the number of extra bits of this row architecture + function uint32_t get_num_extra_bits(); + return num_extra_bits; + endfunction + + // Translates a raw encoded UVM data row from the memory in a contiguous + // row of memory. + // + virtual function uvm_hdl_data_t decode_row(uvm_hdl_data_t read_data); + return read_data; + endfunction + + // Translates a contiguous UVM data row to the internal organization of a row + // that can be written to the memory. + // + virtual function uvm_hdl_data_t encode_row(uvm_hdl_data_t write_data); + return write_data; + endfunction + + // Writes a 39 bit word into a decoded row data depending on the memory architecture + + // Given decoded `row_data`, a 39-bit `data` word to be written, and an address, return the + // decoded row data with the data word at the correct position for the memory architecture and + // the given address. + virtual function uvm_hdl_data_t write_row_data_39b(bit [bus_params_pkg::BUS_AW-1:0] addr, + logic [38:0] data, + uvm_hdl_data_t row_data); + row_data[38:0] = data; + return row_data; + endfunction + + // Reads a 39 bit word from decoded row data depending on the memory architecture + + // Given decoded `row_data` and an address, return the 39-bit data from the correct position + // for the memory architecture and the given address. + virtual function logic [38:0] read_row_data_39b(bit [bus_params_pkg::BUS_AW-1:0] addr, + uvm_hdl_data_t row_data); + logic data; + data = row_data[38:0]; + return data; + endfunction + +endclass diff --git a/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/otp_scrambler_pkg.sv b/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/otp_scrambler_pkg.sv deleted file mode 100644 index 74a8cf6ced..0000000000 --- a/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/otp_scrambler_pkg.sv +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright lowRISC contributors (OpenTitan project). -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -///////////////////////////////////////////////// -// OTP secret data and digest scrambling logic // -///////////////////////////////////////////////// - -package otp_scrambler_pkg; - - import uvm_pkg::*; - import otp_ctrl_reg_pkg::*; - import otp_ctrl_part_pkg::*; - import bus_params_pkg::*; - - `include "uvm_macros.svh" - - parameter int SCRAMBLE_DATA_SIZE = 64; - parameter int SCRAMBLE_KEY_SIZE = 128; - parameter int NUM_ROUND = 31; - string path = "otp_scrambler_pkg"; - - // When secret data write into otp_array, it will be scrambled. - function automatic bit [SCRAMBLE_DATA_SIZE-1:0] scramble_data( - bit [SCRAMBLE_DATA_SIZE-1:0] input_data, - int part_idx - ); - - int secret_idx = part_idx - Secret0Idx; - crypto_dpi_present_pkg::sv_dpi_present_encrypt(input_data, - RndCnstKey[secret_idx], - SCRAMBLE_KEY_SIZE, - NUM_ROUND, - scramble_data); - endfunction - - // When secret data read out of otp_array, it will be descrambled. - function automatic bit [SCRAMBLE_DATA_SIZE-1:0] descramble_data( - bit [SCRAMBLE_DATA_SIZE-1:0] input_data, - int part_idx - ); - - int secret_idx = part_idx - Secret0Idx; - - crypto_dpi_present_pkg::sv_dpi_present_decrypt(input_data, - RndCnstKey[secret_idx], - SCRAMBLE_KEY_SIZE, - NUM_ROUND, - descramble_data); - endfunction - - function automatic bit [SCRAMBLE_DATA_SIZE-1:0] cal_digest(int part_idx, - ref bit [BUS_DW-1:0] mem_q[$]); - int array_size = mem_q.size(); - real key_factor = SCRAMBLE_KEY_SIZE / BUS_DW; - bit [SCRAMBLE_DATA_SIZE-1:0] init_vec = RndCnstDigestIV[0]; - bit [SCRAMBLE_DATA_SIZE-1:0] enc_data; - bit [SCRAMBLE_DATA_SIZE-1:0] digest; - - for (int i = 0; i < $ceil(array_size / key_factor); i++) begin - bit [SCRAMBLE_DATA_SIZE-1:0] input_data = (i == 0) ? init_vec : digest; - bit [SCRAMBLE_KEY_SIZE-1:0] key; - - // Pad 32-bit partition data into 128-bit key input. - // Because the mem_q size is a multiple of 64-bit, so if the last round only has 64-bits key, - // it will repeat the last 64-bits twice. - for (int j = 0; j < key_factor; j++) begin - int index = i * key_factor + j; - key |= ((index >= array_size ? mem_q[index-2] : mem_q[index]) << (j * BUS_DW)); - end - - // Trigger 32 round of PRESENT encrypt. - crypto_dpi_present_pkg::sv_dpi_present_encrypt(input_data, key, SCRAMBLE_KEY_SIZE, - NUM_ROUND, enc_data); - // XOR the previous state into the digest result according to the Davies-Meyer scheme. - digest = enc_data ^ input_data; - end - - // Last 32 round of digest is calculated with a digest constant. - crypto_dpi_present_pkg::sv_dpi_present_encrypt(digest, - RndCnstDigestConst[0], - SCRAMBLE_KEY_SIZE, NUM_ROUND, - enc_data); - // XOR the previous state into the digest result according to the Davies-Meyer scheme. - digest ^= enc_data; - return digest; - endfunction - -endpackage diff --git a/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/sram_scrambler_pkg.sv b/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/sram_scrambler_pkg.sv deleted file mode 100644 index b86dd4368c..0000000000 --- a/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/sram_scrambler_pkg.sv +++ /dev/null @@ -1,363 +0,0 @@ -// Copyright lowRISC contributors (OpenTitan project). -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -//////////////////////////////////////////// -// SRAM address and data scrambling logic // -/////////////////////////////////////////// -// -// There are a few general things to note here: -// -// - SRAM data scrambling relies on a reduced-round PRINCE cipher, plus a custom substitution -// and permutation network loosely based off of PRESENT. -// -// - SRAM address scrambling relies solely on the custom substitution and permutation network. -// -// - The custom subst/perm network used for data scrambling operates at byte granularity, -// while for address scrambling it operates at a granularity of the address width. -// -// - For DV purposes we can safely rely on the PRESENT sboxes, as nightly regressions are -// completely passing plus the sboxes in `prim_cipher_pkg` are copied directly from the -// PRESENT specifications. -// This has the side effect of allowing us to avoid duplication of the sboxes, which lowers the -// probability of an error in translation. - -package sram_scrambler_pkg; - - import uvm_pkg::*; - import bus_params_pkg::BUS_AW; - import crypto_dpi_prince_pkg::*; - import prim_cipher_pkg::*; - - `include "uvm_macros.svh" - - string path = "sram_scrambler_pkg"; - - // Fixed key size - PRINCE cipher operates on a 128-bit key, - // and the same key is used for all parallel cipher instances. - parameter int SRAM_KEY_WIDTH = 128; - - // Fixed data block size - PRINCE cipher operates on 64-bit data blocks. - parameter int SRAM_BLOCK_WIDTH = 64; - - parameter int NUM_PRINCE_ROUNDS_HALF = 3; - parameter int NUM_SP_ROUNDS = 2; - - // Create a generic typedef for dynamic array of logic to be able to return these values. - typedef logic state_t[]; - - // The sboxes operate on nibbles. - // - // If `WIDTH % 4 != 0`, the uppermost bits will get shifted to lower positions - // during either the `flip_vector` or `perm_layer` stage of the network, - // so it is guaranted that all bits will eventually go through an sbox. - function automatic state_t sbox_layer(state_t state, int width, bit inv); - logic state_out[] = new[width](state); - logic [3:0] sbox_in; - logic [3:0] sbox_out; - for (int i = 0; i < width / 4; i++) begin - // `with` syntax is currently unsupported by Verible, - // uncomment once support has been added - // - //sbox_in = {<< {state with [i*4 +: 4]}}; - for (int j = 0; j < 4; j++) begin - sbox_in[j] = state[i*4 + j]; - end - - if (inv) begin - sbox_out = prim_cipher_pkg::PRESENT_SBOX4_INV[sbox_in]; - end else begin - sbox_out = prim_cipher_pkg::PRESENT_SBOX4[sbox_in]; - end - - for (int j = 0; j < 4; j++) begin - state_out[i*4 + j] = sbox_out[j]; - end - end - return state_out; - endfunction : sbox_layer - - // Reverse the input bit vector. - function automatic state_t flip_vector(state_t state); - return {<< {state}}; - endfunction : flip_vector - - // Permutation layer - all even indexed bits move to the lower half, - // and all odd indexed bits move to the top half. - function automatic state_t perm_layer(state_t state, int width, bit inv); - logic state_out[] = new[width](state); - for (int i = 0; i < width / 2; i++) begin - if (inv) begin - state_out[i * 2] = state[i]; - state_out[i * 2 + 1] = state[i + width / 2]; - end else begin - state_out[i] = state[i * 2]; - state_out[i + width / 2] = state[i * 2 + 1]; - end - end - return state_out; - endfunction : perm_layer - - // Performs NUM_SP_ROUNDS full encryption rounds - function automatic state_t sp_encrypt(state_t data, int width, state_t key); - logic state[] = new[width](data); - for (int i = 0; i < NUM_SP_ROUNDS; i++) begin - // xor the data and key - for (int j = 0; j < width; j++) begin - state[j] = state[j] ^ key[j]; - end - // sbox layer - state = sbox_layer(state, width, 0); - // flip the bit vector - state = flip_vector(state); - // permutation layer - state = perm_layer(state, width, 0); - end - // final xor - for (int i = 0; i < width; i++) begin - state[i] = state[i] ^ key[i]; - end - return state; - endfunction : sp_encrypt - - // Performs NUM_SP_ROUNDS full decryption rounds - function automatic state_t sp_decrypt(state_t data, int width, state_t key); - logic state[] = new[width](data); - for (int i = 0; i < NUM_SP_ROUNDS; i++) begin - // xor data and key - for (int j = 0; j < width; j++) begin - state[j] = state[j] ^ key[j]; - end - // permutation layer - state = perm_layer(state, width, 1); - // flip bit vector - state = flip_vector(state); - // sbox layer - state = sbox_layer(state, width, 1'b1); - end - // final xor - for (int i = 0; i < width; i++) begin - state[i] = state[i] ^ key[i]; - end - return state; - endfunction : sp_decrypt - - // Generates the 64-bit keystream that is XORed with the data to obtain a ciphertext. - // Assumes that the data is at most 64 bits wide. - // - // Should not be called directly. - function automatic state_t gen_keystream(logic addr[], int addr_width, - logic key[], logic nonce[]); - logic [NUM_PRINCE_ROUNDS_HALF-1:0][SRAM_BLOCK_WIDTH-1:0] prince_result_arr; - - logic [SRAM_BLOCK_WIDTH-1:0] prince_plaintext; - logic [SRAM_KEY_WIDTH-1:0] prince_key; - logic [SRAM_BLOCK_WIDTH-1:0] prince_result; - - logic iv[] = new[SRAM_BLOCK_WIDTH]; - logic key_out[] = new[SRAM_BLOCK_WIDTH]; - - // IV is composed of nonce concatenated with address - for (int i = 0; i < addr_width; i++) begin - iv[i] = addr[i]; - end - for (int i = 0; i < SRAM_BLOCK_WIDTH - addr_width; i++) begin - iv[addr_width + i] = nonce[i]; - end - - //for (int i = 0; i < SRAM_BLOCK_WIDTH - addr_width; i++) begin - // iv[addr_width + i] = nonce[i]; - //end - - // convert arrays to packed vectors before invoking prince DPI model - prince_plaintext = {<< {iv}}; - // `with` syntax is currently unsupported by Verible, - // uncomment once support has been added - // - // prince_key = {<< {key with [0 +: SRAM_KEY_WIDTH]}}; - for (int i = 0; i < SRAM_KEY_WIDTH; i++) begin - prince_key[i] = key[i]; - end - - crypto_dpi_prince_pkg::sv_dpi_prince_encrypt(.plaintext(prince_plaintext), - .key(prince_key), - .old_key_schedule(0), - .ciphertext(prince_result_arr)); - prince_result = prince_result_arr[NUM_PRINCE_ROUNDS_HALF-1]; - - key_out = {<< {prince_result}}; - - return key_out; - endfunction : gen_keystream - - // Encrypts the target SRAM address using the custom S&P network. - function automatic state_t encrypt_sram_addr(logic addr[], int addr_width, - logic full_nonce[]); - - logic nonce[] = new[addr_width]; - logic encrypted_addr[] = new[addr_width]; - - // The address encryption nonce is the same width as the address, - // and is constructed from the top addr_width bits of the full nonce. - // - // `with` syntax is currently unsupported by Verible, - // uncomment once support has been added - // - // nonce = {>> {full_nonce with [SRAM_BLOCK_WIDTH - addr_width +: addr_width]}}; - for (int i = 0; i < addr_width; i++) begin - nonce[i] = full_nonce[SRAM_BLOCK_WIDTH - addr_width + i]; - end - encrypted_addr = sp_encrypt(addr, addr_width, nonce); - return encrypted_addr; - - endfunction : encrypt_sram_addr - - // Decrypts the target SRAM address using the custom S&P network. - function automatic state_t decrypt_sram_addr(logic addr[], int addr_width, - logic full_nonce[]); - - logic nonce[] = new[addr_width]; - logic encrypted_addr[] = new[addr_width]; - - // The address encryption nonce is the same width as the address, - // and is constructed from the top addr_width bits of the full nonce. - // - // `with` syntax is currently unsupported by Verible, - // uncomment once support has been added - // - // nonce = {>> {full_nonce with [SRAM_BLOCK_WIDTH - addr_width +: addr_width]}}; - for (int i = 0; i < addr_width; i++) begin - nonce[i] = full_nonce[SRAM_BLOCK_WIDTH - addr_width + i]; - end - - encrypted_addr = sp_decrypt(addr, addr_width, nonce); - return encrypted_addr; - - endfunction : decrypt_sram_addr - - // SRAM data encryption is more involved, we need to run 3 rounds of PRINCE on the nonce and key - // and then XOR the result with the data. - // - // Optionally, the XORed data can be passed through the S&P network. - function automatic state_t encrypt_sram_data(logic data[], int data_width, int sp_width, - logic addr[], int addr_width, - logic key[], logic nonce[], bit use_sp_layer = 0); - logic keystream[] = new[SRAM_BLOCK_WIDTH]; - logic data_enc[] = new[data_width]; - logic byte_to_enc[] = new[8]; - logic enc_byte[] = new[8]; - logic zero_key[] = new[data_width]; - int ks_width = (data_width < 64) ? data_width : 64; - - // the key used for byte diffusion is all-zero. - for (int i = 0; i < data_width; i++) begin - zero_key[i] = '0; - end - - // Generate the keystream - keystream = gen_keystream(addr, addr_width, key, nonce); - - // XOR keystream with input data - // Assumes ks_width <= 64. - for (int i = 0; i < data_width; i++) begin - data_enc[i] = data[i] ^ keystream[i % ks_width]; - end - - if (use_sp_layer) begin - if (data_width == sp_width) begin - // pass the entire word through the subst/perm network at once (the next cases would give the - // same results too, but this should be a bit more efficient) - data_enc = sp_encrypt(data_enc, data_width, zero_key); - end else if (sp_width == 8) begin - // pass each byte of the encoded result through the subst/perm network (special case of the - // general code below) - for (int i = 0; i < data_width / 8; i++) begin - byte_to_enc = data_enc[i*8 +: 8]; - enc_byte = sp_encrypt(byte_to_enc, 8, zero_key); - data_enc[i*8 +: 8] = enc_byte; - end - end else begin - // divide the word into sp_width chunks to pass it through the subst/perm network - for (int chunk_lsb = 0; chunk_lsb < data_width; chunk_lsb += sp_width) begin - int bits_remaining = data_width - chunk_lsb; - int chunk_width = (bits_remaining < sp_width) ? bits_remaining : sp_width; - logic chunk[] = new[chunk_width]; - - for (int j = 0; j < chunk_width; j++) begin - chunk[j] = data_enc[chunk_lsb + j]; - end - chunk = sp_encrypt(chunk, chunk_width, zero_key); - for (int j = 0; j < chunk_width; j++) begin - data_enc[chunk_lsb + j] = chunk[j]; - end - end - end - end - return data_enc; - - endfunction : encrypt_sram_data - - function automatic state_t decrypt_sram_data(logic data[], int data_width, int sp_width, - logic addr[], int addr_width, - logic key[], logic nonce[], bit use_sp_layer = 0); - logic keystream[] = new[SRAM_BLOCK_WIDTH]; - logic data_dec[] = new[data_width]; - logic byte_to_dec[] = new[8]; - logic dec_byte[] = new[8]; - logic zero_key[] = new[data_width]; - int ks_width = (data_width < 64) ? data_width : 64; - - // the key used for byte diffusion is all-zero. - for (int i = 0; i < data_width; i++) begin - zero_key[i] = '0; - end - - // Generate the keystream - keystream = gen_keystream(addr, addr_width, key, nonce); - - if (use_sp_layer) begin - if (data_width == sp_width) begin - // pass the entire word through the subst/perm network at once (the next cases would give the - // same results too, but this should be a bit more efficient) - data_dec = sp_decrypt(data, data_width, zero_key); - end else if (sp_width == 8) begin - // pass each byte of the data through the subst/perm network (special case of the general code - // below) - for (int i = 0; i < data_width / 8; i++) begin - byte_to_dec = data[i*8 +: 8]; - dec_byte = sp_decrypt(byte_to_dec, 8, zero_key); - data_dec[i*8 +: 8] = dec_byte; - end - end else begin - // divide the word into sp_width chunks to pass it through the subst/perm network - for (int chunk_lsb = 0; chunk_lsb < data_width; chunk_lsb += sp_width) begin - int bits_remaining = data_width - chunk_lsb; - int chunk_width = (bits_remaining < sp_width) ? bits_remaining : sp_width; - logic chunk[] = new[chunk_width]; - - for (int j = 0; j < chunk_width; j++) begin - chunk[j] = data[chunk_lsb + j]; - end - chunk = sp_decrypt(chunk, chunk_width, zero_key); - for (int j = 0; j < chunk_width; j++) begin - data_dec[chunk_lsb + j] = chunk[j]; - end - end - end - - // XOR result data with the keystream - for (int i = 0; i < data_width; i++) begin - data_dec[i] = data_dec[i] ^ keystream[i % ks_width]; - end - end else begin - // XOR result data with the keystream - for (int i = 0; i < data_width; i++) begin - data_dec[i] = data[i] ^ keystream[i % ks_width]; - end - end - - return data_dec; - - endfunction : decrypt_sram_data - -endpackage : sram_scrambler_pkg diff --git a/vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_agent.sv b/vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_agent.sv index ecb01035f9..8809af1ce7 100644 --- a/vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_agent.sv +++ b/vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_agent.sv @@ -44,6 +44,7 @@ class push_pull_agent #( virtual task run_phase(uvm_phase phase); push_pull_device_seq#(HostDataWidth, DeviceDataWidth) m_seq = push_pull_device_seq#(HostDataWidth, DeviceDataWidth)::type_id::create("m_seq", this); + super.run_phase(phase); if (cfg.if_mode == dv_utils_pkg::Device && cfg.start_default_device_seq) begin uvm_config_db#(uvm_object_wrapper)::set(null, {sequencer.get_full_name(), ".run_phase"}, "default_sequence", m_seq.get_type()); diff --git a/vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_agent_cov.sv b/vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_agent_cov.sv index eddeff027e..d83581bb15 100644 --- a/vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_agent_cov.sv +++ b/vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_agent_cov.sv @@ -35,6 +35,7 @@ class push_pull_agent_cov #(parameter int HostDataWidth = 32, valid_ready_cg m_valid_ready_cg; req_ack_cg m_req_ack_cg; function void build_phase(uvm_phase phase); + super.build_phase(phase); if (cfg.agent_type == PushAgent) begin m_valid_ready_cg = new("m_valid_ready_cg", `gfn); end else begin diff --git a/vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_if.sv b/vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_if.sv index ee28a0218f..30710b5044 100644 --- a/vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_if.sv +++ b/vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_if.sv @@ -111,7 +111,7 @@ interface push_pull_if #(parameter int HostDataWidth = 32, // Whenever valid is asserted, h_data must have a known value. `ASSERT_KNOWN_IF(H_DataKnownWhenValid_A, h_data, valid && is_push_agent, clk, !rst_n) - // Whenver ready is asserted and the agent is in bidirectional mode, + // Whenever ready is asserted and the agent is in bidirectional mode, // d_data must have a known value. `ASSERT_KNOWN_IF(D_DataKnownWhenReady_A, d_data, ready && is_push_agent && in_bidirectional_mode, clk, !rst_n) diff --git a/vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_monitor.sv b/vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_monitor.sv index 2f8cd057bf..9d3782f66d 100644 --- a/vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_monitor.sv +++ b/vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_monitor.sv @@ -24,7 +24,8 @@ class push_pull_monitor #(parameter int HostDataWidth = 32, cfg.in_reset = 0; fork monitor_reset(); - collect_trans(); + // Calling super.run_phase is equivalent to calling collect_trans() + super.run_phase(phase); // Collect partial pull reqs for the reactive pull device agent. collect_pull_req(); collect_cov(); @@ -93,7 +94,7 @@ class push_pull_monitor #(parameter int HostDataWidth = 32, @(cfg.vif.mon_cb); `WAIT_FOR_RESET if (cfg.vif.mon_cb.req) begin - `uvm_info(`gfn, $sformatf("[%0s] pull req detected", cfg.agent_type), UVM_HIGH) + `uvm_info(`gfn, $sformatf("[%0s] pull req detected", cfg.agent_type.name()), UVM_HIGH) // TODO: sample any covergroups item = push_pull_item#(HostDataWidth, DeviceDataWidth)::type_id::create("item"); item.h_data = cfg.vif.mon_cb.h_data; @@ -139,7 +140,7 @@ class push_pull_monitor #(parameter int HostDataWidth = 32, item.h_data = cfg.vif.mon_cb.h_data; `uvm_info(`gfn, $sformatf("[%0s] transaction detected: h_data[0x%0x], d_data[0x%0x]", - cfg.agent_type, item.h_data, item.d_data), UVM_HIGH) + cfg.agent_type.name(), item.h_data, item.d_data), UVM_HIGH) analysis_port.write(item); endfunction diff --git a/vendor/lowrisc_ip/dv/sv/push_pull_agent/seq_lib/push_pull_indefinite_host_seq.sv b/vendor/lowrisc_ip/dv/sv/push_pull_agent/seq_lib/push_pull_indefinite_host_seq.sv index ebee124498..11d2138139 100644 --- a/vendor/lowrisc_ip/dv/sv/push_pull_agent/seq_lib/push_pull_indefinite_host_seq.sv +++ b/vendor/lowrisc_ip/dv/sv/push_pull_agent/seq_lib/push_pull_indefinite_host_seq.sv @@ -4,7 +4,7 @@ // Request sequence for Push and Pull protocols. // -// Similiar push_pull_host_seq, this sequence will send an unlimited number of requests to +// Similar push_pull_host_seq, this sequence will send an unlimited number of requests to // the DUT. It is the responsibility of the parent sequence to halt this sequence by setting // the stop field. // diff --git a/vendor/lowrisc_ip/dv/tools/common.tcl b/vendor/lowrisc_ip/dv/tools/common.tcl index cfa0b37bdf..77434502f2 100644 --- a/vendor/lowrisc_ip/dv/tools/common.tcl +++ b/vendor/lowrisc_ip/dv/tools/common.tcl @@ -21,6 +21,12 @@ if {[info exists ::env(GUI)]} { set gui "$::env(GUI)" } +set gui_debug 0 +# Detect when GUI debug mode has been invoked to build UVM objects by default +if {[info exists ::env(GUI_DEBUG)]} { + set gui_debug "$::env(GUI_DEBUG)" +} + set tb_top "tb" if {[info exists ::env(TB_TOP)]} { set tb_top "$::env(TB_TOP)" diff --git a/vendor/lowrisc_ip/dv/tools/dvsim/common_modes.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/common_modes.hjson index d74d13ebfe..d158c61545 100644 --- a/vendor/lowrisc_ip/dv/tools/dvsim/common_modes.hjson +++ b/vendor/lowrisc_ip/dv/tools/dvsim/common_modes.hjson @@ -12,6 +12,11 @@ is_sim_mode: 1 en_build_modes: ["{tool}_gui"] } + { + name: gui_debug + is_sim_mode: 1 + en_build_modes: ["{tool}_gui_debug"] + } { name: waves is_sim_mode: 1 diff --git a/vendor/lowrisc_ip/dv/tools/dvsim/common_sim_cfg.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/common_sim_cfg.hjson index 1cf530b02c..3eb246f195 100644 --- a/vendor/lowrisc_ip/dv/tools/dvsim/common_sim_cfg.hjson +++ b/vendor/lowrisc_ip/dv/tools/dvsim/common_sim_cfg.hjson @@ -13,6 +13,8 @@ "{dv_root}/tools/dvsim/bazel.hjson", "{dv_root}/tools/dvsim/{tool}.hjson"] + sv_flist_gen_flags: ["--mapping=lowrisc:prim_generic:all:0.1"] + // Default directory structure for the output build_dir: "{scratch_path}/{build_mode}" run_dir_name: "{index}.{test}" @@ -75,8 +77,10 @@ // Default list of things to export to shell exports: [ { dv_root: "{dv_root}" }, + { self_dir: "{self_dir}" }, { SIMULATOR: "{tool}" }, { GUI: "{gui}"}, + { GUI_DEBUG: "{gui_debug}"}, { WAVES: "{waves}" }, { DUT_TOP: "{dut}" }, { TB_TOP: "{tb}" }, diff --git a/vendor/lowrisc_ip/dv/tools/dvsim/fusesoc.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/fusesoc.hjson index 1e44166888..66e282e99f 100644 --- a/vendor/lowrisc_ip/dv/tools/dvsim/fusesoc.hjson +++ b/vendor/lowrisc_ip/dv/tools/dvsim/fusesoc.hjson @@ -8,10 +8,9 @@ "run", "{sv_flist_gen_flags}", "--target=sim", - "--build-root={build_dir}", + "--work-root={build_dir}/fusesoc-work", "--setup {fusesoc_core}"] - fusesoc_cores_root_dirs: ["--cores-root {proj_root}"] - sv_flist_gen_dir: "{build_dir}/sim-vcs" + fusesoc_cores_root_dirs: ["--cores-root {proj_root}/hw"] + sv_flist_gen_dir: "{build_dir}/fusesoc-work" sv_flist: "{sv_flist_gen_dir}/{fusesoc_core_}.scr" - sv_flist_gen_flags: ["--flag=fileset_{design_level}"] } diff --git a/vendor/lowrisc_ip/dv/tools/dvsim/riviera.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/riviera.hjson index 303527525b..dd81546e0b 100644 --- a/vendor/lowrisc_ip/dv/tools/dvsim/riviera.hjson +++ b/vendor/lowrisc_ip/dv/tools/dvsim/riviera.hjson @@ -69,6 +69,13 @@ build_opts: [] run_opts: [] } + { + name: riviera_gui_debug + // TODO: Add options to setup Riviera gui debug environment and features (as in xcelium.hjson) + is_sim_mode: 1 + build_opts: [] + run_opts: [] + } { name: riviera_waves is_sim_mode: 1 diff --git a/vendor/lowrisc_ip/dv/tools/dvsim/sim.mk b/vendor/lowrisc_ip/dv/tools/dvsim/sim.mk index 692b5aad02..bd03c81d28 100644 --- a/vendor/lowrisc_ip/dv/tools/dvsim/sim.mk +++ b/vendor/lowrisc_ip/dv/tools/dvsim/sim.mk @@ -84,7 +84,11 @@ ifneq (${sw_images},) flags=(`echo $$sw_image | cut -d: -f 4- --output-delimiter " "`); \ bazel_label="`echo $$sw_image | cut -d: -f 1-2`"; \ if [[ $${index} != 4 && $${index} != 5 ]]; then \ - bazel_label="$${bazel_label}_$${sw_build_device}"; \ + if [[ $${flags[@]} =~ "silicon_creator" ]]; then \ + bazel_label="$${bazel_label}_silicon_creator"; \ + else \ + bazel_label="$${bazel_label}_$${sw_build_device}"; \ + fi; \ bazel_cquery="labels(data, $${bazel_label}) union labels(srcs, $${bazel_label})"; \ else \ bazel_cquery="$${bazel_label}"; \ @@ -97,15 +101,10 @@ ifneq (${sw_images},) echo "Building SW image \"$${bazel_label}\"."; \ bazel_airgapped_opts=""; \ bazel_opts="${sw_build_opts} --define DISABLE_VERILATOR_BUILD=true"; \ - bazel_opts+=" --//hw/ip/otp_ctrl/data:img_seed=${seed}"; \ - if [[ "${build_seed}" != "None" ]]; then \ - bazel_opts+=" --//hw/ip/otp_ctrl/data:lc_seed=${build_seed}"; \ - bazel_opts+=" --//hw/ip/otp_ctrl/data:otp_seed=${build_seed}"; \ - fi; \ if [[ -n $${BAZEL_OTP_DATA_PERM_FLAG} ]]; then \ - bazel_opts+=" --//hw/ip/otp_ctrl/data:data_perm=$${BAZEL_OTP_DATA_PERM_FLAG}"; \ + bazel_opts+=" --//util/design/data:data_perm=$${BAZEL_OTP_DATA_PERM_FLAG}"; \ fi; \ - if [[ -z $${BAZEL_PYTHON_WHEELS_REPO} ]]; then \ + if [[ $${OT_AIRGAPPED} != true ]]; then \ echo "Building \"$${bazel_label}\" on network connected machine."; \ bazel_cmd="./bazelisk.sh"; \ else \ @@ -122,10 +121,8 @@ ifneq (${sw_images},) --ui_event_filters=-info \ --noshow_progress \ --output=label_kind | cut -f1 -d' '); \ - if [[ $${kind} == "opentitan_test" \ - || $${bazel_label} == "//sw/device/lib/testing/test_rom:test_rom_sim_dv" \ - || $${bazel_label} == "//sw/device/silicon_creator/rom:mask_rom_sim_dv" ]]; then \ - for artifact in $$($${bazel_cmd} cquery $${bazel_airgapped_opts} \ + if [[ $${kind} == "opentitan_test" ]]; then \ + for artifact in $$($${bazel_cmd} cquery $${bazel_airgapped_opts} $${bazel_opts} \ $${bazel_label} \ --ui_event_filters=-info \ --noshow_progress \ @@ -139,8 +136,23 @@ ifneq (${sw_images},) $${run_dir}/$$(basename -s .bin $${artifact}).elf; \ fi; \ done; \ + elif [[ $${kind} == "alias" || $${kind} == "opentitan_binary" ]]; then \ + for artifact in $$($${bazel_cmd} cquery $${bazel_airgapped_opts} $${bazel_opts} \ + $${bazel_label} \ + --ui_event_filters=-info \ + --noshow_progress \ + --output=starlark \ + `# An opentitan_binary rule has all of its needed files in its runfiles.` \ + --starlark:expr='"\n".join([f.path for f in target.files.to_list()])'); do \ + cp -f $${artifact} $${run_dir}/$$(basename $${artifact}); \ + if [[ $$artifact == *.bin && \ + -f "$$(echo $${artifact} | cut -d. -f 1).elf" ]]; then \ + cp -f "$$(echo $${artifact} | cut -d. -f 1).elf" \ + $${run_dir}/$$(basename -s .bin $${artifact}).elf; \ + fi; \ + done; \ else \ - for dep in $$($${bazel_cmd} cquery $${bazel_airgapped_opts} \ + for dep in $$($${bazel_cmd} cquery $${bazel_airgapped_opts} $${bazel_opts} \ $${bazel_cquery} \ --ui_event_filters=-info \ --noshow_progress \ @@ -148,9 +160,9 @@ ifneq (${sw_images},) `# Bazel 6 cquery outputs repository targets in canonical format (@//blabla) whereas bazel 5 does not, ` \ `# so we use a custom starlark printer to remove in leading @ when needed.` \ --starlark:expr='str(target.label)[1:] if str(target.label).startswith("@//") else target.label'); do \ - if [[ $$dep == //hw/ip/otp_ctrl/data* ]] || \ + if [[ $$dep == //hw/top_*/ip_autogen/otp_ctrl/data* ]] || \ ([[ $$dep != //hw* ]] && [[ $$dep != //util* ]] && [[ $$dep != //sw/host* ]]); then \ - for artifact in $$($${bazel_cmd} cquery $${bazel_airgapped_opts} $${dep} \ + for artifact in $$($${bazel_cmd} cquery $${bazel_airgapped_opts} $${bazel_opts} $${dep} \ --ui_event_filters=-info \ --noshow_progress \ --output=starlark \ diff --git a/vendor/lowrisc_ip/dv/tools/dvsim/testplans/BUILD b/vendor/lowrisc_ip/dv/tools/dvsim/testplans/BUILD new file mode 100644 index 0000000000..65cf1e5d87 --- /dev/null +++ b/vendor/lowrisc_ip/dv/tools/dvsim/testplans/BUILD @@ -0,0 +1,10 @@ +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "doc_files", + srcs = glob(["**/*_testplan.hjson"]), +) diff --git a/vendor/lowrisc_ip/dv/tools/dvsim/testplans/racl_testplan.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/testplans/racl_testplan.hjson new file mode 100644 index 0000000000..05fca4a4d7 --- /dev/null +++ b/vendor/lowrisc_ip/dv/tools/dvsim/testplans/racl_testplan.hjson @@ -0,0 +1,36 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +{ + testpoints: [ + { + name: racl_rw + desc: ''' + Precondition: + - Randomize the number of RACL policies and randomize its default policy values. + - Randomize the policy selection vector of the CSRs. + - Randomize the RaclErrorRsp parameter. + - Shuffle the list of CSRs first to remove the effect of ordering. + + Verify the correct access for each CSR: + - Loop through the CSRs in a random order, performing read and write requests using + random RACL roles and CTN UID values. + If the request is allowed: + - No TL-UL error is expected. + - Verify that reads and writes complete as expected. + else if the request is denied: + - Verify the error log matches: + - error_log_o.valid = 1 + - error_log_o.overflow = 0 + - error_log_o.racl_role = + - error_log_o.ctn_uid = + - Verify that a write has no effect. + - Verify a read returns data with 0xFFFFF (all bits set to 1). + - If ErrorRsp = 1: + - Verify a TLUL error is returned. + ''' + stage: V1 + tests: ["{name}{intf}_racl_rw"] + } + ] +} diff --git a/vendor/lowrisc_ip/dv/tools/dvsim/vcs.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/vcs.hjson index b11e601f81..64f58b8a14 100644 --- a/vendor/lowrisc_ip/dv/tools/dvsim/vcs.hjson +++ b/vendor/lowrisc_ip/dv/tools/dvsim/vcs.hjson @@ -38,6 +38,15 @@ // 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", + // Newer compiler versions have escalated these warnings into an error by default, and + // VCS generates code to build the simulation executable which fails these checks. + // De-escalate the error (only when building the simv itself.) + // > rmapats.c:20:9: error: implicit declaration of function 'vcs_simpSetEBlkEvtID' + // > [-Wimplicit-function-declaration] + // > rmapats.c:466:36: error: passing argument 1 of 'setChildClockWriteFuncAndPcode' makes + // > integer from pointer without a cast + // > [-Wint-conversion] + "-Xcflags='-Wno-error=implicit-function-declaration -Wno-error=int-conversion'", // 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 @@ -45,10 +54,10 @@ // 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 -CFLAGS -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", + // C++17 standard is enforced for all sources, including the DPI-C constructs. + // Refer to + // https://opentitan.org/book/doc/contributing/style_guides/c_cpp_coding_style.html#c-style-guide + "-CFLAGS --std=c++17", // 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' @@ -114,6 +123,12 @@ run_opts: ["-licqueue", "-ucli -do {run_script}", "+ntb_random_seed={svseed}", + // In VCS, all random generation starts with an initial seed and that remains same + // for each instance of the module. Hence, for each instance of the same module + // $urandom() generates same random value. + // Below switch generates different randomization values per instance of a module. + // Refer to https://github.com/lowRISC/opentitan/issues/27659 for more details. + "-xlrm hier_inst_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 // did not finish because the simulation terminated, or assertions that did not @@ -270,6 +285,13 @@ build_opts: ["-debug_access+all+reverse"] run_opts: ["-gui", "-l {run_dir}/simv.log"] } + { + name: vcs_gui_debug + // TODO as done for Xcelium see PR #24156 + is_sim_mode: 1 + build_opts: ["-debug_access+all+reverse"] + run_opts: ["-gui", "-l {run_dir}/simv.log"] + } { name: vcs_waves is_sim_mode: 1 @@ -281,7 +303,7 @@ name: vcs_waves_off is_sim_mode: 1 build_opts: [// disable dumping assertion failures to improve runtime performance - "-assert novpi+dbgopt"] + "-assert dbgopt"] } { name: vcs_cov @@ -296,7 +318,7 @@ // Dump toggle coverage on mdas, array of structs and on ports only "-cm_tgl mda+structarr+portsonly", // Report condition coverage within tasks, functions and for loops. - "-cm_cond for+tf", + "-cm_cond for", // Ignore initial blocks for coverage "-cm_report noinitial", // Filter unreachable/statically constant blocks. seqnoconst does a more diff --git a/vendor/lowrisc_ip/dv/tools/dvsim/verilator.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/verilator.hjson index 56ab5d25ba..0a2b9d3b8b 100644 --- a/vendor/lowrisc_ip/dv/tools/dvsim/verilator.hjson +++ b/vendor/lowrisc_ip/dv/tools/dvsim/verilator.hjson @@ -51,8 +51,7 @@ // TODO: Verilator has a few useful build switches. Need to figure out how to // pass them via FuseSoC. - build_opts: ["--flag=fileset_{design_level}", - "--target=sim", + build_opts: ["--target=sim", "--build-root={build_dir}", "--setup", "--build", diff --git a/vendor/lowrisc_ip/dv/tools/dvsim/xcelium.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/xcelium.hjson index b523e4c1ab..172d9a9331 100644 --- a/vendor/lowrisc_ip/dv/tools/dvsim/xcelium.hjson +++ b/vendor/lowrisc_ip/dv/tools/dvsim/xcelium.hjson @@ -46,7 +46,7 @@ // Ignore warning "Include directory given but not used". This is benign. "-nowarn SPDUSD", // Needed for including "secded_enc.h". - "-I{build_dir}/src/lowrisc_dv_secded_enc_0", + "-I{build_dir}/fusesoc-work/src/lowrisc_dv_secded_enc_0", // This warning is thrown when a scalar enum variable is assigned to an enum array. // Other tools (e.g., FPV) treat such assignments as an error, hence we bump it to // an error in simulation so that this can be caught early in CI. @@ -184,6 +184,7 @@ "-jg_coverage {cov_metrics}", "-64bit", "-xmlibdirname {build_db_dir}", + "-jgargs '-allow_unsupported_OS'", // overwrite previous results "-covoverwrite", "-inst_top {dut_instance}", @@ -202,6 +203,16 @@ build_opts: ["-createdebugdb", "-access +c"] run_opts: ["-gui"] } + { + name: xcelium_gui_debug + is_sim_mode: 1 + build_opts: ["-createdebugdb", "-access +c", "-uvmlinedebug", "-linedebug", + "+uvm_set_config_int=*,recording_detail,1"] + run_opts: ["-gui", + "-input '@database -open waves -into waves.shm -default; probe -create \n" + "tb -depth all -packed 32k -unpacked 32k -all -dynamic -database waves'", + "+uvm_set_config_int=*,recording_detail,1"] + } { name: xcelium_waves is_sim_mode: 1 diff --git a/vendor/lowrisc_ip/dv/tools/ralgen/ralgen.py b/vendor/lowrisc_ip/dv/tools/ralgen/ralgen.py index 4281666e13..b84b1fac0d 100755 --- a/vendor/lowrisc_ip/dv/tools/ralgen/ralgen.py +++ b/vendor/lowrisc_ip/dv/tools/ralgen/ralgen.py @@ -57,8 +57,13 @@ def main(): args += ["--alias", root_dir / alias_hjson] else: ral_spec = root_dir / top_hjson + # Extract top_name from ral spec path and create _seed.testing.hjson + ral_path = Path(ral_spec) + top_name = ral_path.stem + seed_path = ral_path.with_name(f"{top_name}_seed.testing.hjson") + cmd = util_path / "topgen.py" - args = [cmd, "-r", "-o", os.getcwd(), "-t", ral_spec] + args = [cmd, "-r", "-o", os.getcwd(), "-t", ral_spec, "-s", seed_path] if hjson_path: args += ["--hjson-path", root_dir / hjson_path] if alias_hjson: diff --git a/vendor/lowrisc_ip/dv/tools/sim.tcl b/vendor/lowrisc_ip/dv/tools/sim.tcl index 98a5694d8a..41e1f0b802 100644 --- a/vendor/lowrisc_ip/dv/tools/sim.tcl +++ b/vendor/lowrisc_ip/dv/tools/sim.tcl @@ -38,9 +38,17 @@ if {$simulator eq "xcelium"} { assertion -list -depth all -multiline -permoff $tb_top } -# In GUI mode, let the user take control of running the simulation. global gui -if {$gui == 0} { +global gui_debug +# In GUI mode, let the user take control of running the simulation. +# In GUI debug mode, run only up until the end of the UVM elaboration phase to have access to the +# dynamic objects. +if {$gui_debug == 1} { + if {$simulator eq "xcelium"} { + uvm_phase -stop_at build -end + run + } +} elseif {$gui == 0} { run if {$simulator eq "xcelium"} { # Xcelium provides a `finish` tcl command instead of `quit`. The argument '2' enables the diff --git a/vendor/lowrisc_ip/dv/tools/vcs/cover.cfg b/vendor/lowrisc_ip/dv/tools/vcs/cover.cfg index 79068f07b7..c6bad4210d 100644 --- a/vendor/lowrisc_ip/dv/tools/vcs/cover.cfg +++ b/vendor/lowrisc_ip/dv/tools/vcs/cover.cfg @@ -18,14 +18,26 @@ -moduletree prim_lfsr -moduletree prim_onehot_check -moduletree prim_prince --moduletree prim_secded_inv_64_57_dec // use in reg_top --moduletree prim_secded_inv_39_32_dec // use in reg_top +-moduletree prim_secded_inv_64_57_dec +-moduletree prim_secded_inv_39_32_dec +-moduletree prim_secded_inv_64_57_enc +-moduletree prim_secded_inv_39_32_enc -// csr_assert_fpv is an auto-generated csr read assertion module. So only assertion coverage is -// meaningful to collect. +// The DV environment binds in some modules to add CSR and TileLink +// assertions. Disable all coverage for these modules here. We'll +// enable assertion coverage for the modules below. -moduletree *csr_assert_fpv +-moduletree tlul_assert + -module prim_cdc_rand_delay // DV construct. +begin assert + // Enable assertion coverage for bound-in assertion modules (we + // disabled all coverage earlier in the file) + +moduletree *csr_assert_fpv + +moduletree tlul_assert +end + begin tgl -tree tb +tree tb.dut 1 @@ -40,7 +52,3 @@ begin tgl +module prim_secded_inv_64_57_dec +module prim_secded_inv_39_32_dec end - -begin assert - +moduletree *csr_assert_fpv -end diff --git a/vendor/lowrisc_ip/dv/tools/vcs/cover_reg_top.cfg b/vendor/lowrisc_ip/dv/tools/vcs/cover_reg_top.cfg index 430f2be9a1..b1fa7cf2e1 100644 --- a/vendor/lowrisc_ip/dv/tools/vcs/cover_reg_top.cfg +++ b/vendor/lowrisc_ip/dv/tools/vcs/cover_reg_top.cfg @@ -4,15 +4,28 @@ // Limits coverage collection only to the *_reg_top module and the TL interface // of the DUT. - +moduletree *_reg_top +node tb.dut tl_* + +// Disable collection is some modules that are instantiated inside the reg_top module but verified +// by a different mechanism (prims that are verified by FPV) or are just DV constructs where +// coverage doesn't matter. -module prim_cdc_rand_delay // DV construct. --module prim_onehot_check // FPV verified --moduletree prim_secded_inv_64_57_dec // use in reg_top --moduletree prim_secded_inv_39_32_dec // use in reg_top +-module prim_onehot_check // FPV verified +-moduletree prim_secded_inv_64_57_dec // FPV verified +-moduletree prim_secded_inv_39_32_dec // FPV verified +-moduletree prim_secded_inv_64_57_enc // FPV verified +-moduletree prim_secded_inv_39_32_enc // FPV verified + +// The DV environment binds in some modules to add CSR and Tilelink assertions. Make sure that we +// collect assertion coverage for these modules (since that's the whole point!) but don't collect +// any other sort of coverage. +-moduletree *csr_assert_fpv +-moduletree tlul_assert begin assert + // Enable assertion coverage for bound-in assertion modules (we + // disabled all coverage earlier in the file) +moduletree *csr_assert_fpv +moduletree tlul_assert end diff --git a/vendor/lowrisc_ip/dv/tools/xcelium/cover.ccf b/vendor/lowrisc_ip/dv/tools/xcelium/cover.ccf index 9a80e7f265..3964c645e1 100644 --- a/vendor/lowrisc_ip/dv/tools/xcelium/cover.ccf +++ b/vendor/lowrisc_ip/dv/tools/xcelium/cover.ccf @@ -22,6 +22,8 @@ deselect_coverage -betfs -module prim_prince... deselect_coverage -betfs -module prim_lfsr... deselect_coverage -betfs -module prim_secded_inv_64_57_dec... deselect_coverage -betfs -module prim_secded_inv_39_32_dec... +deselect_coverage -betfs -module prim_secded_inv_64_57_enc... +deselect_coverage -betfs -module prim_secded_inv_39_32_enc... // Black-box DV CDC module. deselect_coverage -betfs -module prim_cdc_rand_delay diff --git a/vendor/lowrisc_ip/dv/tools/xcelium/cover_reg_top.ccf b/vendor/lowrisc_ip/dv/tools/xcelium/cover_reg_top.ccf index 3bd0f5e926..6c38a171e6 100644 --- a/vendor/lowrisc_ip/dv/tools/xcelium/cover_reg_top.ccf +++ b/vendor/lowrisc_ip/dv/tools/xcelium/cover_reg_top.ccf @@ -11,6 +11,8 @@ select_coverage -befs -module *_reg_top... deselect_coverage -betfs -module prim_onehot_check... deselect_coverage -betfs -module prim_secded_inv_64_57_dec... deselect_coverage -betfs -module prim_secded_inv_39_32_dec... +deselect_coverage -betfs -module prim_secded_inv_64_57_enc... +deselect_coverage -betfs -module prim_secded_inv_39_32_enc... // Black-box DV CDC module. deselect_coverage -betfs -module prim_cdc_rand_delay diff --git a/vendor/lowrisc_ip/dv/verilator/cpp/scrambled_ecc32_mem_area.cc b/vendor/lowrisc_ip/dv/verilator/cpp/scrambled_ecc32_mem_area.cc index c67a92917b..06eced0322 100644 --- a/vendor/lowrisc_ip/dv/verilator/cpp/scrambled_ecc32_mem_area.cc +++ b/vendor/lowrisc_ip/dv/verilator/cpp/scrambled_ecc32_mem_area.cc @@ -117,10 +117,10 @@ std::vector ScrambledEcc32MemArea::GetScrambleNonce() const { ScrambledEcc32MemArea::ScrambledEcc32MemArea(const std::string &scope, uint32_t size, uint32_t width_32, bool repeat_keystream) - : Ecc32MemArea( - SVScoped::join_sv_scopes( - scope, "u_prim_ram_1p_adv.u_mem.gen_generic.u_impl_generic"), - size, width_32), + : Ecc32MemArea(SVScoped::join_sv_scopes(scope, + "u_prim_ram_1p_adv.gen_ram_inst[0]." + "u_mem"), + size, width_32), scr_scope_(scope) { addr_width_ = vbits(size); repeat_keystream_ = repeat_keystream; diff --git a/vendor/lowrisc_ip/dv/verilator/cpp/verilator_memutil.cc b/vendor/lowrisc_ip/dv/verilator/cpp/verilator_memutil.cc index 951152814f..a8295d3fac 100644 --- a/vendor/lowrisc_ip/dv/verilator/cpp/verilator_memutil.cc +++ b/vendor/lowrisc_ip/dv/verilator/cpp/verilator_memutil.cc @@ -24,21 +24,30 @@ struct LoadArg { }; } // 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) { +// Parse a meminit command-line argument and write the result to the +// mem_arg output pointer. The command-line argument should be of the +// form mem_area,file[,type]. +// +// Return true on success. On failure, return false and write an error +// message to err_msg. +static bool ParseMemArg(const std::string mem_argument, LoadArg *load_arg, + std::string *err_msg) { std::array args; size_t pos = 0; size_t end_pos = 0; size_t i; + assert(load_arg); + assert(err_msg); + 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()); + *err_msg = oss.str(); + return false; } if (end_pos == std::string::npos) { args[i] = mem_argument.substr(pos); @@ -53,13 +62,16 @@ static LoadArg ParseMemArg(std::string mem_argument) { std::ostringstream oss; oss << "meminit must be in the format `name,file[,type]'. Got: `" << mem_argument << "'."; - throw std::runtime_error(oss.str()); + *err_msg = oss.str(); + return false; } const char *str_type = (2 <= i) ? args[2].c_str() : nullptr; - MemImageType type = DpiMemUtil::GetMemImageType(args[1], str_type); - return {.name = args[0], .filepath = args[1], .type = type}; + load_arg->name = args[0]; + load_arg->filepath = args[1]; + load_arg->type = DpiMemUtil::GetMemImageType(args[1], str_type); + return true; } // Print a usage message to stdout @@ -140,21 +152,24 @@ bool VerilatorMemUtil::ParseCLIArguments(int argc, char **argv, load_args.push_back( {.name = "otp", .filepath = optarg, .type = kMemImageUnknown}); break; - case 'l': + case 'l': { + LoadArg load_arg; + std::string load_err_msg; + if (strcasecmp(optarg, "list") == 0) { mem_util_->PrintMemRegions(); exit_app = true; return true; } - // --meminit / -l - try { - load_args.emplace_back(ParseMemArg(optarg)); - } catch (const std::runtime_error &err) { - std::cerr << "ERROR: " << err.what() << std::endl; + if (!ParseMemArg(optarg, &load_arg, &load_err_msg)) { + std::cerr << "ERROR: " << load_err_msg << std::endl; return false; + } else { + load_args.emplace_back(load_arg); } break; + } case 'V': verbose = true; break; diff --git a/vendor/lowrisc_ip/dv/verilator/memutil_dpi_scrambled_opts.hjson b/vendor/lowrisc_ip/dv/verilator/memutil_dpi_scrambled_opts.hjson index ee8ae81fa7..0e697ef368 100644 --- a/vendor/lowrisc_ip/dv/verilator/memutil_dpi_scrambled_opts.hjson +++ b/vendor/lowrisc_ip/dv/verilator/memutil_dpi_scrambled_opts.hjson @@ -24,29 +24,29 @@ build_modes: [ { name: vcs_memutil_dpi_scrambled_build_opts - build_opts: ["-CFLAGS -I{build_dir}/src/{memutil_dpi_src_dir}/cpp", - "-CFLAGS -I{build_dir}/src/{memutil_dpi_scrambled_src_dir}/cpp", - "-CFLAGS -I{build_dir}/src/{secded_enc_src_dir}", - "-CFLAGS -I{build_dir}/src/{scramble_model_dir}", - "-CFLAGS -I{build_dir}/src/{prince_ref_src_dir}", + build_opts: ["-CFLAGS -I{build_dir}/fusesoc-work/src/{memutil_dpi_src_dir}/cpp", + "-CFLAGS -I{build_dir}/fusesoc-work/src/{memutil_dpi_scrambled_src_dir}/cpp", + "-CFLAGS -I{build_dir}/fusesoc-work/src/{secded_enc_src_dir}", + "-CFLAGS -I{build_dir}/fusesoc-work/src/{scramble_model_dir}", + "-CFLAGS -I{build_dir}/fusesoc-work/src/{prince_ref_src_dir}", "-lelf"] } { name: xcelium_memutil_dpi_scrambled_build_opts - build_opts: ["-I{build_dir}/src/{memutil_dpi_src_dir}/cpp", - "-I{build_dir}/src/{memutil_dpi_scrambled_src_dir}/cpp", - "-I{build_dir}/src/{prince_ref_src_dir}", - "-I{build_dir}/src/{scramble_model_dir}", + build_opts: ["-I{build_dir}/fusesoc-work/src/{memutil_dpi_src_dir}/cpp", + "-I{build_dir}/fusesoc-work/src/{memutil_dpi_scrambled_src_dir}/cpp", + "-I{build_dir}/fusesoc-work/src/{prince_ref_src_dir}", + "-I{build_dir}/fusesoc-work/src/{scramble_model_dir}", "-lelf"] } { name: dsim_memutil_dpi_scrambled_build_opts - build_opts: ["-c-opts -I{build_dir}/src/{memutil_dpi_src_dir}/cpp", - "-c-opts -I{build_dir}/src/{memutil_dpi_scrambled_src_dir}/cpp", - "-c-opts -I{build_dir}/src/{prince_ref_src_dir}", - "-c-opts -I{build_dir}/src/{scramble_model_dir}", + build_opts: ["-c-opts -I{build_dir}/fusesoc-work/src/{memutil_dpi_src_dir}/cpp", + "-c-opts -I{build_dir}/fusesoc-work/src/{memutil_dpi_scrambled_src_dir}/cpp", + "-c-opts -I{build_dir}/fusesoc-work/src/{prince_ref_src_dir}", + "-c-opts -I{build_dir}/fusesoc-work/src/{scramble_model_dir}", "-ld-opts -lelf"] } ] diff --git a/vendor/lowrisc_ip/ip/prim/BUILD b/vendor/lowrisc_ip/ip/prim/BUILD index f42854cd1b..ef08c79c68 100644 --- a/vendor/lowrisc_ip/ip/prim/BUILD +++ b/vendor/lowrisc_ip/ip/prim/BUILD @@ -5,7 +5,25 @@ package(default_visibility = ["//visibility:public"]) filegroup( - name = "all_files", - srcs = glob(["**"]) + [ + name = "rtl_files", + srcs = glob( + ["**"], + exclude = [ + "dv/**", + "doc/**", + "README.md", + ], + ), +) + +filegroup( + name = "verilator_files", + srcs = glob(["dv/**"]) + [ + ":rtl_files", ], ) + +filegroup( + name = "doc_files", + srcs = glob(["**/*.md"]), +) diff --git a/vendor/lowrisc_ip/ip/prim/README.md b/vendor/lowrisc_ip/ip/prim/README.md index 62dfd43d69..6698ca9f4c 100644 --- a/vendor/lowrisc_ip/ip/prim/README.md +++ b/vendor/lowrisc_ip/ip/prim/README.md @@ -4,226 +4,367 @@ ![](https://dashboards.lowrisc.org/badges/dv/prim_alert/test.svg) ![](https://dashboards.lowrisc.org/badges/dv/prim_alert/passing.svg) ![](https://dashboards.lowrisc.org/badges/dv/prim_alert/functional.svg) -![](https://dashboards.lowrisc.org/badges/dv/prim_alert/code.svg) - +![](https://dashboards.lowrisc.org/badges/dv/prim_alert/code.svg)
[`prim_esc`](https://reports.opentitan.org/hw/ip/prim/dv/prim_esc/latest/report.html): ![](https://dashboards.lowrisc.org/badges/dv/prim_esc/test.svg) ![](https://dashboards.lowrisc.org/badges/dv/prim_esc/passing.svg) ![](https://dashboards.lowrisc.org/badges/dv/prim_esc/functional.svg) -![](https://dashboards.lowrisc.org/badges/dv/prim_esc/code.svg) - +![](https://dashboards.lowrisc.org/badges/dv/prim_esc/code.svg)
[`prim_lfsr`](https://reports.opentitan.org/hw/ip/prim/dv/prim_lfsr/latest/report.html): ![](https://dashboards.lowrisc.org/badges/dv/prim_lfsr/test.svg) ![](https://dashboards.lowrisc.org/badges/dv/prim_lfsr/passing.svg) ![](https://dashboards.lowrisc.org/badges/dv/prim_lfsr/functional.svg) -![](https://dashboards.lowrisc.org/badges/dv/prim_lfsr/code.svg) - -[`prim_present`](https://reports.opentitan.org/hw/ip/prim/dv/prim_lfsr/latest/report.html): +![](https://dashboards.lowrisc.org/badges/dv/prim_lfsr/code.svg)
+[`prim_present`](https://reports.opentitan.org/hw/ip/prim/dv/prim_present/latest/report.html): ![](https://dashboards.lowrisc.org/badges/dv/prim_present/test.svg) ![](https://dashboards.lowrisc.org/badges/dv/prim_present/passing.svg) ![](https://dashboards.lowrisc.org/badges/dv/prim_present/functional.svg) -![](https://dashboards.lowrisc.org/badges/dv/prim_present/code.svg) - -[`prim_prince`](https://reports.opentitan.org/hw/ip/prim/dv/prim_lfsr/latest/report.html): +![](https://dashboards.lowrisc.org/badges/dv/prim_present/code.svg)
+[`prim_prince`](https://reports.opentitan.org/hw/ip/prim/dv/prim_prince/latest/report.html): ![](https://dashboards.lowrisc.org/badges/dv/prim_prince/test.svg) ![](https://dashboards.lowrisc.org/badges/dv/prim_prince/passing.svg) ![](https://dashboards.lowrisc.org/badges/dv/prim_prince/functional.svg) -![](https://dashboards.lowrisc.org/badges/dv/prim_prince/code.svg) +![](https://dashboards.lowrisc.org/badges/dv/prim_prince/code.svg)
## Concepts -This directory contains basic building blocks to create a hardware design, -called primitives. A primitive is described by its name, and has a well-defined -list of ports and parameters. - -Under the hood, primitives are slightly special, as they can have multiple -implementations. In contrast to many other modules in a hardware design, -primitives must often be implemented in technology-dependent ways. For example, -a clock multiplexer for a Xilinx FPGA is implemented differently than one for -a specific ASIC technology. - -Not all primitives need to have multiple implementations. - -* Primitives with a single, generic, implementation are normal SystemVerilog - modules inside the `hw/ip/prim/rtl` directory. We call these primitives - "technology-independent primitives". -* Primitives with multiple implementations have only a FuseSoC core file in the - `hw/ip/prim` directory. The actual implementations are in "technology - libraries". We call these primitives "technology-dependent primitives". - -### Abstract primitives - -Abstract primitives are wrappers around technology-dependent implementations of -primitives, with the ability to select a specific implementation if needed. - -In more technical terms, abstract primitives are SystemVerilog modules. The -example below shows one. - -```systemverilog -`ifndef PRIM_DEFAULT_IMPL - `define PRIM_DEFAULT_IMPL prim_pkg::ImplGeneric -`endif - -module prim_pad_wrapper -#( - parameter int unsigned AttrDw = 6 -) ( - inout wire inout_io, // bidirectional pad - output logic in_o, // input data - input out_i, // output data - input oe_i, // output enable - // additional attributes {drive strength, keeper, pull-up, pull-down, open-drain, invert} - input [AttrDw-1:0] attr_i -); - parameter prim_pkg::impl_e Impl = `PRIM_DEFAULT_IMPL; - - if (Impl == prim_pkg::ImplGeneric) begin : gen_generic - prim_generic_pad_wrapper u_impl_generic ( - .* - ); - end else if (Impl == prim_pkg::ImplXilinx) begin : gen_xilinx - prim_xilinx_pad_wrapper u_impl_xilinx ( - .* - ); - end else begin : gen_failure - // TODO: Find code that works across tools and causes a compile failure - end - -endmodule +One of the ways that complexity is managed and reuse is promoted in hardware design is by encapsulating parts of our designs in 'modules'. +Modules, a standard language feature in HDLs, define their abstraction boundary using 'ports', which can be understood as a finite set of wires via which signals move in and out of the module. +Additionally, modules support 'parameterization' via compile time constant inputs, which can control features of the module which would otherwise be static such as the number of wires in each port. + +When designing at an RTL level, systems are typically composed of common low-level design patterns and well-understood or optimized circuits, which can be abstracted and implemented as modules. +The OpenTitan project contains a number of these low-level reuseable components, which we refer to as '***Primitives***'. +Different projects and contexts may have different definitions about what level of abstraction and complexity may constitute a primitive. +Here, there is no strict limit on the size of the logic inside a primitive, but they tend to be small and fixed-function. +Examples include fifos, counters, arbiters, synchronizers and codecs. + +There may be different implementations of primitives that achieve the same fixed function, but with different trade-offs in how this is achieved. +Modules can contain additional metadata that informs and specializes the process of lowering abstract RTL descriptions of behaviour into hardware that implements the equivalent function. +Tools that perform this lowering undertake a mapping process where higher-level functionality is decomposed into lower and lower level components. +These components exist in, or can be created in, the physical hardware or technology that is being targeted. +In ASIC or FPGA targets, the lower level components may be macro cells or other fixed-function hardware blocks. +An alternative lowering could be to gate-level models of an equivalent hardware implementation, where additional information is added to increase simulation accuracy for prediction of timing and power characteristics. +The process undertaken by these tools is described as 'inferring' (alt. 'inferencing') a combination of lower level components that best implement the circut functionality that is described. +There are many reasons that we may wish to constrain or modify our source files to control inferencing of a set of hardware components to make up a final circuit. + +## Primitive Implementations & Libraries + +Primitives in OpenTitan exist at a low level of RTL abstraction where it may be desirable under different circumstances to swap-out implementations to obtain better optimized hardware. +For this reason, our definition of a primitive is "*a module with a fixed name and set of ports*". +This minimizes the changes required for different implementations of a primitive to be substituted for each other. + +However, not all primitives need to have multiple implementations. +- Primitives with a single generic implementation, where any lowering process is able to infer a suitable hardware implementation from language-level RTL features, are called '***Technology-Independent Primitives***'. +- Primitives with multiple implementations, each of which may be optimized for or targeted towards a certain hardware platform, are called '***Technology-Dependent Primitives***'. + +Technology-dependent primitive implementations may be grouped together into '***Technology Libraries***'. +For example, a technology library of primitive implementations may be created for a certain ASIC technology, where the implementations are optimized for desirable synthesis characteristics in that technology. +Within the OpenTitan repository, each technology library has its own directory within `hw/ip/` with the prefix `prim`, such as `hw/ip/prim_xilinx/` for synthesis targeting Xilinx FPGAs. + +For each technology-dependent primitive, there should be an implementation that is 'generic' in that it is constructed using language-level RTL constructs, and can be consumed by most downstream tooling. +These implementations are commonly used as input to simulation engines for verification and as a functional reference. +- Technology-dependent 'generic' primitive implementations live inside the `hw/ip/prim_generic` directory. +- Technology-independent 'generic' primitives live inside the `hw/ip/prim` directory. + +While primatives are defined primarily by their interface, SystemVerilog does not allow a module interface to be defined without an implementation. +This is unlike constructs in other languages such as Abstract Methods and Interfaces in Java or Traits in Rust. +To determine the interface for a primitive (the module ports and parameters), the generic module implementation should be consulted. + +### Virtual Primitives + +OpenTitan utilizes the *[Fusesoc][]* build system and package manager to manage RTL at a fileset level. +To allow hardware blocks to be generic across implementations of technology-dependent primitives, a feature of FuseSoC called *[Virtual Cores][]* is used. +Virtual Cores allow FuseSoC to swap in a chosen implementation of a module without changing the RTL instantiation itself. +These can be thought of as similar to virtual methods in C++ or SystemVerilog. + +[Fusesoc]: https://github.com/olofk/fusesoc +[Virtual Cores]: https://fusesoc.readthedocs.io/en/stable/user/build_system/virtual_cores.html + +All technology-dependent primitives in OpenTitan use Virtual Cores to allow them to be substituted at build time. +For this reason, they are also referred to as ***Virtual Primitives***. + +FuseSoC Virtual Cores work by adding additional metadata to a Core, marking it as an implementation of another 'virtual' Core. +The Virtual Core is a unique *[VLNV][]*, and does not exist as a named `.core` file in the tree. +Taking `hw/ip/prim_generic/prim_generic_flop_2sync.core` as an example, you will see the following at the head of the file: + +[VLNV]: https://fusesoc.readthedocs.io/en/stable/user/build_system/core_files.html#the-core-name-version-and-description + +```yaml +CAPI=2: +name: "lowrisc:prim_generic:flop_2sync" +description: "Generic implementation of a flop-based synchronizer" +virtual: + - lowrisc:prim:flop_2sync ``` +Descriptively, we might say that the virtual core VLNV is `lowrisc:prim:flop_2sync`, and one possible implementation of this virtual core is `lowrisc:prim_generic:flop_2sync`. +As a virtual primitive, the interface (module name and ports) for `flop_2sync` is common among all implementations, and hence all instantiations. +Fundamentally, if multiple modules with the same name and ports are available, controlling the include paths and fileset inputs to a tool allows FuseSoC to select which module will be used to provide the implementation. + +By depending only on the virtual VLNV of a virtual primative, cores become generic over that primitive. +Any core that implements this virtual core may be selected at build time to provide the implementation for all instantiations. +During build time, all virtual cores must be resolved to a concrete implementation. +If a virtual core cannot be resolved because no implementations are found or specified at build time, a "conflicting-requirements" error will be generated by the FuseSoC solver. +The following section further describes the resolution process. + +It is still possible and valid for a Core to depend only on a specific implementation of a technology-dependent primitive, however the implementation cannot be substituted at build time in this case, and it functions as a normal FuseSoC Core. + +### Resolution of Concrete Implementations -As seen from the source code snippet, abstract primitives have the following -properties: +When invoking FuseSoC, a 'target' in a Core file is selected to choose the flow we wish to run. +Targets can depend on one or more 'filesets' defined within the Core, and each fileset can optionally depend on other Cores. +Therefore, when FuseSoC is run a dependency graph comprised of Cores and filesets is constructed. -- They have an `Impl` parameter which can be set to choose a specific - implementation of the primitive. -- The `Impl` parameter is set to a system-wide default determined by the - `PRIM_DEFAULT_IMPL` define. -- All ports and parameters of the abstract primitive are forwarded to the - implementations. +If a fileset depends on a Virtual Core, a resolution process must take place at build time to determine which of the possible implementations becomes the chosen or 'Concrete' implementation. +This resolution can be controlled in two ways: -### Technology libraries +1) **Dependency tree resolution** -Technology libraries collect implementations of primitives. + If a single implementation of a virtual core exists in the target dependency tree, it will be selected. + Multiple implementations of a virtual core in the target dependency tree will result in a 'conflicting-requirements' build time error from the FuseSoC solver. -At least one technology library must exist: the `generic` technology library, -which contains a pure-SystemVerilog implementation of the functionality. This -library is commonly used for simulations and as functional reference. The -`generic` technology library is contained in the `hw/ip/prim_generic` directory. +2) **Mappings** + + Mappings are an explicit directive for an implementation to be used to resolve a virtual core. + They are described in more detail below. + +If a virtual core cannot be resolved according to the methods above, an implementation is chosed non-deterministically from all known cores in the input libraries that implement this Virtual Core. +The following build time warning will be emitted: +``` +WARNING: Non-deterministic selection of virtual core selected +``` -In addition to the implementation in the `generic` library, primitives may be -implemented by as many other libraries as needed. +Many targets will choose option 1) to resolve their virtual cores by adding a specific implementation core into their dependencies. +Top-level cores will typically specialize generic systems and modules for a particular hardware target or application by adding constraints and wrappers for that target. +One part of this may be choosing a Technology Library to resolve all technology-dependent primitives to implementations that are specialized or optimized for the application. +To reduce the hassle of pulling in implementations for all virtual cores in a Technology Libraries into a dependency tree, the library will provide an `:all` core, e.g. `lowrisc:prim_generic:all` or `lowrisc:prim_xilinx_ultrascale:all`. +For example, the core `hw/top_earlgrey/chip_earlgrey_cw310.core` targeting a synthesis for a specific Xilinx FPGA depends on `lowrisc:prim_xilinx:all` to select a Xilinx Technology Library for primitives. -Technology libraries are referenced by their name. -### Technology library discovery +### Mappings -In many cases, technology libraries contain vendor-specific code which cannot be -shared widely or openly. Therefore, a FuseSoC looks for available technology -libraries at build time, and makes all libraries it finds available. -The discovery is performed based on the agreed-on naming scheme for primitives. +Fusesoc .core files may contain a 'mapping' key, which can define injective/one-to-one *[mappings][]* from virtual cores to a implementation of that virtual core. +Passing `--mapping=` via the CLI will cause any 'mapping' keys in the core to be used to resolve virtual cores to concrete implementations. +The concrete implementation core needs only to be discoverable in the input libraries, not in the target dependency tree. +The mapping applies to all uses of the virtual core anywhere in the dependency tree. -- FuseSoC scans all libraries (e.g. as specified by its `--cores-root` command - line argument) for cores. -- All cores with a name matching `lowrisc:prim_TECHLIBNAME:PRIMNAME` - are considered. `TECHLIBNAME` is then added to the list of technology - libraries. +[mappings]: https://fusesoc.readthedocs.io/en/stable/user/build_system/mappings.html + +An example set of mappings for the Xilinx Technology Library can be found in the following .core file. +Notice that there are not Xilinx specific implementations for all primitives, so we fallback to the generic implementation in those cases. + +```yaml +# hw/ip/prim_xilinx/prim_xilinx.core +name: "lowrisc:prim_xilinx:all:0.1" +description: "Xilinx 7-series prim library" + +mapping: + "lowrisc:prim:and2" : lowrisc:prim_xilinx:and2 + "lowrisc:prim:buf" : lowrisc:prim_xilinx:buf + "lowrisc:prim:clock_buf" : lowrisc:prim_xilinx:clock_buf + "lowrisc:prim:clock_div" : lowrisc:prim_generic:clock_div + "lowrisc:prim:clock_gating" : lowrisc:prim_xilinx:clock_gating + "lowrisc:prim:clock_inv" : lowrisc:prim_generic:clock_inv + "lowrisc:prim:clock_mux2" : lowrisc:prim_xilinx:clock_mux2 + # ... +``` + +One specific use of mappings is the lints for each block, such as the lint target for the OpenTitan UART in `hw/ip/uart/uart.core`. +At the HWIP level, the UART is generic across technology-dependent primitives, and hence its dependencies do not contain any concrete primitive implementations. +Instead, the 'dvsim' verification tool passes a set of mappings via CLI flags to FuseSoC to resolve all virtual cores for the specific linting job. +This allows the block to be linted for multiple different primitives (and top-level constants). + +Mappings may be present in top-level core files, e.g. in `hw/top_earlgrey/top_earlgrey.core`, to specialize block-level flows for top specific implementations as described previously. +```yaml +# hw/top_earlgrey/top_earlgrey.core +name: "lowrisc:systems:top_earlgrey:0.1" +description: "Technology-independent Earl Grey toplevel" + +mapping: + "lowrisc:virtual_constants:top_pkg": "lowrisc:earlgrey_constants:top_pkg" + "lowrisc:virtual_constants:top_racl_pkg": "lowrisc:earlgrey_constants:top_racl_pkg" + "lowrisc:systems:ast_pkg": "lowrisc:systems:top_earlgrey_ast_pkg" + "lowrisc:virtual_ip:flash_ctrl_prim_reg_top": "lowrisc:earlgrey_ip:flash_ctrl_prim_reg_top" +``` + +The following example shows how the UART lint flow is specialized for the earlgrey top. +```yaml +# hw/top_earlgrey/lint/top_earlgrey_lint_cfgs.hjson +{ + name: uart + fusesoc_core: lowrisc:ip:uart + import_cfgs: ["{proj_root}/hw/lint/tools/dvsim/common_lint_cfg.hjson"] + additional_fusesoc_argument: "--mapping=lowrisc:systems:top_earlgrey:0.1" + rel_path: "hw/ip/uart/lint/{tool}" +}, +``` + +Mappings cannot be used to override a virtual core which has already been resolved to a implementation in the target dependency tree. + +If multiple mappings are provided for a virtual core, the following build time error will be generated: +``` +RuntimeError: The following sources are in multiple mappings: + {, ...}. +``` -After the discovery process has completed, a script (`primgen`) creates -- an abstract primitive (see above), and -- an entry in the `prim_pkg` package in the form of `prim_pkg::ImplTechlibname` - to identify the technology library by its name. ## User Guide -### Use primitives +### Using primitives Primitives are normal SystemVerilog modules, and can be used as usual: -* instantiate it like a normal SystemVerilog module, and -* add a dependency in the FuseSoC core file. - -Technology-dependent primitives have an additional parameter called `Impl`. -Set this parameter to use a specific implementation of the primitive for this -specific instance. For example: - -```systemverilog -prim_ram_2p #( - .Width (TotalWidth), - .Depth (Depth), - // Force the use of the tsmc40lp technology library for this instance, instead - // of using the build-time default. - .Impl(prim_pkg::ImplTsmc40lp) -) u_mem ( - .clk_a_i (clk_i), - ... -) -``` +1. Instantiate it like a normal SystemVerilog module. + ```systemverilog + prim_fifo_sync #( + .Width (8), + .Pass (1'b0), + .Depth (TxFifoDepth) + ) u_uart_txfifo ( + .clk_i, + // .. + .err_o () + ) + ``` +2. Add it as a dependency in the FuseSoC core file. + ```yaml + name: "lowrisc:ip:uart:0.1" + description: "uart" + filesets: + files_rtl: + depend: + - lowrisc:virtual_constants:top_pkg + - lowrisc:prim:prim_fifo_sync + ``` + +### Creating a technology library +To create a technology library follow these steps: -### Set the default technology library +1. Choose a name for the new technology library. + Names are all lower-case. + To ease sharing of technology libraries it is encouraged to pick a very specific name, rather than a generic name like `asic`. + `mytech` will be used as a placeholder name in the examples. +2. Create a directory in `hw/ip` with the prefix `prim_` followed by the name of your technology library. +3. Copy `hw/ip/prim_generic/prim_generic.core` into the new directory renaming it to match your primitive library, e.g. `hw/ip/prim_mytech/prim_mytech.core` + Change the vendor and name in this file, e.g. `lowrisc:prim_generic` would become `partner:prim_mytech` where your organisation's name can be used in the place of 'partner'. + Also, edit the description to better describe the specific implementation. +4. For every primitive implemented by your library: + 1. Copy across the generic implementation into your library, e.g. `cp hw/ip/prim_generic/rtl/prim_flop.sv hw/ip/prim_mytech/rtl/prim_flop.sv`. + 2. Make your changes to the implementation without modifying the module name, ports or removing parameters. + 3. Copy the generic primitive's core description into your library, e.g. `cp hw/ip/prim_generic/prim_generic_flop.core hw/ip/prim_mytech/prim_mytech_flop.core`. + 4. Edit this copied primitive core file so that it has the new primitive library name, e.g. replacing `lowrisc:prim_generic:flop` with `partner:prim_mytech:flop`. + 5. Then in the libraries main core file, e.g. `hw/ip/prim_mytech/prim_mytech.core`, replace all instances of the generic implementation with your specific implementation, e.g. replacing `lowrisc:prim_generic:flop` with `partner:prim_mytech:flop` again. -If no specific technology library is chosen for an instantiated primitive the -default library is used. The SystemVerilog define `PRIM_DEFAULT_IMPL` can be -used to set the default for the whole design. Set this define to one of the enum -values in `prim_pkg.sv` in the form `prim_pkg::ImplTechlibname`. `Techlibname` -is the capitalized name of the technology library. +You don't have to have your own implementation for every primitive. +You can rely on the generic implementation or even another library's implementation for other primitives. -In the top-level FuseSoC core file the default technology library can be chosen -like this: +Technology libraries also do not have to live in the OpenTitan repository. +If they are not in the OpenTitan repository, you need to make sure the path to them is given to FuseSoC with either an additional `--cores-root=` argument or set in `fusesoc.conf`. +This is useful in cases where technology libraries contain vendor-specific code which cannot be shared widely or openly. + + +### Selecting a technology library + +As outlined in [Resolution of Concrete Implementations](#resolution-of-concrete-implementations), you can select a technology library in one of two ways. + +If you have your own target which requires a particular primitive, you should add the technology library's VLNV to its dependencies. +`hw/top_earlgrey/chip_earlgrey_cw310.core` is an example of an core requiring a particular technology library, namely `lowrisc:prim_xilinx:all`. +You'll notice this VLNV in its dependencies. + +If you are running a target which is generic across different technology libraries, then you should use mappings to select the technology library you would like to use. +In some cases, a default technology library may already by included, but this will be removable using FuseSoC CLI *[Flags][]* to modify the build process. +`hw/top_earlgrey/chip_earlgrey_asic.core` is an example of one of these cores. +You should provide the `fileset_partner` flag to disable the default implementation, as well as your mapping to select an alternate implementation. + +[Flags]: https://fusesoc.readthedocs.io/en/stable/user/build_system/flags.html ```yaml -# my_toplevel.core - -# Declare filesets and other things (omitted) - -parameters: - # Make the parameter known to FuseSoC to enable overrides from the - # command line. If not overwritten, use the generic technology library. - PRIM_DEFAULT_IMPL: - datatype: str - paramtype: vlogdefine - description: Primitives implementation to use, e.g. "prim_pkg::ImplGeneric". - default: prim_pkg::ImplGeneric - -targets: - fpga_synthesis: - filesets: - - my_rtl_files - parameters: - # Use the xilinx technology library for this target by default. - - PRIM_DEFAULT_IMPL=prim_pkg::ImplXilinx - toplevel: my_toplevel +# hw/top_earlgrey/chip_earlgrey_asic.core +name: "lowrisc:systems:chip_earlgrey_asic:0.1" +description: "Earl Grey chip level" + +filesets: + files_rtl: + depend: + - lowrisc:systems:top_earlgrey:0.1 + - lowrisc:systems:top_earlgrey_pkg + - lowrisc:systems:top_earlgrey_padring + - lowrisc:earlgrey_ip:flash_ctrl_prim_reg_top + - "fileset_partner ? (partner:systems:top_earlgrey_ast)" + - "fileset_partner ? (partner:systems:top_earlgrey_scan_role_pkg)" + - "fileset_partner ? (partner:prim_tech:all)" + - "fileset_partner ? (partner:prim_tech:flash)" + - "!fileset_partner ? (lowrisc:systems:top_earlgrey_ast)" + - "!fileset_partner ? (lowrisc:earlgrey_systems:scan_role_pkg)" + - "!fileset_partner ? (lowrisc:prim_generic:all)" + - "!fileset_partner ? (lowrisc:prim_generic:flash)" ``` +```sh +fusesoc \ + --cores-root=$OT_REPO \ + run \ + --flag fileset_partner \ # Disable default implementation + --mapping partner:prim_mytech:all \ # Select alternate implementation via mappings + lowrisc:systems:chip_earlgrey_asic +``` +### prim_asap7 example -### Create a technology library + [ASAP7](https://github.com/The-OpenROAD-Project/asap7) is an open-source standard-cell library. + It serves as an example for partners to integrate their own technology specific prim library. -To create a technology library follow these steps: +The steps in [creating a tech library](#creating-a-technology-library) were followed to create this prim library. + +Each standard-cell instance name is prefixed with a `u_size_only_` such that these instances can be easily identified during synthesis and preserved. + +### Important synthesis constraints to keep important redundant constructs + +The basic prim instances cannot be removed or merged with other cells through logic optimization or constant propagation as this would remove important security countermeasures from the design. + +All instantiated basic gates (`buf`, `mux2`, `inv`, `clock_gating`, `and2`, `xor2`, `xnor2`, `flop`) should be instantiated with a name prefix of `u_size_only_` such that preserve attributes can be set during synthesis. +The syntax to set a preserved attribute varies across tool providers. +To make sure the right constraints are applied, a simple example design (`prim_sdc_example`) is provided. +This design can be synthesized, and its netlist can be analyzed to verify that the correct constraints are applied and all important cells are preserved. + +The required files for synthesis can be generated with the following command: + +```shell +fusesoc --cores-root . \ + run \ + --target=syn \ + --flag fileset_partner \ + --mapping lowrisc:prim_asap7:all \ + --setup \ + --build-root build lowrisc:prim:sdc_example +``` + +By setting the `fileset_partner` flag, the generic prim implementation is not used, and the one provided through the mapping argument is used instead. +Please note, on designs with other technology dependent files, the `fileset_partner` flag also selects other technology specific implementations (e.g. OTP, Flash, JTAG, AST, pads). +If those are not used, they can be mapped to the generic implementations. + +#### Checks on the generated netlist + +After synthesizing the top module `prim_sdc_example` the following checks should be performed on the netlist: + +1. In the synthesized netlist, the following number of size_only instances must be present: + +| cell names | buf | and2 | xor | xnor | flop | clock_mux2 | clock_gating | +| -----------| ---- |------|----- |------ |------|------------|--------------| +| #instances | 328 | 56 | 120 | 56 | 252 | 2 | 2 | + +2. None of the test_*_o signals can be driven by a constant 0 or 1. +The instantiated `size_only` instances must prevent logic optimizations and keep the output comparators. +This can be checked with the synthesis tool, e.g. `check_design -constant` + +3. None of the buffers or flip flops in this example design are unloaded if constraints are applied correctly. +This can be checked by the synthesis tool, e.g. `check_design -unloaded_comb/-unloaded_seqs` + +4. `lc_en_o`, `mubi_o` signals cannot be driven to a constant value because optimization or constant propagation across preserved instances is not allowed. + +5. `lc_en_i`, `mubi_i` signals can only be connected to variables, or legal values (`MuBi4True`, `MuBi4False`, `On`, `Off`) + +If all checks are successful, the same constraints can be applied to the full design. +The script `utils/design/check-netlist.py` [check-netlist] can be used to report a summary of size_only cells in a netlist. +It can also automate an initial version of checks (4) and (5) but it does **not** replace a final manual inspection of the netlist. -- Choose a name for the new technology library. Names are all lower-case. - To ease sharing of technology libraries it is encouraged to pick a very - specific name, e.g. `tsmc40lp`, and not `asic`. -- Copy the `prim_generic` folder into an arbitrary location (can be outside - of this repository). Name the folder `prim_YOURLIBRARYNAME`. -- Replace the word `generic` everywhere with the name of your technology - library. This includes - - file and directory names (e.g. `prim_generic_ram1p.sv` becomes - `prim_tsmc40lp_ram1p.sv`), - - module names (e.g. `prim_generic_ram1p` becomes `prim_tsmc40lp_ram1p`), and - - all other references (grep for it!). -- Implement all primitives. Replace the module body of the generic - implementation with a technology-specific implementation as needed. Do *not* - modify the list of ports or parameters in any way! - -## Implementation details - -Technology-dependent primitives are implemented as a FuseSoC generator. The -core of the primitive (e.g. `lowrisc:prim:rom` in `prim/prim_rom.core`) calls -a FuseSoC generator. This generator is the script `util/primgen.py`. As input, -the script receives a list of all cores found by FuseSoC anywhere in its search -path. The script then looks through the cores FuseSoC discovered and extracts -a list of technology libraries out of it. It then goes on to create the -abstract primitive (copying over the list of parameters and ports from the -generic implementation), and an associated core file, which depends on all -technology-dependent libraries that were found. +[check-netlist]: https://github.com/lowRISC/opentitan/tree/master/util/design#netlist-checker-script diff --git a/vendor/lowrisc_ip/ip/prim/doc/prim_clock_gp_mux2.md b/vendor/lowrisc_ip/ip/prim/doc/prim_clock_gp_mux2.md deleted file mode 100644 index b73a288e41..0000000000 --- a/vendor/lowrisc_ip/ip/prim/doc/prim_clock_gp_mux2.md +++ /dev/null @@ -1,26 +0,0 @@ -# Primitive Component: Two input clock Mux with glitch protection - -# Overview -`prim_clock_gp_mux2` is a two input clock mux that protects a glitch. When a current clock source is switched to the next clock source where two clocks are totally unrelated, a glitch can be generated as follows. - -### Glitch -```wavejson -{signal: [ - {name: 'clk0_i', wave: 'L.H....L....H....L....H....'}, - {name: 'clk1_i', wave: 'L.H.L.H.L.H.L.H.L.H.L.H.L.H'}, - {name: 'sel_i', wave: '0............1.............'}, - {name: 'clk_o', wave: 'L.H....L....HLH.L.H.L.H.L.H'}, - ]} -``` - -This glitch free clock mux can avoid glitch by placing two parallel synchronizers connected to each other. 1st flop and 2nd flop are triggered by positive edge and negative edge respectively to protect metastability on the sel_i signal. The following waveform shows the result. - -### Glitch Free -```wavejson -{signal: [ - {name: 'clk0_i', wave: 'L.H....L....H....L....H....'}, - {name: 'clk1_i', wave: 'L.H.L.H.L.H.L.H.L.H.L.H.L.H'}, - {name: 'sel_i', wave: '0............1.............'}, - {name: 'clk_o', wave: 'L.H....L....H....LH.L.H.L.H'}, - ]} -``` diff --git a/vendor/lowrisc_ip/ip/prim/doc/prim_keccak.md b/vendor/lowrisc_ip/ip/prim/doc/prim_keccak.md index 122489ea84..e5e5d6ea04 100644 --- a/vendor/lowrisc_ip/ip/prim/doc/prim_keccak.md +++ b/vendor/lowrisc_ip/ip/prim/doc/prim_keccak.md @@ -2,11 +2,11 @@ # Overview -`prim_keccak` is a single round implementation of the permutation stage in [SHA3 algorithm][fibs-pub-202]. +`prim_keccak` is a single round implementation of the Keccak_p permutation stage in [SHA3 algorithm][fibs-pub-202]. Keccak primitive module assumes the number of rounds is less than or equal to 12 + 2L. It supports all combinations of the data width described in the [spec][fibs-pub-202]. -This implementation is not currently hardened against side-channel or fault injection attacks. -It implements the Keccak_p function. +Note that this implementation does not include any countermeasures for security hardening against implementation attacks. +Please refer to the [`keccak_2share` module](https://github.com/lowRISC/opentitan/blob/master/hw/ip/kmac/rtl/keccak_2share.sv) for the side-channel-hardened implementation used in the [hardened KMAC hardware IP block](../../kmac/README.md). [fibs-pub-202]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf diff --git a/vendor/lowrisc_ip/ip/prim/doc/prim_packer_fifo.md b/vendor/lowrisc_ip/ip/prim/doc/prim_packer_fifo.md index b79f565d95..f37b27eb85 100644 --- a/vendor/lowrisc_ip/ip/prim/doc/prim_packer_fifo.md +++ b/vendor/lowrisc_ip/ip/prim/doc/prim_packer_fifo.md @@ -8,7 +8,7 @@ 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, +The controls for this module are modelled 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 diff --git a/vendor/lowrisc_ip/ip/prim/doc/prim_ram_1p_scr.md b/vendor/lowrisc_ip/ip/prim/doc/prim_ram_1p_scr.md index ad67d18fe2..1eafce8a15 100644 --- a/vendor/lowrisc_ip/ip/prim/doc/prim_ram_1p_scr.md +++ b/vendor/lowrisc_ip/ip/prim/doc/prim_ram_1p_scr.md @@ -2,9 +2,10 @@ # Overview -The scrambling primitive `prim_ram_1p_scr` employs a reduced-round (7 instead of 11) PRINCE block cipher in CTR mode to scramble the data. +The scrambling primitive `prim_ram_1p_scr` employs a reduced-round (5 or 7 instead of 11) PRINCE block cipher in CTR mode to scramble the data. The PRINCE lightweight block cipher has been selected due to its low latency and low area characteristics, see also [prim_prince](./prim_prince.md) for more information on PRINCE. -The number of rounds is reduced to 7 in order to ease timing pressure and ensure single cycle operation (the number of rounds can always be increased if it turns out that there is enough timing slack). +In the default configuration, the number of rounds is reduced to 7 in order to ease timing pressure and ensure single cycle operation (the number of rounds can always be increased via the `NumPrinceRoundsHalf` parameter if it turns out that there is enough timing slack). +To ease timing closure at the top level, the number of rounds used for scrambling the main SRAM and the instruction cache of the Ibex processor core is 5 (`NumPrinceRoundsHalf` = 2). In [CTR mode](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_(CTR)), the block cipher is used to encrypt a 64bit IV with the scrambling key in order to create a 64bit keystream block that is bitwise XOR'ed with the data in order to transform plaintext into ciphertext and vice versa. The IV is assembled by concatenating a nonce with the word address. diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_alert/data/prim_alert_testplan.hjson b/vendor/lowrisc_ip/ip/prim/dv/prim_alert/data/prim_alert_testplan.hjson index e55ac1d472..c840b558c8 100644 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_alert/data/prim_alert_testplan.hjson +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_alert/data/prim_alert_testplan.hjson @@ -74,7 +74,7 @@ desc: '''Verify the integrity errors from the prim_alert_sender and prim_alert_receiver pair. 1). `Ack_p/n` integrity error: - - Send an alert reqeust by driving `alert_req` pin to 1. + - Send an alert request by driving `alert_req` pin to 1. - Force `ack_p` signal to stay low to trigger an integrity error. - Verify that prim_alert_receiver can identify the integrity error by setting `integ_fail_o` output to 1. diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_alert/prim_alert_sim_cfg.hjson b/vendor/lowrisc_ip/ip/prim/dv/prim_alert/prim_alert_sim_cfg.hjson index a3154db05d..ffab7bac12 100644 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_alert/prim_alert_sim_cfg.hjson +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_alert/prim_alert_sim_cfg.hjson @@ -38,6 +38,10 @@ name: fatal_alert build_opts: ["+define+IS_FATAL"] } + { + name: fatal_alert_with_3_cycles_skew + build_opts: ["+define+IS_FATAL", "+defines+IS_3_CYCLE_SKEW"] + } { name: sync_fatal_alert build_opts: ["+define+IS_FATAL", "+define+IS_SYNC"] @@ -53,6 +57,10 @@ name: prim_async_fatal_alert build_mode: fatal_alert } + { + name: prim_async_fatal_alert_with_3_cycles_skew + build_mode: fatal_alert_with_3_cycles_skew + } { name: prim_sync_alert build_mode: sync_alert @@ -66,7 +74,7 @@ regressions: [ { name: smoke - tests: ["prim_async_alert"] + tests: ["prim_async_alert", "prim_async_fatal_alert_with_3_cycles_skew"] } ] overrides: [ @@ -74,5 +82,9 @@ name: vcs_cov_cfg_file value: "-cm_hier {proj_root}/hw/ip/prim/dv/prim_alert/data/prim_alert_cover.cfg" } + { + name: xcelium_cov_cfg_file + value: "" + } ] } diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_alert/tb/prim_alert_tb.sv b/vendor/lowrisc_ip/ip/prim/dv/prim_alert/tb/prim_alert_tb.sv index 4f45cd2d3a..98efda7e9d 100644 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_alert/tb/prim_alert_tb.sv +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_alert/tb/prim_alert_tb.sv @@ -22,7 +22,7 @@ module prim_alert_tb; // config ////////////////////////////////////////////////////// - // this can be overriden on the command line + // this can be overridden on the command line `ifdef IS_SYNC localparam bit IsAsync = 0; `else @@ -33,6 +33,11 @@ module prim_alert_tb; `else localparam bit IsFatal = 0; `endif + `ifdef IS_3_CYCLE_SKEW + localparam int unsigned SkewCycles = 3; + `else + localparam int unsigned SkewCycles = 1; + `endif localparam time ClkPeriod = 10_000; localparam int WaitCycle = IsAsync ? 3 : 1; @@ -85,6 +90,7 @@ module prim_alert_tb; prim_mubi_pkg::mubi4_t init_trig = prim_mubi_pkg::MuBi4False; prim_alert_sender #( .AsyncOn(IsAsync), + .SkewCycles(SkewCycles), .IsFatal(IsFatal) ) i_alert_sender ( .clk_i(clk), @@ -98,7 +104,8 @@ module prim_alert_tb; ); prim_alert_receiver #( - .AsyncOn(IsAsync) + .AsyncOn(IsAsync), + .SkewCycles(SkewCycles) ) i_alert_receiver ( .clk_i(clk), .rst_ni(rst_n), @@ -215,7 +222,7 @@ module prim_alert_tb; end // Sequence 4) `Ack_p/n` integrity check sequence. - // Note that alert_tx signal interigy errors are verified in alert_handler testbench. + // Note that alert_tx signal integrity errors are verified in alert_handler testbench. main_clk.wait_clks($urandom_range(MinHandshakeWait, 10)); alert_req = 1; diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/ascon_model_dpi.c b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/ascon_model_dpi.c new file mode 100644 index 0000000000..5218da15b3 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/ascon_model_dpi.c @@ -0,0 +1,190 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "ascon_model_dpi.h" + +#include +#include +#include +#include +#include + +#include "svdpi.h" +#include "vendor/ascon_ascon-c/ascon128/crypto_aead.h" +#include "vendor/ascon_ascon-c/ascon128/round.h" + +void c_dpi_aead_encrypt(svOpenArrayHandle ct, svOpenArrayHandle msg, + unsigned int msg_len, svOpenArrayHandle ad, + unsigned int ad_len, svOpenArrayHandle nonce, + svOpenArrayHandle key) { + unsigned long long *clen; + unsigned long long mlen, alen; + mlen = msg_len; + alen = ad_len; + + // clen and nsec is accutally not needed, but part of the API + clen = (unsigned long long *)malloc(sizeof(unsigned long long)); + uint8_t *nsec; + + uint8_t *c, *m, *a, *npub, *k; + c = (uint8_t *)svGetArrayPtr(ct); + a = (uint8_t *)svGetArrayPtr(ad); + m = (uint8_t *)svGetArrayPtr(msg); + npub = (uint8_t *)svGetArrayPtr(nonce); + k = (uint8_t *)svGetArrayPtr(key); + + /*printf("ad length %d\n", ad_len); + printf("ad = "); + for (int i = 0; i < ad_len; i++) { + printf("%02X", a[i]); + } + printf("\n"); + + printf("msg length %d\n", msg_len); + printf("msg = "); + for (int i = 0; i < msg_len; i++) { + printf("%02X", m[i]); + } + printf("\n"); + + printf("key = "); + for (int i = 0; i < 16; i++) { + printf("%02X", k[i]); + } + printf("\n"); + + printf("nonce = "); + for (int i = 0; i < 16; i++) { + printf("%02X", npub[i]); + } + printf("\n");*/ + + crypto_aead_encrypt(c, clen, m, mlen, a, alen, nsec, npub, k); + /*printf("ct length %d\n", (int)*clen); + + printf("ct = "); + for (int i = 0; i < *clen; i++) { + printf("%02X", c[i]); + } + printf("\n");*/ + free(clen); + return; +} + +void c_dpi_aead_decrypt(svOpenArrayHandle ct, unsigned int ct_len, + svOpenArrayHandle msg, svOpenArrayHandle ad, + unsigned int ad_len, svOpenArrayHandle nonce, + svOpenArrayHandle key) { + unsigned long long *mlen; + unsigned long long clen, alen; + clen = ct_len; + alen = ad_len; + + // mlen and nsec is accutally not needed, but part of the API + mlen = (unsigned long long *)malloc(sizeof(unsigned long long)); + uint8_t *nsec; + + uint8_t *c, *m, *a, *npub, *k; + c = (uint8_t *)svGetArrayPtr(ct); + a = (uint8_t *)svGetArrayPtr(ad); + m = (uint8_t *)svGetArrayPtr(msg); + npub = (uint8_t *)svGetArrayPtr(nonce); + k = (uint8_t *)svGetArrayPtr(key); + + /*printf("ad length %d\n", ad_len); + printf("ad = "); + for (int i = 0; i < ad_len; i++) { + printf("%02X", a[i]); + } + printf("\n"); + + printf("ct length %d\n", ct_len); + printf("ct = "); + for (int i = 0; i < ct_len; i++) { + printf("%02X", m[i]); + } + printf("\n"); + + printf("key = "); + for (int i = 0; i < 16; i++) { + printf("%02X", k[i]); + } + printf("\n"); + + printf("nonce = "); + for (int i = 0; i < 16; i++) { + printf("%02X", npub[i]); + } + printf("\n");*/ + crypto_aead_decrypt(m, mlen, nsec, c, clen, a, alen, npub, k); + /*printf("msg length %d\n", (int)*mlen); + + printf("msg = "); + for (int i = 0; i < *mlen; i++) { + printf("%02X", c[i]); + } + printf("\n");*/ + free(mlen); + return; +} + +void c_dpi_ascon_round(const svBitVecVal *data_i, svBit *round_i, + svBitVecVal *data_o) { + uint8_t round; + + // get input data from simulator + ascon_state_t *state = ascon_data_get(data_i); + round = (uint8_t)*round_i; + + ROUND(state, round); + + ascon_data_put(data_o, state); + + return; +} + +ascon_state_t *ascon_data_get(const svBitVecVal *data_i) { + ascon_state_t *data; + + // alloc data buffer + data = (ascon_state_t *)malloc(sizeof(ascon_state_t)); + assert(data); + + // get data from simulator, convert from 2D to 1D + printf("Getter:\n"); + for (int i = 0; i < 5; i++) { + svBitVecVal value; + + value = data_i[2 * i]; + data->x[i] = (uint64_t)value; + printf("Value of data_i = %X\n", value); + value = data_i[(2 * i) + 1]; + data->x[i] |= ((uint64_t)value) << 32; + printf("Value of data_i = %X\n", value); + printf("Value of X[%i] = %jX\n", i, data->x[i]); + } + + return data; +} + +void ascon_data_put(svBitVecVal *data_o, ascon_state_t *data) { + printf("Putter:\n"); + // convert from 1D to 2D, write output data to simulation + for (int i = 0; i < 5; i++) { + svBitVecVal value; + + printf("Value of X[%i] = %jX\n", i, data->x[i]); + value = (svBitVecVal)(data->x[i]); + printf("Value of data_o = %X\n", value); + data_o[(2 * i)] = value; + value = (svBitVecVal)((data->x[i]) >> (32)); + printf("Value of data_o = %X\n", value); + data_o[(2 * i) + 1] = value; + } + + // free data + free(data); + + return; +} diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/ascon_model_dpi.core b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/ascon_model_dpi.core new file mode 100644 index 0000000000..e2d3d355df --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/ascon_model_dpi.core @@ -0,0 +1,29 @@ +CAPI=2: +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:dv:ascon_model_dpi" +description: "ASCON model DPI" +filesets: + files_dv: + depend: + - lowrisc:prim:prim_ascon + files: + - vendor/ascon_ascon-c/ascon128/api.h: { file_type: cSource, is_include_file: true } + - vendor/ascon_ascon-c/ascon128/round.h: { file_type: cSource, is_include_file: true } + - vendor/ascon_ascon-c/ascon128/permutations.h: { file_type: cSource, is_include_file: true } + - vendor/ascon_ascon-c/ascon128/ascon.h: { file_type: cSource, is_include_file: true } + - vendor/ascon_ascon-c/ascon128/constants.h: { file_type: cSource, is_include_file: true } + - vendor/ascon_ascon-c/ascon128/printstate.c: { file_type: cSource} + - vendor/ascon_ascon-c/ascon128/printstate.h: { file_type: cSource, is_include_file: true } + - vendor/ascon_ascon-c/ascon128/word.h: { file_type: cSource, is_include_file: true } + - vendor/ascon_ascon-c/ascon128/crypto_aead.h: { file_type: cSource, is_include_file: true } + - vendor/ascon_ascon-c/ascon128/aead.c: { file_type: cSource} + - ascon_model_dpi.c: { file_type: cSource } + - ascon_model_dpi.h: { file_type: cSource, is_include_file: true } + - ascon_model_dpi_pkg.sv: { file_type: systemVerilogSource } + +targets: + default: + filesets: + - files_dv diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/ascon_model_dpi.h b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/ascon_model_dpi.h new file mode 100644 index 0000000000..7a1ec3ee50 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/ascon_model_dpi.h @@ -0,0 +1,76 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef OPENTITAN_HW_IP_PRIM_DV_PRIM_ASCON_ASCON_MODEL_DPI_ASCON_MODEL_DPI_H_ +#define OPENTITAN_HW_IP_PRIM_DV_PRIM_ASCON_ASCON_MODEL_DPI_ASCON_MODEL_DPI_H_ + +#include "svdpi.h" +#include "vendor/ascon_ascon-c/ascon128/ascon.h" +#include "vendor/ascon_ascon-c/ascon128/crypto_aead.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief + * + * @param ct Output data with concardinated cipher text + tag + * @param ad Input: Associated Data + * @param ad_len Length of assoicated data in bytes + * @param msg Input: Plaintext + * @param msg_len Length of plaintext + * @param nonce Input: 128 bit Nonce + * @param key Input: 128 bit Key + */ +void c_dpi_aead_encrypt(svOpenArrayHandle ct, svOpenArrayHandle ad, + unsigned int ad_len, svOpenArrayHandle msg, + unsigned int msg_len, svOpenArrayHandle nonce, + svOpenArrayHandle key); +/** + * @brief + * + * @param ct Input data with concardinated cipher text + tag + * @param ct_len Length of concardinated cipher text + tag + * @param msg Output: Plaintext + * @param ad Input: Associated Data + * @param ad_len Length of assoicated data in bytes + * @param nonce Input: 128 bit Nonce + * @param key Input: 128 bit Key + */ +void c_dpi_aead_decrypt(svOpenArrayHandle ct, unsigned int ct_len, + svOpenArrayHandle msg, svOpenArrayHandle ad, + unsigned int ad_len, svOpenArrayHandle nonce, + svOpenArrayHandle key); + +/** + * Perform one ascon round. + * + * @param data_i Input data is expected to be 320 bit ascon state size + * @param round_i Round Number + * @param data_o Output data + */ +void c_dpi_ascon_round(const svBitVecVal *data_i, svBit *round_i, + svBitVecVal *data_o); + +/** + * Get packed data block from simulation. + * + * @param data_i Input data from simulation + * @return Pointer to data copied to memory, 0 in case of an error + */ +ascon_state_t *ascon_data_get(const svBitVecVal *data_i); + +/** + * Write packed data block to simulation and free the source buffer afterwards. + * + * @param data_o Output data for simulation + * @param data Data to be copied to simulation, freed after the operation + */ +void ascon_data_put(svBitVecVal *data_o, ascon_state_t *data); + +#ifdef __cplusplus +} // extern "C" +#endif +#endif // OPENTITAN_HW_IP_PRIM_DV_PRIM_ASCON_ASCON_MODEL_DPI_ASCON_MODEL_DPI_H_ diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/ascon_model_dpi_pkg.sv b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/ascon_model_dpi_pkg.sv new file mode 100644 index 0000000000..288a3ffdc3 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/ascon_model_dpi_pkg.sv @@ -0,0 +1,35 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +package ascon_model_dpi_pkg; + + + import "DPI-C" context function void c_dpi_ascon_round( + input bit[4:0][7:0][7:0] data_i, + input bit[7:0] round_i, + output bit[4:0][7:0][7:0] data_o + ); + + + import "DPI-C" context function void c_dpi_aead_encrypt( + output byte unsigned ct[], + input byte unsigned msg[], + input int msg_len, + input byte unsigned ad[], + input int unsigned ad_len, + input byte unsigned nonce[], + input byte unsigned key[] + ); + + import "DPI-C" context function void c_dpi_aead_decrypt( + input byte unsigned ct[], + input int ct_len, + output byte unsigned msg[], + input byte unsigned ad[], + input int unsigned ad_len, + input byte unsigned nonce[], + input byte unsigned key[] + ); + +endpackage diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/.clang-format b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/.clang-format new file mode 100644 index 0000000000..1d748780cb --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/.clang-format @@ -0,0 +1,3 @@ +# This disables clang-format on all files in any vendored projects. +DisableFormat: true +SortIncludes: false diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c.lock.hjson b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c.lock.hjson new file mode 100644 index 0000000000..8fb8ff2509 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c.lock.hjson @@ -0,0 +1,14 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// This file is generated by the util/vendor script. Please do not modify it +// manually. + +{ + upstream: + { + url: https://github.com/ascon/ascon-c.git + rev: 46f35c0ae911b8d9352bcf4d13dfdf6f32079c0d + } +} diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c.vendor.hjson b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c.vendor.hjson new file mode 100644 index 0000000000..209189c26b --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c.vendor.hjson @@ -0,0 +1,29 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +{ + name: "ascon_ascon-c", + target_dir: "ascon_ascon-c", + + upstream: { + url: "https://github.com/ascon/ascon-c.git", + rev: "main", + }, + + mapping : [ + {from: 'crypto_aead/ascon128v12/ref', to: 'ascon128'}, + {from: 'tests/crypto_aead.h', to: 'ascon128'} + {from: 'crypto_aead/ascon128av12/ref', to: 'ascon128a'}, + {from: 'tests/crypto_aead.h', to: 'ascon128a'}, + {from: 'LICENSE', to: 'LICENSE'} + ] + + exclude_from_upstream : [ + "crypto_aead/ascon128v12/ref/implementors", + "crypto_aead/ascon128v12/ref/goal-constindex", + "crypto_aead/ascon128v12/ref/goal-constbranch", + "crypto_aead/ascon128av12/ref/implementors", + "crypto_aead/ascon128av12/ref/goal-constindex", + "crypto_aead/ascon128av12/ref/goal-constbranch", + ] +} diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/LICENSE b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/LICENSE new file mode 100644 index 0000000000..3bbbc1ee92 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/LICENSE @@ -0,0 +1,116 @@ +CC0 1.0 Universal + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator and +subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for the +purpose of contributing to a commons of creative, cultural and scientific +works ("Commons") that the public can reliably and without fear of later +claims of infringement build upon, modify, incorporate in other works, reuse +and redistribute as freely as possible in any form whatsoever and for any +purposes, including without limitation commercial purposes. These owners may +contribute to the Commons to promote the ideal of a free culture and the +further production of creative, cultural and scientific works, or to gain +reputation or greater distribution for their Work in part through the use and +efforts of others. + +For these and/or other purposes and motivations, and without any expectation +of additional consideration or compensation, the person associating CC0 with a +Work (the "Affirmer"), to the extent that he or she is an owner of Copyright +and Related Rights in the Work, voluntarily elects to apply CC0 to the Work +and publicly distribute the Work under its terms, with knowledge of his or her +Copyright and Related Rights in the Work and the meaning and intended legal +effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not limited +to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, communicate, + and translate a Work; + + ii. moral rights retained by the original author(s) and/or performer(s); + + iii. publicity and privacy rights pertaining to a person's image or likeness + depicted in a Work; + + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + + v. rights protecting the extraction, dissemination, use and reuse of data in + a Work; + + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation thereof, + including any amended or successor version of such directive); and + + vii. other similar, equivalent or corresponding rights throughout the world + based on applicable law or treaty, and any national implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention of, +applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and +unconditionally waives, abandons, and surrenders all of Affirmer's Copyright +and Related Rights and associated claims and causes of action, whether now +known or unknown (including existing as well as future claims and causes of +action), in the Work (i) in all territories worldwide, (ii) for the maximum +duration provided by applicable law or treaty (including future time +extensions), (iii) in any current or future medium and for any number of +copies, and (iv) for any purpose whatsoever, including without limitation +commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes +the Waiver for the benefit of each member of the public at large and to the +detriment of Affirmer's heirs and successors, fully intending that such Waiver +shall not be subject to revocation, rescission, cancellation, termination, or +any other legal or equitable action to disrupt the quiet enjoyment of the Work +by the public as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason be +judged legally invalid or ineffective under applicable law, then the Waiver +shall be preserved to the maximum extent permitted taking into account +Affirmer's express Statement of Purpose. In addition, to the extent the Waiver +is so judged Affirmer hereby grants to each affected person a royalty-free, +non transferable, non sublicensable, non exclusive, irrevocable and +unconditional license to exercise Affirmer's Copyright and Related Rights in +the Work (i) in all territories worldwide, (ii) for the maximum duration +provided by applicable law or treaty (including future time extensions), (iii) +in any current or future medium and for any number of copies, and (iv) for any +purpose whatsoever, including without limitation commercial, advertising or +promotional purposes (the "License"). The License shall be deemed effective as +of the date CC0 was applied by Affirmer to the Work. Should any part of the +License for any reason be judged legally invalid or ineffective under +applicable law, such partial invalidity or ineffectiveness shall not +invalidate the remainder of the License, and in such case Affirmer hereby +affirms that he or she will not (i) exercise any of his or her remaining +Copyright and Related Rights in the Work or (ii) assert any associated claims +and causes of action with respect to the Work, in either case contrary to +Affirmer's express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + + b. Affirmer offers the Work as-is and makes no representations or warranties + of any kind concerning the Work, express, implied, statutory or otherwise, + including without limitation warranties of title, merchantability, fitness + for a particular purpose, non infringement, or the absence of latent or + other defects, accuracy, or the present or absence of errors, whether or not + discoverable, all to the greatest extent permissible under applicable law. + + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without limitation + any person's Copyright and Related Rights in the Work. Further, Affirmer + disclaims responsibility for obtaining any necessary consents, permissions + or other rights required for any use of the Work. + + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to this + CC0 or use of the Work. + +For more information, please see + \ No newline at end of file diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/aead.c b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/aead.c new file mode 100644 index 0000000000..a8abab168b --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/aead.c @@ -0,0 +1,181 @@ +#include "api.h" +#include "ascon.h" +#include "crypto_aead.h" +#include "permutations.h" +#include "printstate.h" +#include "word.h" + +int crypto_aead_encrypt(unsigned char* c, unsigned long long* clen, + const unsigned char* m, unsigned long long mlen, + const unsigned char* ad, unsigned long long adlen, + const unsigned char* nsec, const unsigned char* npub, + const unsigned char* k) { + (void)nsec; + + /* set ciphertext size */ + *clen = mlen + CRYPTO_ABYTES; + + /* load key and nonce */ + const uint64_t K0 = LOADBYTES(k, 8); + const uint64_t K1 = LOADBYTES(k + 8, 8); + const uint64_t N0 = LOADBYTES(npub, 8); + const uint64_t N1 = LOADBYTES(npub + 8, 8); + + /* initialize */ + ascon_state_t s; + s.x[0] = ASCON_128_IV; + s.x[1] = K0; + s.x[2] = K1; + s.x[3] = N0; + s.x[4] = N1; + printstate("init 1st key xor", &s); + P12(&s); + s.x[3] ^= K0; + s.x[4] ^= K1; + printstate("init 2nd key xor", &s); + + if (adlen) { + /* full associated data blocks */ + while (adlen >= ASCON_128_RATE) { + s.x[0] ^= LOADBYTES(ad, 8); + printstate("absorb adata", &s); + P6(&s); + ad += ASCON_128_RATE; + adlen -= ASCON_128_RATE; + } + /* final associated data block */ + s.x[0] ^= LOADBYTES(ad, adlen); + s.x[0] ^= PAD(adlen); + printstate("pad adata", &s); + P6(&s); + } + /* domain separation */ + s.x[4] ^= DSEP(); + printstate("domain separation", &s); + + /* full plaintext blocks */ + while (mlen >= ASCON_128_RATE) { + s.x[0] ^= LOADBYTES(m, 8); + STOREBYTES(c, s.x[0], 8); + printstate("absorb plaintext", &s); + P6(&s); + m += ASCON_128_RATE; + c += ASCON_128_RATE; + mlen -= ASCON_128_RATE; + } + /* final plaintext block */ + s.x[0] ^= LOADBYTES(m, mlen); + STOREBYTES(c, s.x[0], mlen); + s.x[0] ^= PAD(mlen); + c += mlen; + printstate("pad plaintext", &s); + + /* finalize */ + s.x[1] ^= K0; + s.x[2] ^= K1; + printstate("final 1st key xor", &s); + P12(&s); + s.x[3] ^= K0; + s.x[4] ^= K1; + printstate("final 2nd key xor", &s); + + /* get tag */ + STOREBYTES(c, s.x[3], 8); + STOREBYTES(c + 8, s.x[4], 8); + + return 0; +} + +int crypto_aead_decrypt(unsigned char* m, unsigned long long* mlen, + unsigned char* nsec, const unsigned char* c, + unsigned long long clen, const unsigned char* ad, + unsigned long long adlen, const unsigned char* npub, + const unsigned char* k) { + (void)nsec; + + if (clen < CRYPTO_ABYTES) return -1; + + /* set plaintext size */ + *mlen = clen - CRYPTO_ABYTES; + + /* load key and nonce */ + const uint64_t K0 = LOADBYTES(k, 8); + const uint64_t K1 = LOADBYTES(k + 8, 8); + const uint64_t N0 = LOADBYTES(npub, 8); + const uint64_t N1 = LOADBYTES(npub + 8, 8); + + /* initialize */ + ascon_state_t s; + s.x[0] = ASCON_128_IV; + s.x[1] = K0; + s.x[2] = K1; + s.x[3] = N0; + s.x[4] = N1; + printstate("init 1st key xor", &s); + P12(&s); + s.x[3] ^= K0; + s.x[4] ^= K1; + printstate("init 2nd key xor", &s); + + if (adlen) { + /* full associated data blocks */ + while (adlen >= ASCON_128_RATE) { + s.x[0] ^= LOADBYTES(ad, 8); + printstate("absorb adata", &s); + P6(&s); + ad += ASCON_128_RATE; + adlen -= ASCON_128_RATE; + } + /* final associated data block */ + s.x[0] ^= LOADBYTES(ad, adlen); + s.x[0] ^= PAD(adlen); + printstate("pad adata", &s); + P6(&s); + } + /* domain separation */ + s.x[4] ^= DSEP(); + printstate("domain separation", &s); + + /* full ciphertext blocks */ + clen -= CRYPTO_ABYTES; + while (clen >= ASCON_128_RATE) { + uint64_t c0 = LOADBYTES(c, 8); + STOREBYTES(m, s.x[0] ^ c0, 8); + s.x[0] = c0; + printstate("insert ciphertext", &s); + P6(&s); + m += ASCON_128_RATE; + c += ASCON_128_RATE; + clen -= ASCON_128_RATE; + } + /* final ciphertext block */ + uint64_t c0 = LOADBYTES(c, clen); + STOREBYTES(m, s.x[0] ^ c0, clen); + s.x[0] = CLEARBYTES(s.x[0], clen); + s.x[0] |= c0; + s.x[0] ^= PAD(clen); + c += clen; + printstate("pad ciphertext", &s); + + /* finalize */ + s.x[1] ^= K0; + s.x[2] ^= K1; + printstate("final 1st key xor", &s); + P12(&s); + s.x[3] ^= K0; + s.x[4] ^= K1; + printstate("final 2nd key xor", &s); + + /* get tag */ + uint8_t t[16]; + STOREBYTES(t, s.x[3], 8); + STOREBYTES(t + 8, s.x[4], 8); + + /* verify should be constant time, check compiler output */ + int i; + int result = 0; + for (i = 0; i < CRYPTO_ABYTES; ++i) result |= c[i] ^ t[i]; + result = (((result - 1) >> 8) & 1) - 1; + + return result; +} diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/api.h b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/api.h new file mode 100644 index 0000000000..927d81ccc6 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/api.h @@ -0,0 +1,7 @@ +#define CRYPTO_VERSION "1.2.7" +#define CRYPTO_KEYBYTES 16 +#define CRYPTO_NSECBYTES 0 +#define CRYPTO_NPUBBYTES 16 +#define CRYPTO_ABYTES 16 +#define CRYPTO_NOOVERLAP 1 +#define ASCON_AEAD_RATE 8 diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/ascon.h b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/ascon.h new file mode 100644 index 0000000000..2350004099 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/ascon.h @@ -0,0 +1,10 @@ +#ifndef ASCON_H_ +#define ASCON_H_ + +#include + +typedef struct { + uint64_t x[5]; +} ascon_state_t; + +#endif /* ASCON_H_ */ diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/constants.h b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/constants.h new file mode 100644 index 0000000000..b4e20d48fa --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/constants.h @@ -0,0 +1,103 @@ +#ifndef CONSTANTS_H_ +#define CONSTANTS_H_ + +#include + +#define ASCON_128_KEYBYTES 16 +#define ASCON_128A_KEYBYTES 16 +#define ASCON_80PQ_KEYBYTES 20 + +#define ASCON_128_RATE 8 +#define ASCON_128A_RATE 16 +#define ASCON_HASH_RATE 8 +#define ASCON_PRF_IN_RATE 32 +#define ASCON_PRFA_IN_RATE 40 +#define ASCON_PRF_OUT_RATE 16 + +#define ASCON_128_PA_ROUNDS 12 +#define ASCON_128_PB_ROUNDS 6 +#define ASCON_128A_PA_ROUNDS 12 +#define ASCON_128A_PB_ROUNDS 8 + +#define ASCON_HASH_PA_ROUNDS 12 +#define ASCON_HASH_PB_ROUNDS 12 +#define ASCON_HASHA_PA_ROUNDS 12 +#define ASCON_HASHA_PB_ROUNDS 8 + +#define ASCON_PRF_PA_ROUNDS 12 +#define ASCON_PRF_PB_ROUNDS 12 +#define ASCON_PRFA_PA_ROUNDS 12 +#define ASCON_PRFA_PB_ROUNDS 8 + +#define ASCON_128_IV \ + (((uint64_t)(ASCON_128_KEYBYTES * 8) << 56) | \ + ((uint64_t)(ASCON_128_RATE * 8) << 48) | \ + ((uint64_t)(ASCON_128_PA_ROUNDS) << 40) | \ + ((uint64_t)(ASCON_128_PB_ROUNDS) << 32)) + +#define ASCON_128A_IV \ + (((uint64_t)(ASCON_128A_KEYBYTES * 8) << 56) | \ + ((uint64_t)(ASCON_128A_RATE * 8) << 48) | \ + ((uint64_t)(ASCON_128A_PA_ROUNDS) << 40) | \ + ((uint64_t)(ASCON_128A_PB_ROUNDS) << 32)) + +#define ASCON_80PQ_IV \ + (((uint64_t)(ASCON_80PQ_KEYBYTES * 8) << 56) | \ + ((uint64_t)(ASCON_128_RATE * 8) << 48) | \ + ((uint64_t)(ASCON_128_PA_ROUNDS) << 40) | \ + ((uint64_t)(ASCON_128_PB_ROUNDS) << 32)) + +#define ASCON_HASH_IV \ + (((uint64_t)(ASCON_HASH_RATE * 8) << 48) | \ + ((uint64_t)(ASCON_HASH_PA_ROUNDS) << 40) | \ + ((uint64_t)(ASCON_HASH_PA_ROUNDS - ASCON_HASH_PB_ROUNDS) << 32) | \ + ((uint64_t)(ASCON_HASH_BYTES * 8) << 0)) + +#define ASCON_HASHA_IV \ + (((uint64_t)(ASCON_HASH_RATE * 8) << 48) | \ + ((uint64_t)(ASCON_HASHA_PA_ROUNDS) << 40) | \ + ((uint64_t)(ASCON_HASHA_PA_ROUNDS - ASCON_HASHA_PB_ROUNDS) << 32) | \ + ((uint64_t)(ASCON_HASH_BYTES * 8) << 0)) + +#define ASCON_XOF_IV \ + (((uint64_t)(ASCON_HASH_RATE * 8) << 48) | \ + ((uint64_t)(ASCON_HASH_PA_ROUNDS) << 40) | \ + ((uint64_t)(ASCON_HASH_PA_ROUNDS - ASCON_HASH_PB_ROUNDS) << 32)) + +#define ASCON_XOFA_IV \ + (((uint64_t)(ASCON_HASH_RATE * 8) << 48) | \ + ((uint64_t)(ASCON_HASHA_PA_ROUNDS) << 40) | \ + ((uint64_t)(ASCON_HASHA_PA_ROUNDS - ASCON_HASHA_PB_ROUNDS) << 32)) + +#define ASCON_MAC_IV \ + (((uint64_t)(CRYPTO_KEYBYTES * 8) << 56) | \ + ((uint64_t)(ASCON_PRF_OUT_RATE * 8) << 48) | \ + ((uint64_t)(0x80 | ASCON_PRF_PA_ROUNDS) << 40) | \ + ((uint64_t)(ASCON_PRF_PA_ROUNDS - ASCON_PRF_PB_ROUNDS) << 32) | \ + ((uint64_t)(ASCON_PRF_BYTES * 8) << 0)) + +#define ASCON_MACA_IV \ + (((uint64_t)(CRYPTO_KEYBYTES * 8) << 56) | \ + ((uint64_t)(ASCON_PRF_OUT_RATE * 8) << 48) | \ + ((uint64_t)(0x80 | ASCON_PRFA_PA_ROUNDS) << 40) | \ + ((uint64_t)(ASCON_PRFA_PA_ROUNDS - ASCON_PRFA_PB_ROUNDS) << 32) | \ + ((uint64_t)(ASCON_PRF_BYTES * 8) << 0)) + +#define ASCON_PRF_IV \ + (((uint64_t)(CRYPTO_KEYBYTES * 8) << 56) | \ + ((uint64_t)(ASCON_PRF_OUT_RATE * 8) << 48) | \ + ((uint64_t)(0x80 | ASCON_PRF_PA_ROUNDS) << 40) | \ + ((uint64_t)(ASCON_PRF_PA_ROUNDS - ASCON_PRF_PB_ROUNDS) << 32)) + +#define ASCON_PRFA_IV \ + (((uint64_t)(CRYPTO_KEYBYTES * 8) << 56) | \ + ((uint64_t)(ASCON_PRF_OUT_RATE * 8) << 48) | \ + ((uint64_t)(0x80 | ASCON_PRFA_PA_ROUNDS) << 40) | \ + ((uint64_t)(ASCON_PRFA_PA_ROUNDS - ASCON_PRFA_PB_ROUNDS) << 32)) + +#define ASCON_PRFS_IV \ + (((uint64_t)(CRYPTO_KEYBYTES * 8) << 56) | \ + ((uint64_t)(0x40 | ASCON_PRF_PA_ROUNDS) << 40) | \ + ((uint64_t)(ASCON_PRF_BYTES * 8) << 32)) + +#endif /* CONSTANTS_H_ */ diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/crypto_aead.h b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/crypto_aead.h new file mode 100644 index 0000000000..21196782fe --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/crypto_aead.h @@ -0,0 +1,11 @@ +int crypto_aead_encrypt(unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, const unsigned char *npub, + const unsigned char *k); + +int crypto_aead_decrypt(unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, const unsigned char *c, + unsigned long long clen, const unsigned char *ad, + unsigned long long adlen, const unsigned char *npub, + const unsigned char *k); diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/permutations.h b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/permutations.h new file mode 100644 index 0000000000..02f1bcd565 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/permutations.h @@ -0,0 +1,46 @@ +#ifndef PERMUTATIONS_H_ +#define PERMUTATIONS_H_ + +#include + +#include "ascon.h" +#include "constants.h" +#include "printstate.h" +#include "round.h" + +static inline void P12(ascon_state_t* s) { + ROUND(s, 0xf0); + ROUND(s, 0xe1); + ROUND(s, 0xd2); + ROUND(s, 0xc3); + ROUND(s, 0xb4); + ROUND(s, 0xa5); + ROUND(s, 0x96); + ROUND(s, 0x87); + ROUND(s, 0x78); + ROUND(s, 0x69); + ROUND(s, 0x5a); + ROUND(s, 0x4b); +} + +static inline void P8(ascon_state_t* s) { + ROUND(s, 0xb4); + ROUND(s, 0xa5); + ROUND(s, 0x96); + ROUND(s, 0x87); + ROUND(s, 0x78); + ROUND(s, 0x69); + ROUND(s, 0x5a); + ROUND(s, 0x4b); +} + +static inline void P6(ascon_state_t* s) { + ROUND(s, 0x96); + ROUND(s, 0x87); + ROUND(s, 0x78); + ROUND(s, 0x69); + ROUND(s, 0x5a); + ROUND(s, 0x4b); +} + +#endif /* PERMUTATIONS_H_ */ diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/printstate.c b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/printstate.c new file mode 100644 index 0000000000..5e146ed236 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/printstate.c @@ -0,0 +1,33 @@ +#ifdef ASCON_PRINT_STATE + +#include "printstate.h" + +#include +#include +#include + +#ifndef WORDTOU64 +#define WORDTOU64 +#endif + +#ifndef U64BIG +#define U64BIG +#endif + +void printword(const char* text, const uint64_t x) { + printf("%s=%016" PRIx64, text, U64BIG(WORDTOU64(x))); +} + +void printstate(const char* text, const ascon_state_t* s) { + int i; + printf("%s:", text); + for (i = strlen(text); i < 17; ++i) printf(" "); + printword(" x0", s->x[0]); + printword(" x1", s->x[1]); + printword(" x2", s->x[2]); + printword(" x3", s->x[3]); + printword(" x4", s->x[4]); + printf("\n"); +} + +#endif diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/printstate.h b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/printstate.h new file mode 100644 index 0000000000..40b1f9ceda --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/printstate.h @@ -0,0 +1,24 @@ +#ifndef PRINTSTATE_H_ +#define PRINTSTATE_H_ + +#ifdef ASCON_PRINT_STATE + +#include "ascon.h" +#include "word.h" + +void printword(const char* text, const uint64_t x); +void printstate(const char* text, const ascon_state_t* s); + +#else + +#define printword(text, w) \ + do { \ + } while (0) + +#define printstate(text, s) \ + do { \ + } while (0) + +#endif + +#endif /* PRINTSTATE_H_ */ diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/round.h b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/round.h new file mode 100644 index 0000000000..a3ef5bfcd0 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/round.h @@ -0,0 +1,42 @@ +#ifndef ROUND_H_ +#define ROUND_H_ + +#include "ascon.h" +#include "constants.h" +#include "printstate.h" + +static inline uint64_t ROR(uint64_t x, int n) { + return x >> n | x << (-n & 63); +} + +static inline void ROUND(ascon_state_t* s, uint8_t C) { + ascon_state_t t; + /* addition of round constant */ + s->x[2] ^= C; + /* printstate(" round constant", s); */ + /* substitution layer */ + s->x[0] ^= s->x[4]; + s->x[4] ^= s->x[3]; + s->x[2] ^= s->x[1]; + /* start of keccak s-box */ + t.x[0] = s->x[0] ^ (~s->x[1] & s->x[2]); + t.x[1] = s->x[1] ^ (~s->x[2] & s->x[3]); + t.x[2] = s->x[2] ^ (~s->x[3] & s->x[4]); + t.x[3] = s->x[3] ^ (~s->x[4] & s->x[0]); + t.x[4] = s->x[4] ^ (~s->x[0] & s->x[1]); + /* end of keccak s-box */ + t.x[1] ^= t.x[0]; + t.x[0] ^= t.x[4]; + t.x[3] ^= t.x[2]; + t.x[2] = ~t.x[2]; + /* printstate(" substitution layer", &t); */ + /* linear diffusion layer */ + s->x[0] = t.x[0] ^ ROR(t.x[0], 19) ^ ROR(t.x[0], 28); + s->x[1] = t.x[1] ^ ROR(t.x[1], 61) ^ ROR(t.x[1], 39); + s->x[2] = t.x[2] ^ ROR(t.x[2], 1) ^ ROR(t.x[2], 6); + s->x[3] = t.x[3] ^ ROR(t.x[3], 10) ^ ROR(t.x[3], 17); + s->x[4] = t.x[4] ^ ROR(t.x[4], 7) ^ ROR(t.x[4], 41); + printstate(" round output", s); +} + +#endif /* ROUND_H_ */ diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/word.h b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/word.h new file mode 100644 index 0000000000..0929b85d86 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128/word.h @@ -0,0 +1,39 @@ +#ifndef WORD_H_ +#define WORD_H_ + +#include + +/* get byte from 64-bit Ascon word */ +#define GETBYTE(x, i) ((uint8_t)((uint64_t)(x) >> (56 - 8 * (i)))) + +/* set byte in 64-bit Ascon word */ +#define SETBYTE(b, i) ((uint64_t)(b) << (56 - 8 * (i))) + +/* set padding byte in 64-bit Ascon word */ +#define PAD(i) SETBYTE(0x80, i) + +/* define domain separation bit in 64-bit Ascon word */ +#define DSEP() SETBYTE(0x01, 7) + +/* load bytes into 64-bit Ascon word */ +static inline uint64_t LOADBYTES(const uint8_t* bytes, int n) { + int i; + uint64_t x = 0; + for (i = 0; i < n; ++i) x |= SETBYTE(bytes[i], i); + return x; +} + +/* store bytes from 64-bit Ascon word */ +static inline void STOREBYTES(uint8_t* bytes, uint64_t x, int n) { + int i; + for (i = 0; i < n; ++i) bytes[i] = GETBYTE(x, i); +} + +/* clear bytes in 64-bit Ascon word */ +static inline uint64_t CLEARBYTES(uint64_t x, int n) { + int i; + for (i = 0; i < n; ++i) x &= ~SETBYTE(0xff, i); + return x; +} + +#endif /* WORD_H_ */ diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/aead.c b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/aead.c new file mode 100644 index 0000000000..2a03ee16fa --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/aead.c @@ -0,0 +1,219 @@ +#include "api.h" +#include "ascon.h" +#include "crypto_aead.h" +#include "permutations.h" +#include "printstate.h" +#include "word.h" + +int crypto_aead_encrypt(unsigned char* c, unsigned long long* clen, + const unsigned char* m, unsigned long long mlen, + const unsigned char* ad, unsigned long long adlen, + const unsigned char* nsec, const unsigned char* npub, + const unsigned char* k) { + (void)nsec; + + /* set ciphertext size */ + *clen = mlen + CRYPTO_ABYTES; + + /* load key and nonce */ + const uint64_t K0 = LOADBYTES(k, 8); + const uint64_t K1 = LOADBYTES(k + 8, 8); + const uint64_t N0 = LOADBYTES(npub, 8); + const uint64_t N1 = LOADBYTES(npub + 8, 8); + + /* initialize */ + ascon_state_t s; + s.x[0] = ASCON_128A_IV; + s.x[1] = K0; + s.x[2] = K1; + s.x[3] = N0; + s.x[4] = N1; + printstate("init 1st key xor", &s); + P12(&s); + s.x[3] ^= K0; + s.x[4] ^= K1; + printstate("init 2nd key xor", &s); + + if (adlen) { + /* full associated data blocks */ + while (adlen >= ASCON_128A_RATE) { + s.x[0] ^= LOADBYTES(ad, 8); + s.x[1] ^= LOADBYTES(ad + 8, 8); + printstate("absorb adata", &s); + P8(&s); + ad += ASCON_128A_RATE; + adlen -= ASCON_128A_RATE; + } + /* final associated data block */ + if (adlen >= 8) { + s.x[0] ^= LOADBYTES(ad, 8); + s.x[1] ^= LOADBYTES(ad + 8, adlen - 8); + s.x[1] ^= PAD(adlen - 8); + } else { + s.x[0] ^= LOADBYTES(ad, adlen); + s.x[0] ^= PAD(adlen); + } + printstate("pad adata", &s); + P8(&s); + } + /* domain separation */ + s.x[4] ^= DSEP(); + printstate("domain separation", &s); + + /* full plaintext blocks */ + while (mlen >= ASCON_128A_RATE) { + s.x[0] ^= LOADBYTES(m, 8); + s.x[1] ^= LOADBYTES(m + 8, 8); + STOREBYTES(c, s.x[0], 8); + STOREBYTES(c + 8, s.x[1], 8); + printstate("absorb plaintext", &s); + P8(&s); + m += ASCON_128A_RATE; + c += ASCON_128A_RATE; + mlen -= ASCON_128A_RATE; + } + /* final plaintext block */ + if (mlen >= 8) { + s.x[0] ^= LOADBYTES(m, 8); + s.x[1] ^= LOADBYTES(m + 8, mlen - 8); + STOREBYTES(c, s.x[0], 8); + STOREBYTES(c + 8, s.x[1], mlen - 8); + s.x[1] ^= PAD(mlen - 8); + } else { + s.x[0] ^= LOADBYTES(m, mlen); + STOREBYTES(c, s.x[0], mlen); + s.x[0] ^= PAD(mlen); + } + c += mlen; + printstate("pad plaintext", &s); + + /* finalize */ + s.x[2] ^= K0; + s.x[3] ^= K1; + printstate("final 1st key xor", &s); + P12(&s); + s.x[3] ^= K0; + s.x[4] ^= K1; + printstate("final 2nd key xor", &s); + + /* get tag */ + STOREBYTES(c, s.x[3], 8); + STOREBYTES(c + 8, s.x[4], 8); + + return 0; +} + +int crypto_aead_decrypt(unsigned char* m, unsigned long long* mlen, + unsigned char* nsec, const unsigned char* c, + unsigned long long clen, const unsigned char* ad, + unsigned long long adlen, const unsigned char* npub, + const unsigned char* k) { + (void)nsec; + + if (clen < CRYPTO_ABYTES) return -1; + + /* set plaintext size */ + *mlen = clen - CRYPTO_ABYTES; + + /* load key and nonce */ + const uint64_t K0 = LOADBYTES(k, 8); + const uint64_t K1 = LOADBYTES(k + 8, 8); + const uint64_t N0 = LOADBYTES(npub, 8); + const uint64_t N1 = LOADBYTES(npub + 8, 8); + + /* initialize */ + ascon_state_t s; + s.x[0] = ASCON_128A_IV; + s.x[1] = K0; + s.x[2] = K1; + s.x[3] = N0; + s.x[4] = N1; + printstate("init 1st key xor", &s); + P12(&s); + s.x[3] ^= K0; + s.x[4] ^= K1; + printstate("init 2nd key xor", &s); + + if (adlen) { + /* full associated data blocks */ + while (adlen >= ASCON_128A_RATE) { + s.x[0] ^= LOADBYTES(ad, 8); + s.x[1] ^= LOADBYTES(ad + 8, 8); + printstate("absorb adata", &s); + P8(&s); + ad += ASCON_128A_RATE; + adlen -= ASCON_128A_RATE; + } + /* final associated data block */ + if (adlen >= 8) { + s.x[0] ^= LOADBYTES(ad, 8); + s.x[1] ^= LOADBYTES(ad + 8, adlen - 8); + s.x[1] ^= PAD(adlen - 8); + } else { + s.x[0] ^= LOADBYTES(ad, adlen); + s.x[0] ^= PAD(adlen); + } + printstate("pad adata", &s); + P8(&s); + } + /* domain separation */ + s.x[4] ^= DSEP(); + printstate("domain separation", &s); + + /* full ciphertext blocks */ + clen -= CRYPTO_ABYTES; + while (clen >= ASCON_128A_RATE) { + uint64_t c0 = LOADBYTES(c, 8); + uint64_t c1 = LOADBYTES(c + 8, 8); + STOREBYTES(m, s.x[0] ^ c0, 8); + STOREBYTES(m + 8, s.x[1] ^ c1, 8); + s.x[0] = c0; + s.x[1] = c1; + printstate("insert ciphertext", &s); + P8(&s); + m += ASCON_128A_RATE; + c += ASCON_128A_RATE; + clen -= ASCON_128A_RATE; + } + /* final ciphertext block */ + if (clen >= 8) { + uint64_t c0 = LOADBYTES(c, 8); + uint64_t c1 = LOADBYTES(c + 8, clen - 8); + STOREBYTES(m, s.x[0] ^ c0, 8); + STOREBYTES(m + 8, s.x[1] ^ c1, clen - 8); + s.x[0] = c0; + s.x[1] = CLEARBYTES(s.x[1], clen - 8); + s.x[1] |= c1; + s.x[1] ^= PAD(clen - 8); + } else { + uint64_t c0 = LOADBYTES(c, clen); + STOREBYTES(m, s.x[0] ^ c0, clen); + s.x[0] = CLEARBYTES(s.x[0], clen); + s.x[0] |= c0; + s.x[0] ^= PAD(clen); + } + c += clen; + printstate("pad ciphertext", &s); + + /* finalize */ + s.x[2] ^= K0; + s.x[3] ^= K1; + printstate("final 1st key xor", &s); + P12(&s); + s.x[3] ^= K0; + s.x[4] ^= K1; + printstate("final 2nd key xor", &s); + + /* get tag */ + uint8_t t[16]; + STOREBYTES(t, s.x[3], 8); + STOREBYTES(t + 8, s.x[4], 8); + + /* verify should be constant time, check compiler output */ + int i; + int result = 0; + for (i = 0; i < CRYPTO_ABYTES; ++i) result |= c[i] ^ t[i]; + result = (((result - 1) >> 8) & 1) - 1; + + return result; +} diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/api.h b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/api.h new file mode 100644 index 0000000000..c5ef5845ed --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/api.h @@ -0,0 +1,7 @@ +#define CRYPTO_VERSION "1.2.7" +#define CRYPTO_KEYBYTES 16 +#define CRYPTO_NSECBYTES 0 +#define CRYPTO_NPUBBYTES 16 +#define CRYPTO_ABYTES 16 +#define CRYPTO_NOOVERLAP 1 +#define ASCON_AEAD_RATE 16 diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/ascon.h b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/ascon.h new file mode 100644 index 0000000000..2350004099 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/ascon.h @@ -0,0 +1,10 @@ +#ifndef ASCON_H_ +#define ASCON_H_ + +#include + +typedef struct { + uint64_t x[5]; +} ascon_state_t; + +#endif /* ASCON_H_ */ diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/constants.h b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/constants.h new file mode 100644 index 0000000000..b4e20d48fa --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/constants.h @@ -0,0 +1,103 @@ +#ifndef CONSTANTS_H_ +#define CONSTANTS_H_ + +#include + +#define ASCON_128_KEYBYTES 16 +#define ASCON_128A_KEYBYTES 16 +#define ASCON_80PQ_KEYBYTES 20 + +#define ASCON_128_RATE 8 +#define ASCON_128A_RATE 16 +#define ASCON_HASH_RATE 8 +#define ASCON_PRF_IN_RATE 32 +#define ASCON_PRFA_IN_RATE 40 +#define ASCON_PRF_OUT_RATE 16 + +#define ASCON_128_PA_ROUNDS 12 +#define ASCON_128_PB_ROUNDS 6 +#define ASCON_128A_PA_ROUNDS 12 +#define ASCON_128A_PB_ROUNDS 8 + +#define ASCON_HASH_PA_ROUNDS 12 +#define ASCON_HASH_PB_ROUNDS 12 +#define ASCON_HASHA_PA_ROUNDS 12 +#define ASCON_HASHA_PB_ROUNDS 8 + +#define ASCON_PRF_PA_ROUNDS 12 +#define ASCON_PRF_PB_ROUNDS 12 +#define ASCON_PRFA_PA_ROUNDS 12 +#define ASCON_PRFA_PB_ROUNDS 8 + +#define ASCON_128_IV \ + (((uint64_t)(ASCON_128_KEYBYTES * 8) << 56) | \ + ((uint64_t)(ASCON_128_RATE * 8) << 48) | \ + ((uint64_t)(ASCON_128_PA_ROUNDS) << 40) | \ + ((uint64_t)(ASCON_128_PB_ROUNDS) << 32)) + +#define ASCON_128A_IV \ + (((uint64_t)(ASCON_128A_KEYBYTES * 8) << 56) | \ + ((uint64_t)(ASCON_128A_RATE * 8) << 48) | \ + ((uint64_t)(ASCON_128A_PA_ROUNDS) << 40) | \ + ((uint64_t)(ASCON_128A_PB_ROUNDS) << 32)) + +#define ASCON_80PQ_IV \ + (((uint64_t)(ASCON_80PQ_KEYBYTES * 8) << 56) | \ + ((uint64_t)(ASCON_128_RATE * 8) << 48) | \ + ((uint64_t)(ASCON_128_PA_ROUNDS) << 40) | \ + ((uint64_t)(ASCON_128_PB_ROUNDS) << 32)) + +#define ASCON_HASH_IV \ + (((uint64_t)(ASCON_HASH_RATE * 8) << 48) | \ + ((uint64_t)(ASCON_HASH_PA_ROUNDS) << 40) | \ + ((uint64_t)(ASCON_HASH_PA_ROUNDS - ASCON_HASH_PB_ROUNDS) << 32) | \ + ((uint64_t)(ASCON_HASH_BYTES * 8) << 0)) + +#define ASCON_HASHA_IV \ + (((uint64_t)(ASCON_HASH_RATE * 8) << 48) | \ + ((uint64_t)(ASCON_HASHA_PA_ROUNDS) << 40) | \ + ((uint64_t)(ASCON_HASHA_PA_ROUNDS - ASCON_HASHA_PB_ROUNDS) << 32) | \ + ((uint64_t)(ASCON_HASH_BYTES * 8) << 0)) + +#define ASCON_XOF_IV \ + (((uint64_t)(ASCON_HASH_RATE * 8) << 48) | \ + ((uint64_t)(ASCON_HASH_PA_ROUNDS) << 40) | \ + ((uint64_t)(ASCON_HASH_PA_ROUNDS - ASCON_HASH_PB_ROUNDS) << 32)) + +#define ASCON_XOFA_IV \ + (((uint64_t)(ASCON_HASH_RATE * 8) << 48) | \ + ((uint64_t)(ASCON_HASHA_PA_ROUNDS) << 40) | \ + ((uint64_t)(ASCON_HASHA_PA_ROUNDS - ASCON_HASHA_PB_ROUNDS) << 32)) + +#define ASCON_MAC_IV \ + (((uint64_t)(CRYPTO_KEYBYTES * 8) << 56) | \ + ((uint64_t)(ASCON_PRF_OUT_RATE * 8) << 48) | \ + ((uint64_t)(0x80 | ASCON_PRF_PA_ROUNDS) << 40) | \ + ((uint64_t)(ASCON_PRF_PA_ROUNDS - ASCON_PRF_PB_ROUNDS) << 32) | \ + ((uint64_t)(ASCON_PRF_BYTES * 8) << 0)) + +#define ASCON_MACA_IV \ + (((uint64_t)(CRYPTO_KEYBYTES * 8) << 56) | \ + ((uint64_t)(ASCON_PRF_OUT_RATE * 8) << 48) | \ + ((uint64_t)(0x80 | ASCON_PRFA_PA_ROUNDS) << 40) | \ + ((uint64_t)(ASCON_PRFA_PA_ROUNDS - ASCON_PRFA_PB_ROUNDS) << 32) | \ + ((uint64_t)(ASCON_PRF_BYTES * 8) << 0)) + +#define ASCON_PRF_IV \ + (((uint64_t)(CRYPTO_KEYBYTES * 8) << 56) | \ + ((uint64_t)(ASCON_PRF_OUT_RATE * 8) << 48) | \ + ((uint64_t)(0x80 | ASCON_PRF_PA_ROUNDS) << 40) | \ + ((uint64_t)(ASCON_PRF_PA_ROUNDS - ASCON_PRF_PB_ROUNDS) << 32)) + +#define ASCON_PRFA_IV \ + (((uint64_t)(CRYPTO_KEYBYTES * 8) << 56) | \ + ((uint64_t)(ASCON_PRF_OUT_RATE * 8) << 48) | \ + ((uint64_t)(0x80 | ASCON_PRFA_PA_ROUNDS) << 40) | \ + ((uint64_t)(ASCON_PRFA_PA_ROUNDS - ASCON_PRFA_PB_ROUNDS) << 32)) + +#define ASCON_PRFS_IV \ + (((uint64_t)(CRYPTO_KEYBYTES * 8) << 56) | \ + ((uint64_t)(0x40 | ASCON_PRF_PA_ROUNDS) << 40) | \ + ((uint64_t)(ASCON_PRF_BYTES * 8) << 32)) + +#endif /* CONSTANTS_H_ */ diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/crypto_aead.h b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/crypto_aead.h new file mode 100644 index 0000000000..21196782fe --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/crypto_aead.h @@ -0,0 +1,11 @@ +int crypto_aead_encrypt(unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, const unsigned char *npub, + const unsigned char *k); + +int crypto_aead_decrypt(unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, const unsigned char *c, + unsigned long long clen, const unsigned char *ad, + unsigned long long adlen, const unsigned char *npub, + const unsigned char *k); diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/permutations.h b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/permutations.h new file mode 100644 index 0000000000..02f1bcd565 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/permutations.h @@ -0,0 +1,46 @@ +#ifndef PERMUTATIONS_H_ +#define PERMUTATIONS_H_ + +#include + +#include "ascon.h" +#include "constants.h" +#include "printstate.h" +#include "round.h" + +static inline void P12(ascon_state_t* s) { + ROUND(s, 0xf0); + ROUND(s, 0xe1); + ROUND(s, 0xd2); + ROUND(s, 0xc3); + ROUND(s, 0xb4); + ROUND(s, 0xa5); + ROUND(s, 0x96); + ROUND(s, 0x87); + ROUND(s, 0x78); + ROUND(s, 0x69); + ROUND(s, 0x5a); + ROUND(s, 0x4b); +} + +static inline void P8(ascon_state_t* s) { + ROUND(s, 0xb4); + ROUND(s, 0xa5); + ROUND(s, 0x96); + ROUND(s, 0x87); + ROUND(s, 0x78); + ROUND(s, 0x69); + ROUND(s, 0x5a); + ROUND(s, 0x4b); +} + +static inline void P6(ascon_state_t* s) { + ROUND(s, 0x96); + ROUND(s, 0x87); + ROUND(s, 0x78); + ROUND(s, 0x69); + ROUND(s, 0x5a); + ROUND(s, 0x4b); +} + +#endif /* PERMUTATIONS_H_ */ diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/printstate.c b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/printstate.c new file mode 100644 index 0000000000..5e146ed236 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/printstate.c @@ -0,0 +1,33 @@ +#ifdef ASCON_PRINT_STATE + +#include "printstate.h" + +#include +#include +#include + +#ifndef WORDTOU64 +#define WORDTOU64 +#endif + +#ifndef U64BIG +#define U64BIG +#endif + +void printword(const char* text, const uint64_t x) { + printf("%s=%016" PRIx64, text, U64BIG(WORDTOU64(x))); +} + +void printstate(const char* text, const ascon_state_t* s) { + int i; + printf("%s:", text); + for (i = strlen(text); i < 17; ++i) printf(" "); + printword(" x0", s->x[0]); + printword(" x1", s->x[1]); + printword(" x2", s->x[2]); + printword(" x3", s->x[3]); + printword(" x4", s->x[4]); + printf("\n"); +} + +#endif diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/printstate.h b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/printstate.h new file mode 100644 index 0000000000..40b1f9ceda --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/printstate.h @@ -0,0 +1,24 @@ +#ifndef PRINTSTATE_H_ +#define PRINTSTATE_H_ + +#ifdef ASCON_PRINT_STATE + +#include "ascon.h" +#include "word.h" + +void printword(const char* text, const uint64_t x); +void printstate(const char* text, const ascon_state_t* s); + +#else + +#define printword(text, w) \ + do { \ + } while (0) + +#define printstate(text, s) \ + do { \ + } while (0) + +#endif + +#endif /* PRINTSTATE_H_ */ diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/round.h b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/round.h new file mode 100644 index 0000000000..a3ef5bfcd0 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/round.h @@ -0,0 +1,42 @@ +#ifndef ROUND_H_ +#define ROUND_H_ + +#include "ascon.h" +#include "constants.h" +#include "printstate.h" + +static inline uint64_t ROR(uint64_t x, int n) { + return x >> n | x << (-n & 63); +} + +static inline void ROUND(ascon_state_t* s, uint8_t C) { + ascon_state_t t; + /* addition of round constant */ + s->x[2] ^= C; + /* printstate(" round constant", s); */ + /* substitution layer */ + s->x[0] ^= s->x[4]; + s->x[4] ^= s->x[3]; + s->x[2] ^= s->x[1]; + /* start of keccak s-box */ + t.x[0] = s->x[0] ^ (~s->x[1] & s->x[2]); + t.x[1] = s->x[1] ^ (~s->x[2] & s->x[3]); + t.x[2] = s->x[2] ^ (~s->x[3] & s->x[4]); + t.x[3] = s->x[3] ^ (~s->x[4] & s->x[0]); + t.x[4] = s->x[4] ^ (~s->x[0] & s->x[1]); + /* end of keccak s-box */ + t.x[1] ^= t.x[0]; + t.x[0] ^= t.x[4]; + t.x[3] ^= t.x[2]; + t.x[2] = ~t.x[2]; + /* printstate(" substitution layer", &t); */ + /* linear diffusion layer */ + s->x[0] = t.x[0] ^ ROR(t.x[0], 19) ^ ROR(t.x[0], 28); + s->x[1] = t.x[1] ^ ROR(t.x[1], 61) ^ ROR(t.x[1], 39); + s->x[2] = t.x[2] ^ ROR(t.x[2], 1) ^ ROR(t.x[2], 6); + s->x[3] = t.x[3] ^ ROR(t.x[3], 10) ^ ROR(t.x[3], 17); + s->x[4] = t.x[4] ^ ROR(t.x[4], 7) ^ ROR(t.x[4], 41); + printstate(" round output", s); +} + +#endif /* ROUND_H_ */ diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/word.h b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/word.h new file mode 100644 index 0000000000..0929b85d86 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_ascon/ascon_model_dpi/vendor/ascon_ascon-c/ascon128a/word.h @@ -0,0 +1,39 @@ +#ifndef WORD_H_ +#define WORD_H_ + +#include + +/* get byte from 64-bit Ascon word */ +#define GETBYTE(x, i) ((uint8_t)((uint64_t)(x) >> (56 - 8 * (i)))) + +/* set byte in 64-bit Ascon word */ +#define SETBYTE(b, i) ((uint64_t)(b) << (56 - 8 * (i))) + +/* set padding byte in 64-bit Ascon word */ +#define PAD(i) SETBYTE(0x80, i) + +/* define domain separation bit in 64-bit Ascon word */ +#define DSEP() SETBYTE(0x01, 7) + +/* load bytes into 64-bit Ascon word */ +static inline uint64_t LOADBYTES(const uint8_t* bytes, int n) { + int i; + uint64_t x = 0; + for (i = 0; i < n; ++i) x |= SETBYTE(bytes[i], i); + return x; +} + +/* store bytes from 64-bit Ascon word */ +static inline void STOREBYTES(uint8_t* bytes, uint64_t x, int n) { + int i; + for (i = 0; i < n; ++i) bytes[i] = GETBYTE(x, i); +} + +/* clear bytes in 64-bit Ascon word */ +static inline uint64_t CLEARBYTES(uint64_t x, int n) { + int i; + for (i = 0; i < n; ++i) x &= ~SETBYTE(0xff, i); + return x; +} + +#endif /* WORD_H_ */ diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_esc/data/prim_esc_testplan.hjson b/vendor/lowrisc_ip/ip/prim/dv/prim_esc/data/prim_esc_testplan.hjson index 29c3137f3a..887c1e334e 100644 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_esc/data/prim_esc_testplan.hjson +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_esc/data/prim_esc_testplan.hjson @@ -38,7 +38,7 @@ - Force `esc_n` signal to stay high to trigger an integrity error. - Verify that prim_esc_sender identifies the error by setting `integ_fail` signal. - Release the `esc_n` signal. - - Send a ping request and repeat the above sequence and checkings. + - Send a ping request and repeat the above sequence and checks. ''' stage: V1 tests: ["prim_esc_test"] diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_esc/tb/prim_esc_tb.sv b/vendor/lowrisc_ip/ip/prim/dv/prim_esc/tb/prim_esc_tb.sv index e3572df1dc..7cf3cf8cb8 100644 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_esc/tb/prim_esc_tb.sv +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_esc/tb/prim_esc_tb.sv @@ -4,7 +4,7 @@ // // Testbench module for prim_esc_sender and prim_esc_receiver_pair. // -// This test has five sequnces: +// This test has five sequences: // 1). Random reset during escalation handshake sequence. // 2). Escalation request sequence. // 3). Ping request interrupted by escalation request sequence. @@ -48,7 +48,9 @@ module prim_esc_tb; prim_esc_pkg::esc_tx_t esc_tx; prim_esc_pkg::esc_rx_t esc_rx; - prim_esc_sender i_esc_sender ( + prim_esc_sender # ( + .SkewCycles(1) + ) i_esc_sender ( .clk_i(clk), .rst_ni(rst_n), .ping_req_i(ping_req), @@ -62,7 +64,8 @@ module prim_esc_tb; prim_esc_receiver #( .N_ESC_SEV(4), // Set to 1 to avoid long wait period to check ping request reverse timeout. - .PING_CNT_DW(PING_CNT_DW) + .PING_CNT_DW(PING_CNT_DW), + .SkewCycles(1) ) i_esc_receiver ( .clk_i(clk), .rst_ni(rst_n), @@ -110,6 +113,8 @@ module prim_esc_tb; // Drive random length of esc_req and check `esc_req_out` and `integ_fail` outputs. main_clk.wait_clks($urandom_range(1, 20)); if (integ_fail) test_error("Esc_req unexpected signal integrity error!"); + // Wait for the escalation request to pass through the output register. + main_clk.wait_clks(1); if (!esc_req_out) test_error("Esc_req did not set esc_req!"); esc_req = 0; @@ -148,6 +153,8 @@ module prim_esc_tb; `DV_SPINWAIT(wait (integ_fail == 1);, , , "Wait for esc_tx.esc_n integ_fail timeout"); main_clk.wait_clks(1); release esc_tx.esc_n; + // Wait for the escalation request to pass through the output register. + main_clk.wait_clks(1); // Wait #1ps to avoid a race condition on clock edge. #1ps; if (!esc_req_out) test_error("Signal integrity error should set esc_req!"); @@ -161,6 +168,8 @@ module prim_esc_tb; `DV_SPINWAIT(wait (integ_fail == 1);, , , "Wait for esc_rx.resp_n integ_fail timeout"); main_clk.wait_clks(1); release esc_rx.resp_n; + // Wait for the escalation request to pass through the output register. + main_clk.wait_clks(1); // Wait #1ps to avoid a race condition on clock edge. #1ps; if (!esc_req_out) test_error("Signal integrity error should set esc_req!"); @@ -176,8 +185,12 @@ module prim_esc_tb; release esc_tx.esc_n; // Wait #1ps to avoid a race condition on clock edge. #1ps; - if (!esc_req_out) test_error("Signal integrity error should set esc_req!"); if (ping_ok) test_error("Ping error!"); + // Wait for the escalation request to pass through the output register. + main_clk.wait_clks(1); + // Wait #1ps to avoid a race condition on clock edge. + #1ps; + if (!esc_req_out) test_error("Signal integrity error should set esc_req!"); ping_req = 0; $display("[prim_esc_seq] Escalation esc_p/n integrity sequence during ping request finished!"); @@ -191,7 +204,7 @@ module prim_esc_tb; // After one ping_req, esc_receiver will start a counter to expect next ping_req. If the // counter reaches its max value but no ping_req has been received, design will set // `esc_req_out` signal. - main_clk.wait_clks(TIMEOUT_CYCLES + 1); + main_clk.wait_clks(TIMEOUT_CYCLES + 2); if (!esc_req_out) test_error("Design failed to detect ping request timeout!"); end begin @@ -200,6 +213,8 @@ module prim_esc_tb; main_clk.wait_clks(2); ping_req = 0; if (integ_fail) test_error("Ping_req unexpected signal integrity error!"); + // Wait for the escalation request to pass through the output register. + main_clk.wait_clks(1); if (esc_req_out) test_error("Ping request should not set esc_req_out!"); end join diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_tb.sv b/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_tb.sv index d7bcc79d8a..4a6d4ced4d 100644 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_tb.sv +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_tb.sv @@ -226,8 +226,8 @@ module prim_lfsr_tb; repeat ($urandom_range(5000, 10000)) begin // Do random reset sometimes if ($urandom_range(0, 10) == 0) main_clk.apply_reset(); - randomize(rand_seed); - randomize(rand_entropy); + `DV_CHECK_STD_RANDOMIZE_FATAL(rand_seed,, "prim_lfsr_tb") + `DV_CHECK_STD_RANDOMIZE_FATAL(rand_entropy,, "prim_lfsr_tb") seed[k] = rand_seed; entropy[k] = rand_entropy; lfsr_en[k] = $urandom_range(0, 1); diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_prince/crypto_dpi_prince/crypto_dpi_prince_sim_opts.hjson b/vendor/lowrisc_ip/ip/prim/dv/prim_prince/crypto_dpi_prince/crypto_dpi_prince_sim_opts.hjson index 9f2e9c6fd8..29a6550735 100644 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_prince/crypto_dpi_prince/crypto_dpi_prince_sim_opts.hjson +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_prince/crypto_dpi_prince/crypto_dpi_prince_sim_opts.hjson @@ -11,12 +11,12 @@ build_modes: [ { name: vcs_crypto_dpi_prince_build_opts - build_opts: ["-CFLAGS -I{build_dir}/src/{crypto_prince_ref_src_dir}"] + build_opts: ["-CFLAGS -I{build_dir}/fusesoc-work/src/{crypto_prince_ref_src_dir}"] } { name: xcelium_crypto_dpi_prince_build_opts - build_opts: ["-I{build_dir}/src/{crypto_prince_ref_src_dir}"] + build_opts: ["-I{build_dir}/fusesoc-work/src/{crypto_prince_ref_src_dir}"] } ] } 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 index 6a2bb7b3ad..53afb0b1ef 100644 --- 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 @@ -18,7 +18,7 @@ module prim_prince_tb; ////////////////////////////////////////////////////// // Default to {data_width:64, key_width:128} configuration. -// Data width and key width can be overriden from command-line if desired. +// Data width and key width can be overridden from command-line if desired. `ifdef DATA_WIDTH localparam int unsigned DataWidth = `DATA_WIDTH; 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 3a3254a07c..10fcd82f89 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 @@ -5,7 +5,7 @@ module prim_alert_rxtx_async_bind_fpv; - bind prim_alert_rxtx_async_fpv + bind prim_alert_rxtx_async_tb prim_alert_rxtx_async_assert_fpv prim_alert_rxtx_async_assert_fpv ( .clk_i, .rst_ni, diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_fatal_bind_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_fatal_bind_fpv.sv index 796496e83c..7f972350d9 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_fatal_bind_fpv.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_fatal_bind_fpv.sv @@ -5,7 +5,7 @@ module prim_alert_rxtx_async_fatal_bind_fpv; - bind prim_alert_rxtx_async_fpv + bind prim_alert_rxtx_async_tb prim_alert_rxtx_async_assert_fpv prim_alert_rxtx_async_assert_fpv ( .clk_i, .rst_ni, diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_fatal_tb.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_fatal_tb.sv index e0bf1f2c63..1eed99ff71 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_fatal_tb.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_fatal_tb.sv @@ -37,6 +37,8 @@ module prim_alert_rxtx_async_fatal_tb localparam bit AsyncOn = 1'b1; localparam bit IsFatal = 1'b1; + localparam int unsigned SkewCycles = 1; + logic ping_pd; logic ping_nd; logic ack_pd; @@ -71,8 +73,9 @@ module prim_alert_rxtx_async_fatal_tb assign alert_tx_in.alert_n = alert_nq[alert_skew_i[1]] ^ alert_err_ni; prim_alert_sender #( - .AsyncOn ( AsyncOn ), - .IsFatal ( IsFatal ) + .AsyncOn ( AsyncOn ), + .SkewCycles ( SkewCycles ), + .IsFatal ( IsFatal ) ) i_prim_alert_sender ( .clk_i, .rst_ni, @@ -85,7 +88,8 @@ module prim_alert_rxtx_async_fatal_tb ); prim_alert_receiver #( - .AsyncOn ( AsyncOn ) + .AsyncOn ( AsyncOn ), + .SkewCycles ( SkewCycles ) ) i_prim_alert_receiver ( .clk_i, .rst_ni, diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_tb.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_tb.sv index d36700eb64..cb2a9b030b 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_tb.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_tb.sv @@ -37,6 +37,8 @@ module prim_alert_rxtx_async_tb localparam bit AsyncOn = 1'b1; localparam bit IsFatal = 1'b0; + localparam int unsigned SkewCycles = 1; + logic ping_pd; logic ping_nd; logic ack_pd; @@ -71,8 +73,9 @@ module prim_alert_rxtx_async_tb assign alert_tx_in.alert_n = alert_nq[alert_skew_i[1]] ^ alert_err_ni; prim_alert_sender #( - .AsyncOn ( AsyncOn ), - .IsFatal ( IsFatal ) + .AsyncOn ( AsyncOn ), + .SkewCycles ( SkewCycles ), + .IsFatal ( IsFatal ) ) i_prim_alert_sender ( .clk_i, .rst_ni, @@ -85,7 +88,8 @@ module prim_alert_rxtx_async_tb ); prim_alert_receiver #( - .AsyncOn ( AsyncOn ) + .AsyncOn ( AsyncOn ), + .SkewCycles ( SkewCycles ) ) i_prim_alert_receiver ( .clk_i, .rst_ni, 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 696dddda1d..5cfc5c5f03 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 @@ -5,7 +5,7 @@ module prim_alert_rxtx_bind_fpv; - bind prim_alert_rxtx_fpv + bind prim_alert_rxtx_tb prim_alert_rxtx_assert_fpv prim_alert_rxtx_assert_fpv ( .clk_i, .rst_ni, diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_fatal_bind_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_fatal_bind_fpv.sv index 958325f646..7702ff9ac7 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_fatal_bind_fpv.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_fatal_bind_fpv.sv @@ -6,7 +6,7 @@ module prim_alert_rxtx_fatal_bind_fpv; // this reuses the synchronous VIP. - bind prim_alert_rxtx_fpv + bind prim_alert_rxtx_tb prim_alert_rxtx_assert_fpv prim_alert_rxtx_assert_fpv ( .clk_i, .rst_ni, diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_fatal_tb.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_fatal_tb.sv index 0e1b0eae9c..4d29652826 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_fatal_tb.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_fatal_tb.sv @@ -34,6 +34,8 @@ module prim_alert_rxtx_fatal_tb localparam bit AsyncOn = 1'b0; localparam bit IsFatal = 1'b1; + localparam int unsigned SkewCycles = 1; + alert_rx_t alert_rx_out, alert_rx_in; alert_tx_t alert_tx_out, alert_tx_in; @@ -46,8 +48,9 @@ module prim_alert_rxtx_fatal_tb assign alert_tx_in.alert_n = alert_tx_out.alert_n ^ alert_err_ni; prim_alert_sender #( - .AsyncOn ( AsyncOn ), - .IsFatal ( IsFatal ) + .AsyncOn ( AsyncOn ), + .SkewCycles ( SkewCycles ), + .IsFatal ( IsFatal ) ) i_prim_alert_sender ( .clk_i, .rst_ni, @@ -60,7 +63,8 @@ module prim_alert_rxtx_fatal_tb ); prim_alert_receiver #( - .AsyncOn ( AsyncOn ) + .AsyncOn ( AsyncOn ), + .SkewCycles ( SkewCycles ) ) i_prim_alert_receiver ( .clk_i, .rst_ni, diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_tb.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_tb.sv index a77f582954..e97f582bd9 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_tb.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_tb.sv @@ -34,6 +34,8 @@ module prim_alert_rxtx_tb localparam bit AsyncOn = 1'b0; localparam bit IsFatal = 1'b0; + localparam int unsigned SkewCycles = 1; + alert_rx_t alert_rx_out, alert_rx_in; alert_tx_t alert_tx_out, alert_tx_in; @@ -46,8 +48,9 @@ module prim_alert_rxtx_tb assign alert_tx_in.alert_n = alert_tx_out.alert_n ^ alert_err_ni; prim_alert_sender #( - .AsyncOn ( AsyncOn ), - .IsFatal ( IsFatal ) + .AsyncOn ( AsyncOn ), + .SkewCycles ( SkewCycles ), + .IsFatal ( IsFatal ) ) i_prim_alert_sender ( .clk_i, .rst_ni, 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 34468ec396..5df1e02048 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 @@ -5,8 +5,8 @@ module prim_esc_rxtx_bind_fpv; - bind prim_esc_rxtx_fpv - prim_esc_rxtx_assert_fpv #(TimeoutCntDw(TimeoutCntDw)) + bind prim_esc_rxtx_tb + prim_esc_rxtx_assert_fpv #(.TimeoutCntDw(6)) prim_esc_rxtx_assert_fpv ( .clk_i , .rst_ni , diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_esc_rxtx_tb.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_esc_rxtx_tb.sv index f7d77ce59d..708cdeca40 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_esc_rxtx_tb.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_esc_rxtx_tb.sv @@ -35,7 +35,9 @@ module prim_esc_rxtx_tb assign esc_tx_in.esc_p = esc_tx_out.esc_p ^ esc_err_pi; assign esc_tx_in.esc_n = esc_tx_out.esc_n ^ esc_err_ni; - prim_esc_sender u_prim_esc_sender ( + prim_esc_sender #( + .SkewCycles(1) + ) u_prim_esc_sender ( .clk_i , .rst_ni , .ping_req_i , @@ -47,7 +49,8 @@ module prim_esc_rxtx_tb ); prim_esc_receiver #( - .TimeoutCntDw(TimeoutCntDw) + .TimeoutCntDw(TimeoutCntDw), + .SkewCycles(1) ) u_prim_esc_receiver ( .clk_i , .rst_ni , diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_fifo_async_sram_adapter_tb.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_fifo_async_sram_adapter_tb.sv index 4faac74935..cb02d7f392 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_fifo_async_sram_adapter_tb.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_fifo_async_sram_adapter_tb.sv @@ -127,7 +127,8 @@ if (FpgaSram == 1) begin : g_sram_fpga .b_wmask_i (r_sram_wmask ), .b_rdata_o (r_sram_rdata ), - .cfg_i ('0) + .cfg_i ('0), + .cfg_rsp_o () ); end else begin : g_sram_ff logic [SramDw-1:0] mem [2**SramAw]; diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_fifo_sync_bind_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_fifo_sync_bind_fpv.sv index 895a9e280f..68e43a91f4 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_fifo_sync_bind_fpv.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_fifo_sync_bind_fpv.sv @@ -29,7 +29,9 @@ module prim_fifo_sync_bind_fpv; .rvalid_o, .rready_i, .rdata_o, - .depth_o + .full_o, + .depth_o, + .err_o ); bind i_nopass7 prim_fifo_sync_assert_fpv #( @@ -47,7 +49,9 @@ module prim_fifo_sync_bind_fpv; .rvalid_o, .rready_i, .rdata_o, - .depth_o + .full_o, + .depth_o, + .err_o ); bind i_nopass8 prim_fifo_sync_assert_fpv #( @@ -65,7 +69,9 @@ module prim_fifo_sync_bind_fpv; .rvalid_o, .rready_i, .rdata_o, - .depth_o + .full_o, + .depth_o, + .err_o ); bind i_nopass15 prim_fifo_sync_assert_fpv #( @@ -83,7 +89,9 @@ module prim_fifo_sync_bind_fpv; .rvalid_o, .rready_i, .rdata_o, - .depth_o + .full_o, + .depth_o, + .err_o ); bind i_nopass16 prim_fifo_sync_assert_fpv #( @@ -101,7 +109,9 @@ module prim_fifo_sync_bind_fpv; .rvalid_o, .rready_i, .rdata_o, - .depth_o + .full_o, + .depth_o, + .err_o ); //////////////// @@ -123,7 +133,9 @@ module prim_fifo_sync_bind_fpv; .rvalid_o, .rready_i, .rdata_o, - .depth_o + .full_o, + .depth_o, + .err_o ); bind i_pass1 prim_fifo_sync_assert_fpv #( @@ -141,7 +153,9 @@ module prim_fifo_sync_bind_fpv; .rvalid_o, .rready_i, .rdata_o, - .depth_o + .full_o, + .depth_o, + .err_o ); bind i_pass7 prim_fifo_sync_assert_fpv #( @@ -159,7 +173,9 @@ module prim_fifo_sync_bind_fpv; .rvalid_o, .rready_i, .rdata_o, - .depth_o + .full_o, + .depth_o, + .err_o ); bind i_pass8 prim_fifo_sync_assert_fpv #( @@ -177,7 +193,9 @@ module prim_fifo_sync_bind_fpv; .rvalid_o, .rready_i, .rdata_o, - .depth_o + .full_o, + .depth_o, + .err_o ); bind i_pass15 prim_fifo_sync_assert_fpv #( @@ -195,7 +213,9 @@ module prim_fifo_sync_bind_fpv; .rvalid_o, .rready_i, .rdata_o, - .depth_o + .full_o, + .depth_o, + .err_o ); bind i_pass16 prim_fifo_sync_assert_fpv #( @@ -213,7 +233,9 @@ module prim_fifo_sync_bind_fpv; .rvalid_o, .rready_i, .rdata_o, - .depth_o + .full_o, + .depth_o, + .err_o ); endmodule : prim_fifo_sync_bind_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_fifo_sync_tb.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_fifo_sync_tb.sv index a879001ec2..1792112d3d 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_fifo_sync_tb.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_fifo_sync_tb.sv @@ -19,7 +19,7 @@ module prim_fifo_sync_tb #( parameter int unsigned NumDuts = 11, // fifo params parameter int unsigned Width = 4, - parameter int unsigned MaxDepth = 16, // max depth used in this destbench + parameter int unsigned MaxDepth = 16, // max depth used in this testbench localparam int unsigned DepthW = ($clog2(MaxDepth+1) == 0) ? 1 : $clog2(MaxDepth+1) ) ( input clk_i, @@ -31,7 +31,9 @@ module prim_fifo_sync_tb #( output rvalid_o[NumDuts], input rready_i[NumDuts], output [Width-1:0] rdata_o [NumDuts], - output [DepthW-1:0] depth_o [NumDuts] + output full_o [NumDuts], + output [DepthW-1:0] depth_o [NumDuts], + output err_o [NumDuts] ); // need to instantiate by hand since bind statements inside @@ -55,7 +57,9 @@ module prim_fifo_sync_tb #( .rvalid_o(rvalid_o[0]), .rready_i(rready_i[0]), .rdata_o(rdata_o[0]), - .depth_o(depth_o[0][0]) + .full_o(full_o[0]), + .depth_o(depth_o[0][0]), + .err_o(err_o[0]) ); prim_fifo_sync #( @@ -72,7 +76,9 @@ module prim_fifo_sync_tb #( .rvalid_o(rvalid_o[1]), .rready_i(rready_i[1]), .rdata_o(rdata_o[1]), - .depth_o(depth_o[1][2:0]) + .full_o(full_o[1]), + .depth_o(depth_o[1][2:0]), + .err_o(err_o[1]) ); prim_fifo_sync #( @@ -89,7 +95,9 @@ module prim_fifo_sync_tb #( .rvalid_o(rvalid_o[2]), .rready_i(rready_i[2]), .rdata_o(rdata_o[2]), - .depth_o(depth_o[2][3:0]) + .full_o(full_o[2]), + .depth_o(depth_o[2][3:0]), + .err_o(err_o[2]) ); prim_fifo_sync #( @@ -106,7 +114,9 @@ module prim_fifo_sync_tb #( .rvalid_o(rvalid_o[3]), .rready_i(rready_i[3]), .rdata_o(rdata_o[3]), - .depth_o(depth_o[3][3:0]) + .full_o(full_o[3]), + .depth_o(depth_o[3][3:0]), + .err_o(err_o[3]) ); prim_fifo_sync #( @@ -123,7 +133,9 @@ module prim_fifo_sync_tb #( .rvalid_o(rvalid_o[4]), .rready_i(rready_i[4]), .rdata_o(rdata_o[4]), - .depth_o(depth_o[4][4:0]) + .full_o(full_o[4]), + .depth_o(depth_o[4][4:0]), + .err_o(err_o[4]) ); //////////////// @@ -145,7 +157,9 @@ module prim_fifo_sync_tb #( .rvalid_o(rvalid_o[5]), .rready_i(rready_i[5]), .rdata_o(rdata_o[5]), - .depth_o(depth_o[5][0]) + .full_o(full_o[5]), + .depth_o(depth_o[5][0]), + .err_o(err_o[5]) ); prim_fifo_sync #( @@ -162,7 +176,9 @@ module prim_fifo_sync_tb #( .rvalid_o(rvalid_o[6]), .rready_i(rready_i[6]), .rdata_o(rdata_o[6]), - .depth_o(depth_o[6][0]) + .full_o(full_o[6]), + .depth_o(depth_o[6][0]), + .err_o(err_o[6]) ); prim_fifo_sync #( @@ -179,7 +195,9 @@ module prim_fifo_sync_tb #( .rvalid_o(rvalid_o[7]), .rready_i(rready_i[7]), .rdata_o(rdata_o[7]), - .depth_o(depth_o[7][2:0]) + .full_o(full_o[7]), + .depth_o(depth_o[7][2:0]), + .err_o(err_o[7]) ); prim_fifo_sync #( @@ -196,7 +214,9 @@ module prim_fifo_sync_tb #( .rvalid_o(rvalid_o[8]), .rready_i(rready_i[8]), .rdata_o(rdata_o[8]), - .depth_o(depth_o[8][3:0]) + .full_o(full_o[8]), + .depth_o(depth_o[8][3:0]), + .err_o(err_o[8]) ); prim_fifo_sync #( @@ -213,7 +233,9 @@ module prim_fifo_sync_tb #( .rvalid_o(rvalid_o[9]), .rready_i(rready_i[9]), .rdata_o(rdata_o[9]), - .depth_o(depth_o[9][3:0]) + .full_o(full_o[9]), + .depth_o(depth_o[9][3:0]), + .err_o(err_o[9]) ); prim_fifo_sync #( @@ -230,7 +252,9 @@ module prim_fifo_sync_tb #( .rvalid_o(rvalid_o[10]), .rready_i(rready_i[10]), .rdata_o(rdata_o[10]), - .depth_o(depth_o[10][4:0]) + .full_o(full_o[10]), + .depth_o(depth_o[10][4:0]), + .err_o(err_o[10]) ); endmodule : prim_fifo_sync_tb 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 22d219415b..1aec8ee4ea 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 @@ -40,9 +40,9 @@ module prim_alert_rxtx_assert_fpv logic init_pending; assign init_pending = mubi4_test_true_strict(init_trig_i) || - prim_alert_rxtx_fpv.i_prim_alert_receiver.state_q inside { - prim_alert_rxtx_fpv.i_prim_alert_receiver.InitReq, - prim_alert_rxtx_fpv.i_prim_alert_receiver.InitAckWait}; + prim_alert_rxtx_tb.i_prim_alert_receiver.state_q inside { + prim_alert_rxtx_tb.i_prim_alert_receiver.InitReq, + prim_alert_rxtx_tb.i_prim_alert_receiver.InitAckWait}; // note: we can only detect sigint errors where one wire is flipped. `ASSUME_FPV(PingErrorsAreOH_M, $onehot0({ping_err_pi, ping_err_ni}), clk_i, !rst_ni) @@ -56,91 +56,91 @@ module prim_alert_rxtx_assert_fpv (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) && - $stable(prim_alert_rxtx_fpv.alert_tx_out.alert_p) ##1 - $fell(prim_alert_rxtx_fpv.alert_tx_out.alert_p) && - $stable(prim_alert_rxtx_fpv.alert_rx_out.ack_p) ##1 - $fell(prim_alert_rxtx_fpv.alert_rx_out.ack_p) && - $stable(prim_alert_rxtx_fpv.alert_tx_out.alert_p) ; + $rose(prim_alert_rxtx_tb.alert_tx_out.alert_p) ##1 + $rose(prim_alert_rxtx_tb.alert_rx_out.ack_p) && + $stable(prim_alert_rxtx_tb.alert_tx_out.alert_p) ##1 + $fell(prim_alert_rxtx_tb.alert_tx_out.alert_p) && + $stable(prim_alert_rxtx_tb.alert_rx_out.ack_p) ##1 + $fell(prim_alert_rxtx_tb.alert_rx_out.ack_p) && + $stable(prim_alert_rxtx_tb.alert_tx_out.alert_p) ; endsequence // note: injected errors may lockup the FSMs, and hence the full HS can // only take place if both FSMs are in a good 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_receiver.state_q == - prim_alert_rxtx_fpv.i_prim_alert_receiver.Idle) |=> FullHandshake_S, + `ASSERT(PingHs_A, ##1 $changed(prim_alert_rxtx_tb.alert_rx_out.ping_p) && + (prim_alert_rxtx_tb.i_prim_alert_sender.state_q == + prim_alert_rxtx_tb.i_prim_alert_sender.Idle) && + (prim_alert_rxtx_tb.i_prim_alert_receiver.state_q == + prim_alert_rxtx_tb.i_prim_alert_receiver.Idle) |=> FullHandshake_S, clk_i, !rst_ni || error_present || mubi4_test_true_strict(init_trig_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) |=> + (prim_alert_rxtx_tb.i_prim_alert_sender.state_q == + prim_alert_rxtx_tb.i_prim_alert_sender.Idle) && + (prim_alert_rxtx_tb.i_prim_alert_receiver.state_q == + prim_alert_rxtx_tb.i_prim_alert_receiver.Idle) |=> FullHandshake_S |-> alert_ack_o, clk_i, !rst_ni || error_present || mubi4_test_true_strict(init_trig_i)) `ASSERT(AlertTestHs_A, alert_test_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) |=> + (prim_alert_rxtx_tb.i_prim_alert_sender.state_q == + prim_alert_rxtx_tb.i_prim_alert_sender.Idle) && + (prim_alert_rxtx_tb.i_prim_alert_receiver.state_q == + prim_alert_rxtx_tb.i_prim_alert_receiver.Idle) |=> FullHandshake_S, clk_i, !rst_ni || error_present || mubi4_test_true_strict(init_trig_i)) // Make sure we eventually get an ACK `ASSERT(AlertReqAck_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) |-> strong(##[1:$] alert_ack_o), + (prim_alert_rxtx_tb.i_prim_alert_sender.state_q == + prim_alert_rxtx_tb.i_prim_alert_sender.Idle) && + (prim_alert_rxtx_tb.i_prim_alert_receiver.state_q == + prim_alert_rxtx_tb.i_prim_alert_receiver.Idle) |-> strong(##[1:$] alert_ack_o), clk_i, !rst_ni || error_present || mubi4_test_true_strict(init_trig_i)) // transmission of pings // 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) |-> + `ASSERT(AlertPingOk_A, !(prim_alert_rxtx_tb.i_prim_alert_sender.state_q inside { + prim_alert_rxtx_tb.i_prim_alert_sender.PingHsPhase1, + prim_alert_rxtx_tb.i_prim_alert_sender.PingHsPhase2}) && $rose(ping_req_i) |-> ##[1:9] ping_ok_o, clk_i, !rst_ni || error_present || init_pending) - `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) |-> + `ASSERT(AlertPingIgnored_A, (prim_alert_rxtx_tb.i_prim_alert_sender.state_q inside { + prim_alert_rxtx_tb.i_prim_alert_sender.PingHsPhase1, + prim_alert_rxtx_tb.i_prim_alert_sender.PingHsPhase2}) && $rose(ping_req_i) |-> ping_ok_o == 0 throughout ping_req_i [->1], clk_i, !rst_ni || error_present || mubi4_test_true_strict(init_trig_i)) // transmission of alerts in case of no collision with ping enable `ASSERT(AlertCheck0_A, !ping_req_i [*3] ##0 ($rose(alert_req_i) || $rose(alert_test_i)) && - (prim_alert_rxtx_fpv.i_prim_alert_sender.state_q == - prim_alert_rxtx_fpv.i_prim_alert_sender.Idle) |=> + (prim_alert_rxtx_tb.i_prim_alert_sender.state_q == + prim_alert_rxtx_tb.i_prim_alert_sender.Idle) |=> alert_o, clk_i, !rst_ni || error_present || ping_req_i || init_pending) - // transmission of alerts in the general case which can include continous ping collisions + // transmission of alerts in the general case which can include continuous ping collisions `ASSERT(AlertCheck1_A, alert_req_i || alert_test_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), + strong(##[1:$] ((prim_alert_rxtx_tb.i_prim_alert_sender.state_q == + prim_alert_rxtx_tb.i_prim_alert_sender.Idle) && !ping_req_i) ##1 alert_o), clk_i, - !rst_ni || error_present || prim_alert_rxtx_fpv.i_prim_alert_sender.alert_clr || + !rst_ni || error_present || prim_alert_rxtx_tb.i_prim_alert_sender.alert_clr || mubi4_test_true_strict(init_trig_i)) // basic liveness of FSMs in case no errors are present `ASSERT(FsmLivenessSender_A, - (prim_alert_rxtx_fpv.i_prim_alert_sender.state_q != - prim_alert_rxtx_fpv.i_prim_alert_sender.Idle) |-> - strong(##[1:$] (prim_alert_rxtx_fpv.i_prim_alert_sender.state_q == - prim_alert_rxtx_fpv.i_prim_alert_sender.Idle)), + (prim_alert_rxtx_tb.i_prim_alert_sender.state_q != + prim_alert_rxtx_tb.i_prim_alert_sender.Idle) |-> + strong(##[1:$] (prim_alert_rxtx_tb.i_prim_alert_sender.state_q == + prim_alert_rxtx_tb.i_prim_alert_sender.Idle)), clk_i, !rst_ni || error_present || mubi4_test_true_strict(init_trig_i)) `ASSERT(FsmLivenessReceiver_A, - (prim_alert_rxtx_fpv.i_prim_alert_receiver.state_q != - prim_alert_rxtx_fpv.i_prim_alert_receiver.Idle) |-> - strong(##[1:$] (prim_alert_rxtx_fpv.i_prim_alert_receiver.state_q == - prim_alert_rxtx_fpv.i_prim_alert_receiver.Idle)), + (prim_alert_rxtx_tb.i_prim_alert_receiver.state_q != + prim_alert_rxtx_tb.i_prim_alert_receiver.Idle) |-> + strong(##[1:$] (prim_alert_rxtx_tb.i_prim_alert_receiver.state_q == + prim_alert_rxtx_tb.i_prim_alert_receiver.Idle)), clk_i, !rst_ni || error_present || mubi4_test_true_strict(init_trig_i)) // check that the in-band reset moves sender FSM into Idle state. `ASSERT(InBandInitFromReceiverToSender_A, mubi4_test_true_strict(init_trig_i) |-> - ##[1:20] (prim_alert_rxtx_fpv.i_prim_alert_sender.state_q == - prim_alert_rxtx_fpv.i_prim_alert_sender.Idle), + ##[1:20] (prim_alert_rxtx_tb.i_prim_alert_sender.state_q == + prim_alert_rxtx_tb.i_prim_alert_sender.Idle), clk_i, !rst_ni || error_present) endmodule : prim_alert_rxtx_assert_fpv 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 486c5f6f5c..b54c58973f 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 @@ -43,11 +43,22 @@ module prim_alert_rxtx_async_assert_fpv logic init_pending; assign init_pending = mubi4_test_true_strict(init_trig_i) || - prim_alert_rxtx_async_fpv.i_prim_alert_receiver.state_q inside { - prim_alert_rxtx_async_fpv.i_prim_alert_receiver.InitReq, - prim_alert_rxtx_async_fpv.i_prim_alert_receiver.InitAckWait}; + prim_alert_rxtx_async_tb.i_prim_alert_receiver.state_q inside { + prim_alert_rxtx_async_tb.i_prim_alert_receiver.InitReq, + prim_alert_rxtx_async_tb.i_prim_alert_receiver.InitAckWait}; - // used to check that an error has never occured so far + logic sender_is_idle, receiver_is_idle, sender_is_pinging; + assign sender_is_idle = i_prim_alert_sender.state_q == i_prim_alert_sender.Idle; + assign receiver_is_idle = i_prim_alert_receiver.state_q == i_prim_alert_receiver.Idle; + assign sender_is_pinging = i_prim_alert_sender.state_q inside + {i_prim_alert_sender.PingHsPhase1, i_prim_alert_sender.PingHsPhase2}; + + // A signal that is true if the alert sender is sending an alert (p & !n) + logic alert_from_sender; + assign alert_from_sender = prim_alert_rxtx_async_tb.alert_tx_out.alert_p && + !prim_alert_rxtx_async_tb.alert_tx_out.alert_n; + + // used to check that an error has never occurred so far // this is used to check the handshake below. the handshake can lock up // the protocol FSMs causing the handshake to never complete. // note that this will block any ping messages and hence it can be @@ -78,91 +89,90 @@ module prim_alert_rxtx_async_assert_fpv // be parameterized accordingly if different clock ratios are to be used here. // TODO: tighten bounds if possible sequence FullHandshake_S; - $rose(prim_alert_rxtx_async_fpv.alert_pd) ##[3:5] - $rose(prim_alert_rxtx_async_fpv.ack_pd) && - $stable(prim_alert_rxtx_async_fpv.alert_pd) ##[3:5] - $fell(prim_alert_rxtx_async_fpv.alert_pd) && - $stable(prim_alert_rxtx_async_fpv.ack_pd) ##[3:5] - $fell(prim_alert_rxtx_async_fpv.ack_pd) && - $stable(prim_alert_rxtx_async_fpv.alert_pd); + $rose(prim_alert_rxtx_async_tb.alert_pd) ##[3:6] + $rose(prim_alert_rxtx_async_tb.ack_pd) && + $stable(prim_alert_rxtx_async_tb.alert_pd) ##[3:6] + $fell(prim_alert_rxtx_async_tb.alert_pd) && + $stable(prim_alert_rxtx_async_tb.ack_pd) ##[3:6] + $fell(prim_alert_rxtx_async_tb.ack_pd) && + $stable(prim_alert_rxtx_async_tb.alert_pd); endsequence // note: injected errors may lockup the FSMs, and hence the full HS can // only take place if both FSMs are in a good state - `ASSERT(PingHs_A, ##1 $changed(prim_alert_rxtx_async_fpv.ping_pd) && - (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, + `ASSERT(PingHs_A, ##1 $changed(prim_alert_rxtx_async_tb.ping_pd) && + sender_is_idle && receiver_is_idle |-> ##[0:5] FullHandshake_S, clk_i, !rst_ni || error_setreg_q || init_pending) `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, + sender_is_idle && receiver_is_idle |-> ##[0:5] FullHandshake_S, clk_i, !rst_ni || error_setreg_q || init_pending) `ASSERT(AlertTestHs_A, alert_test_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, + sender_is_idle && receiver_is_idle |-> ##[0:5] FullHandshake_S, clk_i, !rst_ni || error_setreg_q || init_pending) // Make sure we eventually get an ACK `ASSERT(AlertReqAck_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) |-> strong(##[1:$] alert_ack_o), + sender_is_idle && receiver_is_idle |-> strong(##[1:$] alert_ack_o), clk_i, !rst_ni || error_setreg_q || init_pending) - // 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 - // 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 || init_pending) - `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 pings + // + // Check that if we tell the receiver to request a ping then it will send one and get a response + // in a bounded time. Note that this is considering the "good case": we assume that we aren't + // injecting errors or skews that will break the signal integrity. + // + // This bound is relatively large as, in the worst case, we need to resolve staggered differential + // signal patterns on all three differential channels. + // + // Note 0: The ping sent from the alert receiver is just a single cycle long. For this property, + // we aren't interested in the sort of clock jitter that might eat the ping signal (a pulse of a + // channel of ping_skew_i at just the wrong time). If that happens in the real chip, it probably + // shows an attack and this will behave like a ping that doesn't get a response. This causes a + // timer in the alert handler that requested the ping to send an alert out itself. + // + // Note 1: The complete transmission of pings only happens when no ping handshake is in progress, + // so we only allow the property to start when the sender isn't in a ping handshake FSM state. + // + // Note 2: The receiver gives up on a ping request if it receives an alert (this is strong + // evidence that alerts can come through, so it doesn't really need to do the ping at all!) To see + // the ping handshake go through, we constrain things to ensure this doesn't happen. + `ASSERT(AlertPingOk_A, + !sender_is_pinging && $rose(ping_req_i) |-> ##[1:23] ping_ok_o, + clk_i, + (!rst_ni || error_setreg_q || init_pending || alert_from_sender || + $changed(ping_skew_i, @clk_i) || ^ping_skew_i || + ack_skew_i)) + + `ASSERT(AlertPingIgnored_A, + sender_is_pinging && $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_req_i [*10] ##1 ($rose(alert_req_i) || $rose(alert_test_i)) && - (prim_alert_rxtx_async_fpv.i_prim_alert_sender.state_q == - prim_alert_rxtx_async_fpv.i_prim_alert_sender.Idle) |-> + `ASSERT(AlertCheck0_A, + !ping_req_i [*10] ##1 ($rose(alert_req_i) || $rose(alert_test_i)) && sender_is_idle |-> ##[3:5] alert_o, - clk_i, !rst_ni || ping_req_i || error_setreg_q || init_pending) + clk_i, !rst_ni || ping_req_i || error_setreg_q || init_pending || alert_skew_i || ack_skew_i) // eventual transmission of alerts in the general case which can include continous ping // collisions - `ASSERT(AlertCheck1_A, alert_req_i || alert_test_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), + `ASSERT(AlertCheck1_A, + alert_req_i || alert_test_i |-> strong(##[1:$] sender_is_idle ##[3:5] alert_o), clk_i, !rst_ni || error_setreg_q || - prim_alert_rxtx_async_fpv.i_prim_alert_sender.alert_clr || init_pending) + prim_alert_rxtx_async_tb.i_prim_alert_sender.alert_clr || init_pending) // basic liveness of FSMs in case no errors are present - `ASSERT(FsmLivenessSender_A, !error_present [*2] ##1 !error_present && - (prim_alert_rxtx_async_fpv.i_prim_alert_sender.state_q != - prim_alert_rxtx_async_fpv.i_prim_alert_sender.Idle) |-> - strong(##[1:$] (prim_alert_rxtx_async_fpv.i_prim_alert_sender.state_q == - prim_alert_rxtx_async_fpv.i_prim_alert_sender.Idle)), + `ASSERT(FsmLivenessSender_A, + !error_present [*2] ##1 !error_present && !sender_is_idle |-> + strong(##[1:$] sender_is_idle), clk_i, !rst_ni || error_present || init_pending) - `ASSERT(FsmLivenessReceiver_A, !error_present [*2] ##1 !error_present && - (prim_alert_rxtx_async_fpv.i_prim_alert_receiver.state_q != - prim_alert_rxtx_async_fpv.i_prim_alert_receiver.Idle) |-> - strong(##[1:$] (prim_alert_rxtx_async_fpv.i_prim_alert_receiver.state_q == - prim_alert_rxtx_async_fpv.i_prim_alert_receiver.Idle)), + `ASSERT(FsmLivenessReceiver_A, + !error_present [*2] ##1 !error_present && receiver_is_idle |-> + strong(##[1:$] receiver_is_idle), clk_i, !rst_ni || error_present || init_pending) // check that the in-band reset moves sender FSM into Idle state. `ASSERT(InBandInitFromReceiverToSender_A, mubi4_test_true_strict(init_trig_i) |-> - ##[1:30] (prim_alert_rxtx_async_fpv.i_prim_alert_sender.state_q == - prim_alert_rxtx_async_fpv.i_prim_alert_sender.Idle), + ##[1:30] sender_is_idle, clk_i, !rst_ni || error_present) endmodule : prim_alert_rxtx_async_assert_fpv 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 d39fae3ff1..a7eb1787ee 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 @@ -97,17 +97,17 @@ module prim_esc_rxtx_assert_fpv `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, + ##[0:1] prim_esc_rxtx_tb.esc_rx_out.resp_p + ##1 !prim_esc_rxtx_tb.esc_rx_out.resp_p, clk_i, !rst_ni || error_present) - // check correct transmission of escalation within 0-1 cycles + // check correct transmission of escalation within 1-2 cycles `ASSERT(EscCheck_A, ##1 esc_req_i |-> - ##[0:1] esc_req_o, + ##[1:2] esc_req_o, clk_i, !rst_ni || error_present) @@ -126,26 +126,26 @@ module prim_esc_rxtx_assert_fpv // basic liveness of sender FSM `ASSERT(FsmLivenessSender_A, - (prim_esc_rxtx_fpv.u_prim_esc_sender.state_q != - prim_esc_rxtx_fpv.u_prim_esc_sender.Idle) + (prim_esc_rxtx_tb.u_prim_esc_sender.state_q != + prim_esc_rxtx_tb.u_prim_esc_sender.Idle) |-> - strong(##[1:$] (prim_esc_rxtx_fpv.u_prim_esc_sender.state_q - == prim_esc_rxtx_fpv.u_prim_esc_sender.Idle))) + strong(##[1:$] (prim_esc_rxtx_tb.u_prim_esc_sender.state_q + == prim_esc_rxtx_tb.u_prim_esc_sender.Idle))) // basic liveness of sender FSM (can only be guaranteed if no error is present) `ASSERT(FsmLivenessReceiver_A, - (prim_esc_rxtx_fpv.u_prim_esc_receiver.state_q != - prim_esc_rxtx_fpv.u_prim_esc_receiver.Idle) + (prim_esc_rxtx_tb.u_prim_esc_receiver.state_q != + prim_esc_rxtx_tb.u_prim_esc_receiver.Idle) |-> - strong(##[1:$] (prim_esc_rxtx_fpv.u_prim_esc_receiver.state_q - == prim_esc_rxtx_fpv.u_prim_esc_receiver.Idle)), + strong(##[1:$] (prim_esc_rxtx_tb.u_prim_esc_receiver.state_q + == prim_esc_rxtx_tb.u_prim_esc_receiver.Idle)), clk_i, - rst_ni || + !rst_ni || error_present) // The assertions below use TimeoutCntDw to bound some sequence lengths. Add an assertion to check // it matches the parameter in the design. `ASSERT(TimeoutCntDwConsistent_A, - TimeoutCntDw == prim_esc_rxtx_fpv.u_prim_esc_receiver.TimeoutCntDw) + TimeoutCntDw == prim_esc_rxtx_tb.u_prim_esc_receiver.TimeoutCntDw) // check that auto escalation timeout does not trigger prematurely. // this requires that no errors have been present so far. @@ -155,7 +155,7 @@ module prim_esc_rxtx_assert_fpv !esc_req_o ##1 !ping_req_i [*0 : 2**TimeoutCntDw - 4] |-> - !esc_req_o, + ##1 !esc_req_o, clk_i, !rst_ni || error_d || @@ -169,7 +169,7 @@ module prim_esc_rxtx_assert_fpv !esc_req_o ##1 !ping_req_i [* 2**TimeoutCntDw - 3 : $] |-> - esc_req_o, + ##1 esc_req_o, clk_i, !rst_ni || error_d || diff --git a/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_fifo_sync_assert_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_fifo_sync_assert_fpv.sv index 7dd9bfa891..8d914a577f 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_fifo_sync_assert_fpv.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_fifo_sync_assert_fpv.sv @@ -16,18 +16,23 @@ module prim_fifo_sync_assert_fpv #( localparam int unsigned DepthWNorm = $clog2(Depth+1), localparam int unsigned DepthW = (DepthWNorm == 0) ? 1 : DepthWNorm ) ( - input clk_i, - input rst_ni, - input clr_i, - input wvalid_i, - input wready_o, - input [Width-1:0] wdata_i, - input rvalid_o, - input rready_i, - input [Width-1:0] rdata_o, - input [DepthW-1:0] depth_o + input clk_i, + input rst_ni, + input clr_i, + input wvalid_i, + input wready_o, + input [Width-1:0] wdata_i, + input rvalid_o, + input rready_i, + input [Width-1:0] rdata_o, + input full_o, + input [DepthW-1:0] depth_o, + input err_o ); + localparam bit [DepthW+2:0] WideOne = (DepthW + 3)'(1'b1); + localparam int unsigned PtrW = prim_util_pkg::vbits(Depth); + ///////////////// // Assumptions // ///////////////// @@ -86,7 +91,7 @@ module prim_fifo_sync_assert_fpv #( // implements (++val) mod Depth function automatic logic [DepthW+2:0] modinc(logic [DepthW+2:0] val, int modval); if (val == Depth-1) return 0; - else return val + 1; + else return val + WideOne; endfunction // this only models the data flow, since the control logic is tested below @@ -102,25 +107,25 @@ module prim_fifo_sync_assert_fpv #( ref_depth <= 0; end else begin if (wvalid_i && wready_o && rvalid_o && rready_i) begin - fifo[wptr] <= wdata_i; + fifo[wptr[PtrW-1:0]] <= wdata_i; wptr <= modinc(wptr, Depth); rptr <= modinc(rptr, Depth); end else if (wvalid_i && wready_o) begin - fifo[wptr] <= wdata_i; + fifo[wptr[PtrW-1:0]] <= wdata_i; wptr <= modinc(wptr, Depth); - ref_depth <= ref_depth + 1; + ref_depth <= ref_depth + WideOne; end else if (rvalid_o && rready_i) begin rptr <= modinc(rptr, Depth); - ref_depth <= ref_depth - 1; + ref_depth <= ref_depth - WideOne; end end end end if (Pass) begin : gen_pass - assign ref_rdata = (ref_depth == 0) ? wdata_i : fifo[rptr]; + assign ref_rdata = (ref_depth == 0) ? wdata_i : fifo[rptr[PtrW-1:0]]; end else begin : gen_no_pass - assign ref_rdata = fifo[rptr]; + assign ref_rdata = fifo[rptr[PtrW-1:0]]; end end @@ -136,6 +141,9 @@ module prim_fifo_sync_assert_fpv #( // Forward Assertions // //////////////////////// + // The full_o port should be high iff the depth is maximal. + `ASSERT(FullIffFullDepth_A, (depth_o == Depth) <-> (full_o)) + // assert depth of FIFO `ASSERT(Depth_A, depth_o <= Depth) // if we clear the FIFO, it must be empty in the next cycle @@ -170,7 +178,12 @@ module prim_fifo_sync_assert_fpv #( `ASSERT(UnusedClr_A, prim_fifo_sync.gen_passthru_fifo.unused_clr == clr_i) end else begin : gen_depth_gt0 // check wready - `ASSERT(Wready_A, depth_o < Depth |-> wready_o) + + // The wready_o signal should be high (saying that we can accept an item in the fifo) if the + // FIFO is not currently full, which can be checked my seeing that depth_o < Depth. This + // property is delayed for a single cycle after coming out of reset (because of an under_rst + // signal that gets cleared on the first clock afterwards). + `ASSERT(Wready_A, 1 |=> depth_o < Depth -> wready_o) // check rvalid `ASSERT(Rvalid_A, depth_o > 0 |-> rvalid_o) // check write only @@ -206,9 +219,14 @@ module prim_fifo_sync_assert_fpv #( `ASSERT(RvalidElemskBkwd_A, rvalid_o |-> depth_o > 0) end - // no more space in the FIFO - `ASSERT(WreadyNoSpaceBkwd_A, !wready_o |-> depth_o == Depth) + // If the wready_o signal is not high, the FIFO should be full. As with Wready_A, this property is + // delayed by a cycle after coming out of reset, to handle the clearing of the under_rst signal. + `ASSERT(WreadyNoSpaceBkwd_A, 1 |=> !wready_o -> depth_o == Depth) // elements ready to be read `ASSERT(RvalidNoElemskBkwd_A, !rvalid_o |-> depth_o == 0) + // The err_o signal should never go high. This isn't supposed to be triggerable without fault + // injection (which isn't modelled in FPV so the output should be constant zero). + `ASSERT(NoErrSignal_A, !err_o) + endmodule : prim_fifo_sync_assert_fpv diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim.waiver index 877ff83192..3cfe4081d9 100644 --- a/vendor/lowrisc_ip/ip/prim/lint/prim.waiver +++ b/vendor/lowrisc_ip/ip/prim/lint/prim.waiver @@ -12,10 +12,6 @@ waive -rules INTEGER -location {prim_packer.sv} -msg {'i' of type int waive -rules {ZERO_REP} -location {prim_packer_fifo.sv} -regexp {Replication count is zero in .*DepthW.*} \ -comment "If InW equals OutW, DepthW is zero" -# prim_sram_arbiter -waive -rules CONST_OUTPUT -location {prim_sram_arbiter.sv} -regexp {rsp_error.* is driven by constant} \ - -comment "SRAM protection is not yet implemented" - # prim_fifo_async_simple waive -rules CONST_FF -location {prim_fifo_async_simple.sv} -msg {Flip-flop 'not_in_reset_q' is driven by constant one in module 'prim_fifo_async_simple'} \ -comment "The flop input and reset values are constants." diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_ascon.vlt b/vendor/lowrisc_ip/ip/prim/lint/prim_ascon.vlt new file mode 100644 index 0000000000..019c19fc4e --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_ascon.vlt @@ -0,0 +1,13 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// waiver file for ascon + +`verilator_config + +// In the following arrays some members may depend on others. +// There are no circular dependencies but the tool must be told to analyze each member separately for simulation, i.e., to split up the arrays internally. +// Otherwise the tool needs to evaluate corresponding statements multiple times before the entire signal settles. +// This slows down simulation and causes the tool to print UNOPTFLAT lint warnings. +split_var -module "prim_ascon_sbox" -var "*temp_w*" diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_ascon.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_ascon.waiver new file mode 100644 index 0000000000..aa1d50edfb --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_ascon.waiver @@ -0,0 +1,5 @@ +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# waiver file for ascon diff --git a/vendor/lowrisc_ip/ip/prim/primgen.core b/vendor/lowrisc_ip/ip/prim/lint/prim_fifo.vbl similarity index 58% rename from vendor/lowrisc_ip/ip/prim/primgen.core rename to vendor/lowrisc_ip/ip/prim/lint/prim_fifo.vbl index 167f796593..5a9c044e86 100644 --- a/vendor/lowrisc_ip/ip/prim/primgen.core +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_fifo.vbl @@ -1,10 +1,7 @@ -CAPI=2: # Copyright lowRISC contributors (OpenTitan project). # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -name: "lowrisc:prim:primgen:0.1" -generators: - primgen: - interpreter: python3 - command: util/primgen.py + +# waive long line violations in assertions +waive --rule=line-length --location="prim_fifo_assert.svh" diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_fifo.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_fifo.waiver index b8c503a358..79ad3e5694 100644 --- a/vendor/lowrisc_ip/ip/prim/lint/prim_fifo.waiver +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_fifo.waiver @@ -10,22 +10,19 @@ waive -rules {ONE_BIT_MEM_WIDTH} -location {prim_fifo_sync.sv} -msg {Memory 'gen waive -rules {INPUT_NOT_READ} -location {prim_fifo_sync.sv} -regexp {Input port '(clk_i|rst_ni)' is not read from, instance.*Depth=0\)} \ -comment "In passthrough mode, clk and reset are not read form within this module" - -waive -rules {ASSIGN_SIGN} -location {prim_fifo_async.sv} -msg {Signed target 'i' assigned unsigned value 'PTR_WIDTH - 3'} \ - -comment "Parameter PTR_WIDTH is unsigned, but integer i is signed. This is fine. Changing the integer to unsigned might \ - cause issues with the for loop never exiting, because an unsigned integer can never become < 0." - -waive -rules NOT_READ -location {prim_fifo_async.sv} -regexp {Signal 'nc_decval_msb' is not read} \ - -comment "Store temporary values. Not used intentionally" - - waive -rules VAR_INDEX_RANGE -location {prim_fifo_*sync.sv} -regexp {maximum value .* may be too large for 'storage'} \ -comment "index is protected by control logic" -waive -rules EXPLICIT_BITLEN -location {prim_fifo_*sync.sv} -regexp {Bit length not specified for constant '1'} \ - -comment "index is protected by control logic" - ## prim_fifo_async_sram_adapter waive -rules ARITH_CONTEXT -location {prim_fifo_async_sram_adapter.sv} \ -regexp {(r|w)_wptr_v.*_rptr_v} \ -comment "The pointer value width is determined. Remove the casting for readability" +waive -rules USE_BEFORE_DECL -location {prim_fifo_async_sram_adapter.sv} -msg {'dec2gray' is referenced before its declaration at prim_fifo_async_sram_adapter.sv} \ + -comment "dec2gray is a function defined towards the end of the file." +waive -rules USE_BEFORE_DECL -location {prim_fifo_async_sram_adapter.sv} -msg {'gray2dec' is referenced before its declaration at prim_fifo_async_sram_adapter.sv} \ + -comment "gray2dec is a function defined towards the end of the file." + +# Avoid warnings about overly long macro prototypes (caused by long default values of arguments) +waive -rules {LINE_LENGTH} -location {prim_fifo_assert.svh} \ + -msg {Line length of} \ + -comment "Some macros cannot be line-wrapped, as some tools do not support that." diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_flop_2sync.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_flop_2sync.waiver index 1f6544386a..865aa075c3 100644 --- a/vendor/lowrisc_ip/ip/prim/lint/prim_flop_2sync.waiver +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_flop_2sync.waiver @@ -12,3 +12,6 @@ waive -rules {PARAM_NOT_USED} -location {prim_flop_2sync.sv} -regexp {Parameter waive -rules {SAME_NAME_TYPE} -location {prim_flop_2sync.sv} -regexp {'ResetValue' is used as a parameter here, and as an enumeration value at prim.*} \ -comment "Parameter name reuse." + +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_gf_mult.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_gf_mult.waiver new file mode 100644 index 0000000000..520302bcc0 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_gf_mult.waiver @@ -0,0 +1,10 @@ +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# waiver file for prim_gf_mult + +waive -rules USE_BEFORE_DECL -location {prim_gf_mult.sv} -msg {'gf_mult' is referenced before its declaration at prim_gf_mult.sv} \ + -comment "gf_mult is a function defined towards the end of the file." +waive -rules USE_BEFORE_DECL -location {prim_gf_mult.sv} -msg {'gen_matrix' is referenced before its declaration at prim_gf_mult.sv} \ + -comment "gen_matrix is a function defined towards the end of the file." diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_lfsr.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_lfsr.waiver index 699015288d..55ace8e441 100644 --- a/vendor/lowrisc_ip/ip/prim/lint/prim_lfsr.waiver +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_lfsr.waiver @@ -5,5 +5,5 @@ # waiver file for prim_lfsr # TODO: this lint waiver may not be necessary in future AscentLint versions. check and remove if possible. -waive -rules {LOOP_VAR_OP} -location {prim_lfsr.sv} -msg {Loop variable 'k' is in arithmetic expression '(k + shift) % gen_out_non_linear.NumSboxes' with non-constant terms} \ +waive -rules {LOOP_VAR_OP} -location {prim_lfsr.sv} -regexp {Loop variable 'k' is in arithmetic expression '\(k \+ shift\) % (gen_out_non_linear.|)NumSboxes' with non-constant terms} \ -comment "This message is a false positive in this context, since the function inputs are constant." diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_racl_error_arb.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_racl_error_arb.waiver new file mode 100644 index 0000000000..d093f0e3d6 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_racl_error_arb.waiver @@ -0,0 +1,10 @@ +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# waiver file for prim_racl_error_arb + +waive -rules {HIER_BRANCH_NOT_READ} -location {prim_racl_error_arb.sv} -regexp {Net '(clk_i|rst_ni)' in module 'prim_racl_error_arb'.*} \ + -comment "clk_ and rst_ni are only used for assertions in the underlying arbiter." +waive -rules {HIER_BRANCH_NOT_READ} -location {prim_racl_error_arb.sv} -regexp {Connected net '(clk_i|rst_ni)' at prim_racl_error_arb.sv.*} \ + -comment "clk_ and rst_ni are only used for assertions in the underlying arbiter." 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 index dfd8d6f485..bd43559fd7 100644 --- a/vendor/lowrisc_ip/ip/prim/lint/prim_ram_1p_adv.waiver +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_ram_1p_adv.waiver @@ -6,3 +6,6 @@ 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." + +waive -rules {RESET_USE} -location {prim_ram_1p_adv.sv} -regexp {rst_ni' is connected to 'prim_ram_1p' port 'rst_ni', and used as an asynchronous reset or set at prim_ram_1p_adv.sv} \ + -comment "rst_ni is the asynchronous reset of prim_ram_1p_adv. It's unused in the generic implementation, but other implementations may use it." diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_ram_1r1w_async_adv.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_ram_1r1w_async_adv.waiver new file mode 100644 index 0000000000..9e970be642 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_ram_1r1w_async_adv.waiver @@ -0,0 +1,15 @@ +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# waiver file for prim_ram_1r1w_async_adv + +waive -rules {HIER_BRANCH_NOT_READ} -location {prim_ram_1r1w_async_adv.sv} -regexp {Net 'rst_a_ni' is not read from} \ + -comment "rst_a_ni is only used in assertions in certain configurations." + +waive -rules {INPUT_NOT_READ} -location {prim_ram_1r1w_async_adv.sv} -regexp {Input port 'rst_a_ni' is not read from, instance} \ + -comment "rst_a_ni is only used in assertions in certain configurations." + +waive -rules {RESET_USE} -location {prim_ram_1r1w_async_adv.sv} + -regexp {'rst_b_ni' is connected to 'prim_ram_1r1w' port 'rst_b_ni', and used as an asynchronous reset} \ + -comment "The generic implementation of the underlying prim does not use rst_b_ni and ties off this input." diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_rom_adv.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_rom_adv.waiver new file mode 100644 index 0000000000..a930a57440 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_rom_adv.waiver @@ -0,0 +1,8 @@ +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# waiver file for prim_rom_adv + +waive -rules {RESET_USE} -location {prim_rom_adv.sv} -regexp {rst_ni' is connected to 'prim_rom' port 'rst_ni', and used as an asynchronous reset or set at prim_rom_adv.sv} \ + -comment "rst_ni is the asynchronous reset of prim_rom. It's unused in the generic implementation, but other implementations may use it (e.g., for BIST or DFT purposes)." diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_secded.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_secded.waiver index f419c53548..3b83540bca 100644 --- a/vendor/lowrisc_ip/ip/prim/lint/prim_secded.waiver +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_secded.waiver @@ -6,3 +6,9 @@ waive -rules {SAME_NAME_TYPE} -location {*} -regexp {'prim_secded_.*' is used as a module here, and as a function at prim_secded_pkg.sv.*} \ -comment "The secded functions and primitives may have the same name." +waive -rules {SAME_NAME_TYPE} -location {*} -regexp {'prim_secded_.*' is used as a function here, and as a module at prim_secded_.*} \ + -comment "The secded functions and primitives may have the same name." +waive -rules {TWO_STATE_TYPE} -location {*} -regexp {'sd_type' is of two state type } \ + -comment "sd_type is used in constant functions that are used for generates" +waive -rules {TWO_STATE_TYPE} -location {*} -regexp {'width' is of two state type } \ + -comment "width is used in constant functions that are used for generates" diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_sha2.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_sha2.waiver index cb5b908e72..9b912147fb 100644 --- a/vendor/lowrisc_ip/ip/prim/lint/prim_sha2.waiver +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_sha2.waiver @@ -18,9 +18,6 @@ waive -rules {EXPLICIT_BITLEN} -location {prim_sha2.sv} -regexp {.*(0|1)} \ waive -rules {HIER_BRANCH_NOT_READ INPUT_NOT_READ} -location {prim_sha2_pad.sv} -regexp {wipe_(secret|v)} \ -comment "Not used but remained for future use" -waive -rules {NOT_READ} -location {*_reg_top.sv} -regexp {(address|param|user)} \ - -comment "Register module waiver" - # ARITH_CONTEXT waive -rules {ARITH_CONTEXT} -location {prim_sha2.sv} -regexp {Bitlength of arithmetic operation '.processed_length.63:9. \+ 1'b1.'} \ -comment "Bitwidth overflow is intended" diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_subreg.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_subreg.waiver index d66498b7de..7259946dcc 100644 --- a/vendor/lowrisc_ip/ip/prim/lint/prim_subreg.waiver +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_subreg.waiver @@ -2,8 +2,5 @@ # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -waive -rules INPUT_NOT_READ -location {prim_subreg.sv} -regexp {Input port 'wd' is not read from} \ - -comment "for RO wd is not used" - waive -rules {PARAM_NOT_USED} -location {prim_subreg_shadow.sv} -regexp {Mubi} \ -comment "Mubi is not yet supported in prim_subreg_shadow." diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_util.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_util.waiver new file mode 100644 index 0000000000..b3e82dbfb7 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_util.waiver @@ -0,0 +1,11 @@ +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# waiver file for prim_util + +waive -rules {DIVIDE} -location {prim_util_pkg.sv} -msg {Divide operation '(dividend / divisor)' encountered} \ + -comment "Divide allowed to compute static values." + +waive -rules {MODULUS} -location {prim_util_pkg.sv} -msg {Modulus operation '(dividend % divisor)' encountered} \ + -comment "Modulus allowed to compute static values." diff --git a/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_duplex_tb/README.md b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_duplex_tb/README.md new file mode 100644 index 0000000000..e842aa7d4e --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_duplex_tb/README.md @@ -0,0 +1,30 @@ +Ascon Duplex Verilator Testbench +================================ + +This directory contains a basic, scratch Verilator testbench targeting +functional verification of the Ascon duplex implementations during +development. + +How to build and run the testbench +---------------------------------- + +From the OpenTitan top level execute + + ```sh + fusesoc --cores-root=. run --setup --build lowrisc:dv_verilator:prim_ascon_duplex_tb + ``` +to build the testbench and afterwards + + ```sh + ./build/lowrisc_dv_verilator_prim_ascon_duplex_tb_0/default-verilator/Vprim_ascon_duplex_tb \ + --trace + ``` +to run it. + +Details of the testbench +------------------------ + +- `rtl/prim_ascon_duplex_tb.sv`: SystemVerilog testbench, signals test end and + result (pass/fail) to C++ via output ports. +- `cpp/prim_ascon_duplex_tb.cc`: Contains main function and instantiation of SimCtrl, + reads output ports of DUT and signals simulation termination to Verilator. diff --git a/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_duplex_tb/cpp/prim_ascon_duplex_tb.cc b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_duplex_tb/cpp/prim_ascon_duplex_tb.cc new file mode 100644 index 0000000000..7c61dbc357 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_duplex_tb/cpp/prim_ascon_duplex_tb.cc @@ -0,0 +1,57 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include +#include +#include + +#include "Vprim_ascon_duplex_tb.h" +#include "sim_ctrl_extension.h" +#include "verilated_toplevel.h" +#include "verilator_sim_ctrl.h" + +class PRIMASCONDUPLEXTB : public SimCtrlExtension { + using SimCtrlExtension::SimCtrlExtension; + + public: + PRIMASCONDUPLEXTB(prim_ascon_duplex_tb *top); + + void OnClock(unsigned long sim_time); + + private: + prim_ascon_duplex_tb *top_; +}; + +// Constructor: +// - Set up top_ ptr +PRIMASCONDUPLEXTB::PRIMASCONDUPLEXTB(prim_ascon_duplex_tb *top) + : SimCtrlExtension{}, top_(top) {} + +// Function called once every clock cycle from SimCtrl +void PRIMASCONDUPLEXTB::OnClock(unsigned long sim_time) { + if (top_->test_done_o) { + VerilatorSimCtrl::GetInstance().RequestStop(top_->test_passed_o); + } +} + +int main(int argc, char **argv) { + // Init verilog instance + prim_ascon_duplex_tb top; + + // Init sim + VerilatorSimCtrl &simctrl = VerilatorSimCtrl::GetInstance(); + simctrl.SetTop(&top, &top.clk_i, &top.rst_ni, + VerilatorSimCtrlFlags::ResetPolarityNegative); + + // Create and register VerilatorSimCtrl extension + PRIMASCONDUPLEXTB primasconduplextb(&top); + simctrl.RegisterExtension(&primasconduplextb); + + std::cout << "Simulation of Ascon Duplex" << std::endl + << "==========================" << std::endl + << std::endl; + + // Get pass / fail from Verilator + return simctrl.Exec(argc, argv).first; +} diff --git a/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_duplex_tb/prim_ascon_dublex_tb.core b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_duplex_tb/prim_ascon_dublex_tb.core new file mode 100644 index 0000000000..3bd178d9ec --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_duplex_tb/prim_ascon_dublex_tb.core @@ -0,0 +1,54 @@ +CAPI=2: +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:dv_verilator:prim_ascon_duplex_tb" +description: "Ascon Duplex Verilator TB" +filesets: + files_rtl: + depend: + - lowrisc:prim:prim_ascon + - lowrisc:dv:ascon_model_dpi + files: + - rtl/prim_ascon_duplex_tb_pkg.sv + - rtl/prim_ascon_duplex_tb.sv + file_type: systemVerilogSource + + files_dv_verilator: + depend: + - lowrisc:dv_verilator:simutil_verilator + + files: + - cpp/prim_ascon_duplex_tb.cc + file_type: cppSource + +targets: + default: + default_tool: verilator + filesets: + - files_rtl + - files_dv_verilator + toplevel: prim_ascon_duplex_tb + tools: + verilator: + mode: cc + verilator_options: +# Disabling tracing reduces compile times by multiple times, but doesn't have a +# huge influence on runtime performance. (Based on early observations.) + - '--trace' + - '--trace-fst' # this requires -DVM_TRACE_FMT_FST in CFLAGS below! + - '--trace-structs' + - '--trace-params' + - '--trace-max-array 1024' + #- '--timing' # this requires verilator >= 5.0 +# compiler flags +# +# -O +# Optimization levels have a large impact on the runtime performance of the +# simulation model. -O2 and -O3 are pretty similar, -Os is slower than -O2/-O3 + - '-CFLAGS "-std=c++17 -Wall -DVM_TRACE_FMT_FST -DTOPLEVEL_NAME=prim_ascon_duplex_tb -g -O0"' + - '-LDFLAGS "-pthread -lutil -lelf"' + - "-Wall" + # XXX: Cleanup all warnings and remove this option + # (or make it more fine-grained at least) + - "-Wno-fatal" diff --git a/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_duplex_tb/rtl/prim_ascon_duplex_tb.sv b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_duplex_tb/rtl/prim_ascon_duplex_tb.sv new file mode 100644 index 0000000000..3ebfb39608 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_duplex_tb/rtl/prim_ascon_duplex_tb.sv @@ -0,0 +1,392 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Ascon duplex testbench + +module prim_ascon_duplex_tb ( + input logic clk_i, + input logic rst_ni, + + output logic test_done_o, + output logic test_passed_o +); + + import ascon_model_dpi_pkg::*; + import prim_ascon_duplex_tb_pkg::*; + import prim_ascon_pkg::*; + import prim_mubi_pkg::*; + + parameter int NUMB_RUNS = 100; + + // TODO: Problem: the c dpi model of Ascon128a and Ascon128a cannot be compiled + // at the same time, due to the structure in the vendor code. + // TODO: Use streaming operator instead of for loops? + + parameter duplex_op_e OPERATION = ASCON_ENC; + parameter duplex_variant_e VARIANT = ASCON_128; + localparam int unsigned BLOCKSIZE = VARIANT == ASCON_128 ? 8 : 16; + + parameter int STIMULUS_MSG_LEN = 10; + localparam int EXPECTED_CT_LEN = STIMULUS_MSG_LEN +16; + byte unsigned stimulus_msg[STIMULUS_MSG_LEN]; + assign stimulus_msg = '{'hDE, 'hAD, 'hBE, 'hEF, 'hCA, 'hFE, 'hF0, 'h0D, + 'hF0, 'hF0};//, 'hF0, 'hF0, 'hE0, 'hE0,'hE0, 'hE0}; + + parameter int STIMULUS_CT_LEN = 10; + localparam int EXPECTED_MSG_LEN = STIMULUS_CT_LEN; + byte unsigned stimulus_ct[STIMULUS_CT_LEN]; + assign stimulus_ct = '{'hDE, 'hAD, 'hBE, 'hEF, 'hCA, 'hFE, 'hF0, 'h0D, + 'hF0, 'hF0};//, 'hF0, 'hF0, 'hE0, 'hE0,'hE0, 'hE0}; + + parameter int STIMULUS_AD_LEN = 8; + byte unsigned stimulus_ad[STIMULUS_AD_LEN]; + assign stimulus_ad = '{'h12, 'h34, 'h56, 'h78, 'h9A, 'hBC, 'hDE, 'hF0};//, + // 'hF0, 'hF0, 'hF0, 'hF0, 'hE0, 'hE0, 'hE0, 'hE0}; + + logic [127:0] key; + logic [127:0] nonce; + + assign key = 128'hDEAD_BEEF_CAFE_F00D_0000_0000_0000_0000; + assign nonce = 128'h0000_0000_0000_0000_DEAD_BEEF_CAFE_F00D; + + byte unsigned c_key[16]; + byte unsigned c_nonce[16]; + + // convert logic <=> byte array for c_dpi call + for (genvar i = 0; i < 16; i++) begin : g_key_array + assign c_key[i] = key[127 - 8*i : 120 - 8*i]; + assign c_nonce[i] = nonce[127 - 8*i : 120 - 8*i]; + end + + // in the c modle the tag is part of the ciphertext + byte unsigned expected_ct[EXPECTED_CT_LEN]; + byte unsigned actual_ct[EXPECTED_CT_LEN]; + + // in the c modle the tag is part of the ciphertext + byte unsigned expected_msg[EXPECTED_MSG_LEN]; + byte unsigned actual_msg[EXPECTED_MSG_LEN]; + byte unsigned actual_tag[16]; + byte unsigned expected_tag[16]; + assign expected_tag = '{'hDE, 'hAD, 'hBE, 'hEF, 'hCA, 'hFE, 'hF0, 'h0D, + 'hF0, 'hF0, 'hF0, 'hF0, 'hE0, 'hE0,'hE0, 'hE0}; + + byte unsigned ct_tag_input[STIMULUS_CT_LEN+16]; + + for (genvar i = 0; i < STIMULUS_CT_LEN; i++ ) begin : g_ct_tag_input1 + assign ct_tag_input[i] = stimulus_ct[i]; + end + + for (genvar i = 0; i < 16; i++) begin : g_ct_tag_input2 + assign ct_tag_input[STIMULUS_CT_LEN + i] = expected_tag[i]; + end + + always_comb begin : C_DPI + if (OPERATION == ASCON_ENC) begin + c_dpi_aead_encrypt(expected_ct, + stimulus_msg, STIMULUS_MSG_LEN, + stimulus_ad, STIMULUS_AD_LEN, + c_nonce, c_key); + + end else begin + //TODO check return value for tag missmatch + c_dpi_aead_decrypt(ct_tag_input, (STIMULUS_CT_LEN+16), + expected_msg, + stimulus_ad, STIMULUS_AD_LEN, + c_nonce, c_key); + end + end + + int unsigned ad_count_d, ad_count_q; + int unsigned msg_count_d, msg_count_q; + int unsigned ct_count_d, ct_count_q; + + fsm_tb_state_e tb_state, nxt_tb_state; + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + tb_state <= Idle; + msg_count_q <= 0; + ad_count_q <= 0; + ct_count_q <= 0; + end else begin + tb_state <= nxt_tb_state; + msg_count_q <= msg_count_d; + ad_count_q <= ad_count_d; + ct_count_q <= ct_count_d; + end + end + + for (genvar i = 0; i < BLOCKSIZE; i++) begin : g_dut_input + // TODO double check for out of bounds: Looks like this is working, but we should add + // more information why. + assign dut_input_data_ad[127 - 8*i : 120 - 8*i] = stimulus_ad[(ad_count_q * BLOCKSIZE) + i]; + assign dut_input_data_msg[127 - 8*i : 120 - 8*i] = stimulus_msg[(msg_count_q * BLOCKSIZE) + i]; + assign dut_input_data_ct[127 - 8*i : 120 - 8*i] = stimulus_ct[(ct_count_q * BLOCKSIZE) + i]; + end + + for (genvar i = 0; i < BLOCKSIZE; i++) begin : g_dut_response_data + // TODO double check for out of bounds: Looks like this is working, but we should add + // more information why. + always_ff @(posedge clk_i) begin + if (dut_response_data_valid) begin + actual_ct[(msg_count_q * BLOCKSIZE) + i] <= dut_response_data[127 - 8*i : 120 - 8*i]; + actual_msg[(ct_count_q * BLOCKSIZE) + i] <= dut_response_data[127 - 8*i : 120 - 8*i]; + end + end + end + + for (genvar i = 0; i < 16; i++) begin : g_dut_response_tag + always_ff @(posedge clk_i) begin + if (dut_response_tag_valid) begin + actual_ct[STIMULUS_MSG_LEN+i] <= dut_response_tag[127 - 8*i : 120 - 8*i]; + actual_tag[i] <= dut_response_tag[127 - 8*i : 120 - 8*i]; + end + end + end + + always_comb begin + nxt_tb_state = tb_state; + start = 1'b0; + dut_input_valid = 1'b0; + dut_last_block_msg = MuBi4False; + dut_last_block_ad = MuBi4False; + msg_count_d = msg_count_q; + ct_count_d = ct_count_q; + ad_count_d = ad_count_q; + fsm_done = 1'b0; + dut_input_data = 'h0; + + unique case (tb_state) + Idle: begin + start = 1'b1; + if (STIMULUS_AD_LEN > 0) begin + nxt_tb_state = SendAD; + end else begin + nxt_tb_state = CheckMSGLen; + end + end + SendAD: begin + dut_input_valid = 1'b1; + dut_input_data = dut_input_data_ad; + if ((ad_count_q + 1) * BLOCKSIZE < STIMULUS_AD_LEN) begin + dut_data_valid_bytes = 5'(BLOCKSIZE); + dut_last_block_ad = MuBi4False; + end else begin + dut_data_valid_bytes = 5'(STIMULUS_AD_LEN - ((ad_count_q) * 8)); + dut_last_block_ad = MuBi4True; + end + if (dut_read_data) begin + nxt_tb_state = WaitADRead; + end + end + WaitADRead: begin + if ((ad_count_q + 1) * BLOCKSIZE < STIMULUS_AD_LEN) begin + ad_count_d = ad_count_q +1; + nxt_tb_state = SendAD; + end else begin + if (OPERATION == ASCON_ENC) begin + nxt_tb_state = CheckMSGLen; + end else begin + nxt_tb_state = CheckCTLen; + end + end + end + CheckMSGLen: begin + if (STIMULUS_MSG_LEN > 0) begin + nxt_tb_state = SendMSG; + end else begin + nxt_tb_state = ReceiveTag; + end + end + SendMSG: begin + dut_input_valid = 1'b1; + dut_input_data = dut_input_data_msg; + if ((msg_count_q + 1) * BLOCKSIZE < STIMULUS_MSG_LEN) begin + dut_data_valid_bytes = 5'(BLOCKSIZE); + dut_last_block_msg = MuBi4False; + end else begin + dut_data_valid_bytes = 5'(STIMULUS_MSG_LEN - (msg_count_q * BLOCKSIZE)); + dut_last_block_msg = MuBi4True; + end + if (dut_read_data) begin + nxt_tb_state = WaitMSGRead; + end + end + WaitMSGRead: begin + if ((msg_count_q + 1) * 8 < STIMULUS_MSG_LEN) begin + msg_count_d = msg_count_q + 1; + nxt_tb_state = SendMSG; + end else begin + nxt_tb_state = ReceiveTag; + end + end + ReceiveTag: begin + if (dut_response_tag_valid) begin + nxt_tb_state = WaitForEver; + end + end + + CheckCTLen: begin + if (EXPECTED_MSG_LEN > 0) begin + nxt_tb_state = SendCT; + end else begin + nxt_tb_state = VerifyTag; + end + end + SendCT: begin + dut_input_valid = 1'b1; + dut_input_data = dut_input_data_ct; + if ((ct_count_q + 1) * BLOCKSIZE < STIMULUS_CT_LEN) begin + dut_data_valid_bytes = 5'(BLOCKSIZE); + dut_last_block_msg = MuBi4False; + end else begin + dut_data_valid_bytes = 5'(EXPECTED_MSG_LEN - (msg_count_q * BLOCKSIZE)); + dut_last_block_msg = MuBi4True; + end + if (dut_read_data) begin + nxt_tb_state = WaitCTRead; + end + end + WaitMSGRead: begin + if ((ct_count_q + 1) * 8 < EXPECTED_MSG_LEN) begin + ct_count_d = ct_count_q + 1; + nxt_tb_state = SendCT; + end else begin + nxt_tb_state = VerifyTag; + end + end + ReceiveTag: begin + if (dut_response_tag_valid) begin + nxt_tb_state = WaitForEver; + end + end + WaitForEver: begin + fsm_done = 1'b1; + end + default: nxt_tb_state = tb_state; + endcase + end + + + //generate the sequential input/output for the DUT: + + logic [127:0] dut_input_data; + logic [127:0] dut_input_data_ad; + logic [127:0] dut_input_data_msg; + logic [127:0] dut_input_data_ct; + logic dut_input_valid; + + logic [4:0] dut_data_valid_bytes; + logic dut_ready_data; + + logic dut_read_data; + assign dut_read_data = dut_ready_data & dut_input_valid; + + logic [127:0] dut_response_data; + logic dut_response_data_valid; + + logic [127:0] dut_response_tag; + logic dut_response_tag_valid; + + prim_mubi_pkg::mubi4_t dut_no_msg; + prim_mubi_pkg::mubi4_t dut_no_ad; + + assign dut_no_msg = + ((OPERATION == ASCON_ENC && STIMULUS_MSG_LEN == 0) + ||(OPERATION == ASCON_DEC && EXPECTED_MSG_LEN == 0)) + ? prim_mubi_pkg::MuBi4True : prim_mubi_pkg::MuBi4False; + assign dut_no_ad = STIMULUS_AD_LEN == 0 ? prim_mubi_pkg::MuBi4True : + prim_mubi_pkg::MuBi4False; + + mubi4_t dut_last_block_ad; + mubi4_t dut_last_block_msg; + + mubi4_t idle; + logic start; + logic fsm_done; + + + // Instantiate Ascon Duplex + prim_ascon_duplex ascon_duplex ( + + .clk_i(clk_i), + .rst_ni(rst_ni), + + .ascon_variant(VARIANT), + .ascon_operation(OPERATION), + + .start_i(start), + .done_o(), + .idle_o(idle), + + // It is assumed that no_ad, no_msg, key, and nonce are always + // valid and constant, when the cipher is triggered by the start command + .no_ad_i(dut_no_ad), + .no_msg_i(dut_no_msg), + + .key_i(key), + .nonce_i(nonce), + + // Cipher Input Port + .data_in_i(dut_input_data), + .data_in_valid_bytes_i(dut_data_valid_bytes), + .last_block_ad_i(dut_last_block_ad), + .last_block_msg_i(dut_last_block_msg), + .data_in_valid_i(dut_input_valid), + .data_in_ready_o(dut_ready_data), + + // Cipher Output Port + .data_out_o(dut_response_data), + // TODO: Test backpreasure + .data_out_ready_i(1'b1), + .data_out_valid_o(dut_response_data_valid), + + .tag_out_o(dut_response_tag), + .tag_out_valid_o(dut_response_tag_valid), + + .fsm_state_o(), + .err_o() + ); + + // Generate the runtime counter + int count_d, count_q; + assign count_d = count_q + 1; + always_ff @(posedge clk_i or negedge rst_ni) begin : reg_count + if (!rst_ni) begin + count_q <= 0; + end else begin + count_q <= count_d; + end + end + + initial begin + test_done_o = 1'b0; + test_passed_o = 1'b1; + end + + // Check responses, signal end of simulation + always_ff @(posedge clk_i or negedge rst_ni) begin : tb_ctrl + if (rst_ni && fsm_done) begin + if (OPERATION == ASCON_ENC) begin + if (actual_ct != expected_ct) begin + $display("\nERROR: Mismatch between DPI-based Ascon and Implementation found."); + test_passed_o <= 1'b0; + test_done_o <= 1'b1; + end + end else begin + if ((actual_msg != expected_msg) || (actual_tag != expected_tag)) begin + $display("\nERROR: Mismatch between DPI-based Ascon and Implementation found."); + test_passed_o <= 1'b0; + test_done_o <= 1'b1; + end + end + end + + if (count_q == NUMB_RUNS) begin + $display("\nSUCCESS: Outputs matches."); + test_done_o <= 1'b1; + end + end + +endmodule diff --git a/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_duplex_tb/rtl/prim_ascon_duplex_tb_pkg.sv b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_duplex_tb/rtl/prim_ascon_duplex_tb_pkg.sv new file mode 100644 index 0000000000..1d8b2d90cb --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_duplex_tb/rtl/prim_ascon_duplex_tb_pkg.sv @@ -0,0 +1,23 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +package prim_ascon_duplex_tb_pkg; + + +typedef enum { + Idle, + SendAD, + WaitADRead, + SendMSG, + CheckMSGLen, + WaitMSGRead, + ReceiveTag, + CheckCTLen, + SendCT, + WaitCTRead, + VerifyTag, + WaitForEver +} fsm_tb_state_e; + +endpackage : prim_ascon_duplex_tb_pkg diff --git a/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_round_tb/README.md b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_round_tb/README.md new file mode 100644 index 0000000000..f92ed8da2c --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_round_tb/README.md @@ -0,0 +1,30 @@ +Ascon Permutation Verilator Testbench +===================================== + +This directory contains a basic, scratch Verilator testbench targeting +functional verification of the Ascon permutation implementations during +development. + +How to build and run the testbench +---------------------------------- + +From the OpenTitan top level execute + + ```sh + fusesoc --cores-root=. run --setup --build lowrisc:dv_verilator:prim_ascon_round_tb + ``` +to build the testbench and afterwards + + ```sh + ./build/lowrisc_dv_verilator_prim_ascon_round_tb_0/default-verilator/Vprim_ascon_round_tb \ + --trace + ``` +to run it. + +Details of the testbench +------------------------ + +- `rtl/prim_ascon_round_tb.sv`: SystemVerilog testbench, signals test end and + result (pass/fail) to C++ via output ports. +- `cpp/prim_ascon_round_tb.cc`: Contains main function and instantiation of SimCtrl, + reads output ports of DUT and signals simulation termination to Verilator. diff --git a/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_round_tb/cpp/prim_ascon_round_tb.cc b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_round_tb/cpp/prim_ascon_round_tb.cc new file mode 100644 index 0000000000..7ab13300bd --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_round_tb/cpp/prim_ascon_round_tb.cc @@ -0,0 +1,57 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include +#include +#include + +#include "Vprim_ascon_round_tb.h" +#include "sim_ctrl_extension.h" +#include "verilated_toplevel.h" +#include "verilator_sim_ctrl.h" + +class PRIMASCONROUNDTB : public SimCtrlExtension { + using SimCtrlExtension::SimCtrlExtension; + + public: + PRIMASCONROUNDTB(prim_ascon_round_tb *top); + + void OnClock(unsigned long sim_time); + + private: + prim_ascon_round_tb *top_; +}; + +// Constructor: +// - Set up top_ ptr +PRIMASCONROUNDTB::PRIMASCONROUNDTB(prim_ascon_round_tb *top) + : SimCtrlExtension{}, top_(top) {} + +// Function called once every clock cycle from SimCtrl +void PRIMASCONROUNDTB::OnClock(unsigned long sim_time) { + if (top_->test_done_o) { + VerilatorSimCtrl::GetInstance().RequestStop(top_->test_passed_o); + } +} + +int main(int argc, char **argv) { + // Init verilog instance + prim_ascon_round_tb top; + + // Init sim + VerilatorSimCtrl &simctrl = VerilatorSimCtrl::GetInstance(); + simctrl.SetTop(&top, &top.clk_i, &top.rst_ni, + VerilatorSimCtrlFlags::ResetPolarityNegative); + + // Create and register VerilatorSimCtrl extension + PRIMASCONROUNDTB primasconroundtb(&top); + simctrl.RegisterExtension(&primasconroundtb); + + std::cout << "Simulation of Ascon Round" << std::endl + << "=========================" << std::endl + << std::endl; + + // Get pass / fail from Verilator + return simctrl.Exec(argc, argv).first; +} diff --git a/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_round_tb/prim_ascon_round_tb.core b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_round_tb/prim_ascon_round_tb.core new file mode 100644 index 0000000000..70d3fac7be --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_round_tb/prim_ascon_round_tb.core @@ -0,0 +1,52 @@ +CAPI=2: +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:dv_verilator:prim_ascon_round_tb" +description: "Ascon Permutation Verilator TB" +filesets: + files_rtl: + depend: + - lowrisc:prim:prim_ascon + - lowrisc:dv:ascon_model_dpi + files: + - rtl/prim_ascon_round_tb.sv + file_type: systemVerilogSource + + files_dv_verilator: + depend: + - lowrisc:dv_verilator:simutil_verilator + + files: + - cpp/prim_ascon_round_tb.cc + file_type: cppSource + +targets: + default: + default_tool: verilator + filesets: + - files_rtl + - files_dv_verilator + toplevel: prim_ascon_round_tb + tools: + verilator: + mode: cc + verilator_options: +# Disabling tracing reduces compile times by multiple times, but doesn't have a +# huge influence on runtime performance. (Based on early observations.) + - '--trace' + - '--trace-fst' # this requires -DVM_TRACE_FMT_FST in CFLAGS below! + - '--trace-structs' + - '--trace-params' + - '--trace-max-array 1024' +# compiler flags +# +# -O +# Optimization levels have a large impact on the runtime performance of the +# simulation model. -O2 and -O3 are pretty similar, -Os is slower than -O2/-O3 + - '-CFLAGS "-std=c++17 -Wall -DVM_TRACE_FMT_FST -DTOPLEVEL_NAME=prim_ascon_round_tb -g -O0"' + - '-LDFLAGS "-pthread -lutil -lelf"' + - "-Wall" + # XXX: Cleanup all warnings and remove this option + # (or make it more fine-grained at least) + - "-Wno-fatal" diff --git a/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_round_tb/rtl/prim_ascon_round_tb.sv b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_round_tb/rtl/prim_ascon_round_tb.sv new file mode 100644 index 0000000000..cd4a835104 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_ascon/prim_ascon_round_tb/rtl/prim_ascon_round_tb.sv @@ -0,0 +1,87 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Ascon Permutation testbench + +module prim_ascon_round_tb ( + input logic clk_i, + input logic rst_ni, + + output logic test_done_o, + output logic test_passed_o +); + + import ascon_model_dpi_pkg::*; + + parameter int NUMB_RUNS = 12; + localparam int ASCON_STATE_WIDTH = 320; + + int count_d, count_q; + logic [ASCON_STATE_WIDTH-1:0] stimulus; + logic [ASCON_STATE_WIDTH-1:0] response, response_golden; + + int round; + assign round = count_q; + + logic [7:0] rcon [12]; + assign rcon[ 0] = 'hf0; + assign rcon[ 1] = 'he1; + assign rcon[ 2] = 'hd2; + assign rcon[ 3] = 'hc3; + assign rcon[ 4] = 'hb4; + assign rcon[ 5] = 'ha5; + assign rcon[ 6] = 'h96; + assign rcon[ 7] = 'h87; + assign rcon[ 8] = 'h78; + assign rcon[ 9] = 'h69; + assign rcon[10] = 'h5a; + assign rcon[11] = 'h4b; + + // Generate the stimuli + assign count_d = count_q + 1; + always_ff @(posedge clk_i or negedge rst_ni) begin : reg_count + if (!rst_ni) begin + count_q <= 0; + stimulus <= '0; + end else begin + count_q <= count_d; + stimulus <= {32'hDEADBEEF, 32'hCAFEF00D, 32'hF0F0F0F0, + 32'hE0E0E0E0, 32'h12345678, 32'h9ABCDEF0, + $urandom, $urandom, $urandom, $urandom}; + end + end + + // Instantiate Ascon Round + prim_ascon_round ascon_round ( + .state_o (response), + .state_i (stimulus), + .rcon_i (rcon[round]) + ); + + always @(stimulus) begin : C_DPI + c_dpi_ascon_round(stimulus, rcon[round], response_golden); + end + + initial begin + test_done_o = 1'b0; + test_passed_o = 1'b1; + end + + // Check responses, signal end of simulation + always_ff @(posedge clk_i or negedge rst_ni) begin : tb_ctrl + if (rst_ni && (response_golden != response)) begin + $display("\nERROR: Mismatch between DPI-based Ascon and Implementation found."); + $display("stimulus = 320'h%h,\nexpected resp = 320'h%h,\nactual resp = 320'h%h\n", + stimulus, response_golden, response); + test_passed_o <= 1'b0; + test_done_o <= 1'b1; + end + + if (count_q == NUMB_RUNS) begin + $display("\nSUCCESS: Outputs matches."); + test_done_o <= 1'b1; + end + end + +endmodule diff --git a/vendor/lowrisc_ip/ip/prim/pre_dv/prim_crc32/prim_crc32_sim.core b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_crc32/prim_crc32_sim.core index 23118823d1..4a23eee7b1 100644 --- a/vendor/lowrisc_ip/ip/prim/pre_dv/prim_crc32/prim_crc32_sim.core +++ b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_crc32/prim_crc32_sim.core @@ -53,7 +53,7 @@ targets: - '--trace-structs' - '--trace-params' - '--trace-max-array 1024' - - '-CFLAGS "-std=c++11 -Wall -DVM_TRACE_FMT_FST -DTOPLEVEL_NAME=prim_crc32_sim"' + - '-CFLAGS "-std=c++17 -Wall -DVM_TRACE_FMT_FST -DTOPLEVEL_NAME=prim_crc32_sim"' - '-LDFLAGS "-pthread -lutil -lelf"' - "-Wall" # RAM primitives wider than 64bit (required for ECC) fail to build in diff --git a/vendor/lowrisc_ip/ip/prim/pre_dv/prim_flop_2sync/tb.sv b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_flop_2sync/tb.sv index 1ee9500401..5037bc921c 100644 --- a/vendor/lowrisc_ip/ip/prim/pre_dv/prim_flop_2sync/tb.sv +++ b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_flop_2sync/tb.sv @@ -27,7 +27,7 @@ module tb; clk_rst_if.apply_reset(.reset_width_clks(10)); $display("Using prim_cdc_rand_delay_mode slow"); - dut.u_prim_cdc_rand_delay.set_prim_cdc_rand_delay_mode(1); + dut.gen_generic.u_impl_generic.u_prim_cdc_rand_delay.set_prim_cdc_rand_delay_mode(1); repeat (100) begin src_d <= $urandom(); clk_rst_if.wait_clks($urandom_range(1, 20)); @@ -35,7 +35,7 @@ module tb; clk_rst_if.wait_clks(200); $display("Using prim_cdc_rand_delay_mode once"); - dut.u_prim_cdc_rand_delay.set_prim_cdc_rand_delay_mode(2); + dut.gen_generic.u_impl_generic.u_prim_cdc_rand_delay.set_prim_cdc_rand_delay_mode(2); repeat (100) begin src_d <= $urandom(); clk_rst_if.wait_clks($urandom_range(1, 20)); @@ -43,8 +43,8 @@ module tb; clk_rst_if.wait_clks(200); $display("Using prim_cdc_rand_delay_mode interval = 10"); - dut.u_prim_cdc_rand_delay.set_prim_cdc_rand_delay_mode(3); - dut.u_prim_cdc_rand_delay.set_prim_cdc_rand_delay_interval(10); + dut.gen_generic.u_impl_generic._prim_cdc_rand_delay.set_prim_cdc_rand_delay_mode(3); + dut.gen_generic.u_impl_generic.u_prim_cdc_rand_delay.set_prim_cdc_rand_delay_interval(10); repeat (100) begin src_d <= $urandom(); clk_rst_if.wait_clks($urandom_range(1, 20)); @@ -52,7 +52,7 @@ module tb; clk_rst_if.wait_clks(200); $display("Using prim_cdc_rand_delay_mode interval = 1"); - dut.u_prim_cdc_rand_delay.set_prim_cdc_rand_delay_interval(1); + dut.gen_generic.u_impl_generic.u_prim_cdc_rand_delay.set_prim_cdc_rand_delay_interval(1); repeat (100) begin src_d <= $urandom(); clk_rst_if.wait_clks($urandom_range(1, 20)); @@ -60,7 +60,7 @@ module tb; clk_rst_if.wait_clks(200); $display("Using prim_cdc_rand_delay_mode interval = 0"); - dut.u_prim_cdc_rand_delay.set_prim_cdc_rand_delay_interval(0); + dut.gen_generic.u_impl_generic.u_prim_cdc_rand_delay.set_prim_cdc_rand_delay_interval(0); repeat (100) begin src_d <= $urandom(); clk_rst_if.wait_clks($urandom_range(1, 20)); diff --git a/vendor/lowrisc_ip/ip/prim/pre_dv/prim_sync_reqack/prim_sync_reqack_tb.core b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_sync_reqack/prim_sync_reqack_tb.core index 21fd9adc3f..6c402cd306 100644 --- a/vendor/lowrisc_ip/ip/prim/pre_dv/prim_sync_reqack/prim_sync_reqack_tb.core +++ b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_sync_reqack/prim_sync_reqack_tb.core @@ -43,7 +43,7 @@ targets: # -O # Optimization levels have a large impact on the runtime performance of the # simulation model. -O2 and -O3 are pretty similar, -Os is slower than -O2/-O3 - - '-CFLAGS "-std=c++11 -Wall -DVM_TRACE_FMT_FST -DTOPLEVEL_NAME=prim_sync_reqack_tb -g -O0"' + - '-CFLAGS "-std=c++17 -Wall -DVM_TRACE_FMT_FST -DTOPLEVEL_NAME=prim_sync_reqack_tb -g -O0"' - '-LDFLAGS "-pthread -lutil -lelf"' - "-Wall" # XXX: Cleanup all warnings and remove this option diff --git a/vendor/lowrisc_ip/ip/prim/pre_dv/prim_trivium/prim_trivium_tb.core b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_trivium/prim_trivium_tb.core index f86d00c8ce..ad149c8637 100644 --- a/vendor/lowrisc_ip/ip/prim/pre_dv/prim_trivium/prim_trivium_tb.core +++ b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_trivium/prim_trivium_tb.core @@ -43,7 +43,7 @@ targets: # -O # Optimization levels have a large impact on the runtime performance of the # simulation model. -O2 and -O3 are pretty similar, -Os is slower than -O2/-O3 - - '-CFLAGS "-std=c++11 -Wall -DVM_TRACE_FMT_FST -DTOPLEVEL_NAME=prim_trivium_tb -g -O0"' + - '-CFLAGS "-std=c++17 -Wall -DVM_TRACE_FMT_FST -DTOPLEVEL_NAME=prim_trivium_tb -g -O0"' - '-LDFLAGS "-pthread -lutil -lelf"' - "-Wall" # XXX: Cleanup all warnings and remove this option diff --git a/vendor/lowrisc_ip/ip/prim/prim.core b/vendor/lowrisc_ip/ip/prim/prim.core index 5aa7a57ca5..befc14071f 100644 --- a/vendor/lowrisc_ip/ip/prim/prim.core +++ b/vendor/lowrisc_ip/ip/prim/prim.core @@ -13,13 +13,13 @@ filesets: - lowrisc:prim:util - lowrisc:prim:diff_decode # for prim_alert_sender/receiver - lowrisc:prim:pad_wrapper - - lowrisc:prim:prim_pkg - lowrisc:prim:clock_mux2 - lowrisc:prim:clock_inv - lowrisc:prim:buf - lowrisc:prim:flop - lowrisc:prim:flop_en - lowrisc:prim:flop_2sync + - lowrisc:prim:flop_no_rst - lowrisc:prim:rst_sync - lowrisc:prim:arbiter - lowrisc:prim:fifo diff --git a/vendor/lowrisc_ip/ip/prim/prim_clock_gp_mux2.core b/vendor/lowrisc_ip/ip/prim/prim_alert_to_diff.core similarity index 61% rename from vendor/lowrisc_ip/ip/prim/prim_clock_gp_mux2.core rename to vendor/lowrisc_ip/ip/prim/prim_alert_to_diff.core index 2c9894d465..0f60721cec 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_clock_gp_mux2.core +++ b/vendor/lowrisc_ip/ip/prim/prim_alert_to_diff.core @@ -3,14 +3,15 @@ CAPI=2: # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -name: "lowrisc:prim:clock_gp_mux2" -description: "2-input glitch free clock multiplexer" +name: "lowrisc:prim:alert_to_diff" +description: "Translate an alert to a differentially encoded signal" filesets: files_rtl: depend: - - lowrisc:prim:prim_pkg + - lowrisc:prim:diff_encode + - lowrisc:prim:alert files: - - rtl/prim_clock_gp_mux2.sv + - rtl/prim_alert_to_diff.sv file_type: systemVerilogSource targets: diff --git a/vendor/lowrisc_ip/ip/prim/prim_and2.core b/vendor/lowrisc_ip/ip/prim/prim_and2.core deleted file mode 100644 index 10cfee5c45..0000000000 --- a/vendor/lowrisc_ip/ip/prim/prim_and2.core +++ /dev/null @@ -1,48 +0,0 @@ -CAPI=2: -# Copyright lowRISC contributors (OpenTitan project). -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 - -name: "lowrisc:prim:and2" -description: "Generic 2-input and" -filesets: - primgen_dep: - depend: - - lowrisc:prim:prim_pkg - - lowrisc:prim:primgen - - lowrisc:prim:assert - - files_verilator_waiver: - depend: - # common waivers - - lowrisc:lint:common - file_type: vlt - - files_ascentlint_waiver: - depend: - # common waivers - - lowrisc:lint:common - files: - - lint/prim_and2.waiver - file_type: waiver - - files_veriblelint_waiver: - depend: - # common waivers - - lowrisc:lint:common - -generate: - impl: - generator: primgen - parameters: - prim_name: and2 - -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_arbiter.core b/vendor/lowrisc_ip/ip/prim/prim_arbiter.core index 784de057ff..7367391206 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_arbiter.core +++ b/vendor/lowrisc_ip/ip/prim/prim_arbiter.core @@ -9,6 +9,7 @@ filesets: files_rtl: depend: - lowrisc:prim:assert + - lowrisc:prim:leading_one_ppc files: - rtl/prim_arbiter_fixed.sv - rtl/prim_arbiter_ppc.sv diff --git a/vendor/lowrisc_ip/ip/prim/prim_ascon.core b/vendor/lowrisc_ip/ip/prim/prim_ascon.core new file mode 100644 index 0000000000..76a15c53ff --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/prim_ascon.core @@ -0,0 +1,76 @@ +CAPI=2: +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +name: "lowrisc:prim:prim_ascon:0.1" +description: "Ascon unit" +filesets: + files_rtl: + depend: + - lowrisc:prim:all + - lowrisc:prim:sparse_fsm + files: + - rtl/prim_ascon_round.sv + - rtl/prim_ascon_sbox.sv + - rtl/prim_ascon_pkg.sv + - rtl/prim_ascon_duplex.sv + file_type: systemVerilogSource + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + - lowrisc:lint:comportable + files: + - lint/prim_ascon.vlt + file_type: vlt + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + - lowrisc:lint:comportable + files: + - lint/prim_ascon.waiver + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + - lowrisc:lint:comportable + +parameters: + SYNTHESIS: + datatype: bool + paramtype: vlogdefine + +targets: + default: &default_target + filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) + - files_rtl + toplevel: ascon + + lint: + <<: *default_target + default_tool: verilator + parameters: + - SYNTHESIS=true + tools: + verilator: + mode: lint-only + verilator_options: + - "-Wall" + + syn: + <<: *default_target + # TODO: set default to DC once + # this option is available + # olofk/edalize#89 + default_tool: icarus + parameters: + - SYNTHESIS=true diff --git a/vendor/lowrisc_ip/ip/prim/prim_cdc_rand_delay.core b/vendor/lowrisc_ip/ip/prim/prim_cdc_rand_delay.core index 5ae1c71a76..ecbf9300b2 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_cdc_rand_delay.core +++ b/vendor/lowrisc_ip/ip/prim/prim_cdc_rand_delay.core @@ -9,7 +9,6 @@ filesets: files_rtl: depend: - lowrisc:prim:assert - - lowrisc:dv:dv_macros files: - rtl/prim_cdc_rand_delay.sv file_type: systemVerilogSource diff --git a/vendor/lowrisc_ip/ip/prim/prim_clock_buf.core b/vendor/lowrisc_ip/ip/prim/prim_clock_buf.core deleted file mode 100644 index 54b95ae1bf..0000000000 --- a/vendor/lowrisc_ip/ip/prim/prim_clock_buf.core +++ /dev/null @@ -1,47 +0,0 @@ -CAPI=2: -# Copyright lowRISC contributors (OpenTitan project). -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 - -name: "lowrisc:prim:clock_buf" -description: "Generic clock buffer" -filesets: - primgen_dep: - depend: - - lowrisc:prim:prim_pkg - - lowrisc:prim:primgen - - lowrisc:prim:assert - - files_verilator_waiver: - depend: - # common waivers - - lowrisc:lint:common - - 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 - -generate: - impl: - generator: primgen - parameters: - prim_name: clock_buf - -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_gating.core b/vendor/lowrisc_ip/ip/prim/prim_clock_gating.core deleted file mode 100644 index 04cf68bd1e..0000000000 --- a/vendor/lowrisc_ip/ip/prim/prim_clock_gating.core +++ /dev/null @@ -1,47 +0,0 @@ -CAPI=2: -# Copyright lowRISC contributors (OpenTitan project). -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 - -name: "lowrisc:prim:clock_gating" -description: "Clock gating primitives" -filesets: - primgen_dep: - depend: - - lowrisc:prim:prim_pkg - - lowrisc:prim:primgen - - - files_verilator_waiver: - depend: - # common waivers - - lowrisc:lint:common - - 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 - -generate: - impl: - generator: primgen - parameters: - prim_name: clock_gating - -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 deleted file mode 100644 index a6dcab935a..0000000000 --- a/vendor/lowrisc_ip/ip/prim/prim_clock_inv.core +++ /dev/null @@ -1,47 +0,0 @@ -CAPI=2: -# Copyright lowRISC contributors (OpenTitan project). -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 - -name: "lowrisc:prim:clock_inv" -description: "Clock inverter with scanmode bypass mux" -filesets: - primgen_dep: - depend: - - lowrisc:prim:prim_pkg - - lowrisc:prim:primgen - - - files_verilator_waiver: - depend: - # common waivers - - lowrisc:lint:common - - 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 - -generate: - impl: - generator: primgen - parameters: - prim_name: clock_inv - -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/util/primgen/prim_pkg.core.tpl b/vendor/lowrisc_ip/ip/prim/prim_diff_encode.core similarity index 68% rename from vendor/lowrisc_ip/ip/prim/util/primgen/prim_pkg.core.tpl rename to vendor/lowrisc_ip/ip/prim/prim_diff_encode.core index b51a34c5e0..9d5cdb5673 100644 --- a/vendor/lowrisc_ip/ip/prim/util/primgen/prim_pkg.core.tpl +++ b/vendor/lowrisc_ip/ip/prim/prim_diff_encode.core @@ -2,13 +2,14 @@ CAPI=2: # Copyright lowRISC contributors (OpenTitan project). # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -name: "lowrisc:prim_abstract:prim_pkg:0.1" -description: "Constants used by the primitives" - +name: "lowrisc:prim:diff_encode" +description: "prim diff encode" filesets: files_rtl: + depend: + - lowrisc:prim:flop files: - - prim_pkg.sv + - rtl/prim_diff_encode.sv file_type: systemVerilogSource targets: diff --git a/vendor/lowrisc_ip/ip/prim/prim_diff_to_alert.core b/vendor/lowrisc_ip/ip/prim/prim_diff_to_alert.core new file mode 100644 index 0000000000..d237172875 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/prim_diff_to_alert.core @@ -0,0 +1,21 @@ +CAPI=2: +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +name: "lowrisc:prim:diff_to_alert" +description: "Translate a differentially encoded signal to an alert" +filesets: + files_rtl: + depend: + - lowrisc:prim:flop_2sync + - lowrisc:prim:buf + - lowrisc:prim:alert + files: + - rtl/prim_diff_to_alert.sv + file_type: systemVerilogSource + +targets: + default: + filesets: + - files_rtl diff --git a/vendor/lowrisc_ip/ip/prim/prim_edge_detector.core b/vendor/lowrisc_ip/ip/prim/prim_edge_detector.core index f0b1437d23..15ca1e5bd1 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_edge_detector.core +++ b/vendor/lowrisc_ip/ip/prim/prim_edge_detector.core @@ -18,17 +18,11 @@ filesets: depend: # common waivers - lowrisc:lint:common - files: - - lint/prim.vlt - file_type: vlt files_ascentlint_waiver: depend: # common waivers - lowrisc:lint:common - files: - - lint/prim.waiver - file_type: waiver files_veriblelint_waiver: depend: diff --git a/vendor/lowrisc_ip/ip/prim/prim_fifo.core b/vendor/lowrisc_ip/ip/prim/prim_fifo.core index dd0fc7eb14..ba7de53adb 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_fifo.core +++ b/vendor/lowrisc_ip/ip/prim/prim_fifo.core @@ -11,12 +11,14 @@ filesets: - lowrisc:prim:assert - lowrisc:prim:util - lowrisc:prim:flop_2sync + - lowrisc:prim:count files: - rtl/prim_fifo_async_sram_adapter.sv - rtl/prim_fifo_async_simple.sv - rtl/prim_fifo_async.sv - rtl/prim_fifo_sync.sv - rtl/prim_fifo_sync_cnt.sv + - rtl/prim_fifo_assert.svh : {is_include_file : true} file_type: systemVerilogSource files_verilator_waiver: @@ -39,6 +41,9 @@ filesets: depend: # common waivers - lowrisc:lint:common + files: + - lint/prim_fifo.vbl + file_type: veribleLintWaiver targets: default: diff --git a/vendor/lowrisc_ip/ip/prim/prim_flash.core b/vendor/lowrisc_ip/ip/prim/prim_flash.core deleted file mode 100644 index 7e293a1dde..0000000000 --- a/vendor/lowrisc_ip/ip/prim/prim_flash.core +++ /dev/null @@ -1,52 +0,0 @@ -CAPI=2: -# Copyright lowRISC contributors (OpenTitan project). -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 - -name: "lowrisc:prim:flash" -description: "Flash memory" -filesets: - primgen_dep: - depend: - - lowrisc:prim:prim_pkg - - lowrisc:prim:primgen - # TODO olofk/fusesoc#404: The below dependency is already added to prim_generic_flash.core. - # However, the generator for the prim:ram1p does not kick in, causing compile errors. - - lowrisc:prim:ram_1p - - lowrisc:prim:clock_inv - - lowrisc:prim:clock_gating - - - files_verilator_waiver: - depend: - # common waivers - - lowrisc:lint:common - - 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 - -generate: - impl: - generator: primgen - parameters: - prim_name: flash - -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_gf_mult.core b/vendor/lowrisc_ip/ip/prim/prim_gf_mult.core index ccc94bb147..7bb155cdc9 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_gf_mult.core +++ b/vendor/lowrisc_ip/ip/prim/prim_gf_mult.core @@ -13,7 +13,17 @@ filesets: - rtl/prim_gf_mult.sv file_type: systemVerilogSource + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + - lint/prim_gf_mult.waiver + file_type: waiver + + targets: default: filesets: + - tool_ascentlint ? (files_ascentlint_waiver) - files_rtl diff --git a/vendor/lowrisc_ip/ip/prim/prim_flop_en.core b/vendor/lowrisc_ip/ip/prim/prim_leading_one_ppc.core similarity index 70% rename from vendor/lowrisc_ip/ip/prim/prim_flop_en.core rename to vendor/lowrisc_ip/ip/prim/prim_leading_one_ppc.core index 608384d18b..7591f05de6 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_flop_en.core +++ b/vendor/lowrisc_ip/ip/prim/prim_leading_one_ppc.core @@ -3,13 +3,15 @@ CAPI=2: # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -name: "lowrisc:prim:flop_en" -description: "Generic enable flop" +name: "lowrisc:prim:leading_one_ppc" +description: "Leading one computation using parallel prefix computation" filesets: - primgen_dep: + files_rtl: depend: - - lowrisc:prim:prim_pkg - - lowrisc:prim:primgen + - lowrisc:prim:util + files: + - rtl/prim_leading_one_ppc.sv + file_type: systemVerilogSource files_verilator_waiver: depend: @@ -21,8 +23,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - files: - - lint/prim_flop_en.waiver file_type: waiver files_veriblelint_waiver: @@ -30,18 +30,10 @@ filesets: # common waivers - lowrisc:lint:common -generate: - impl: - generator: primgen - parameters: - prim_name: flop_en - targets: default: filesets: - tool_verilator ? (files_verilator_waiver) - tool_ascentlint ? (files_ascentlint_waiver) - tool_veriblelint ? (files_veriblelint_waiver) - - primgen_dep - generate: - - impl + - files_rtl diff --git a/vendor/lowrisc_ip/ip/prim/prim_mubi.core b/vendor/lowrisc_ip/ip/prim/prim_mubi.core index 45aa85f7ae..f8d8cdd0b6 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_mubi.core +++ b/vendor/lowrisc_ip/ip/prim/prim_mubi.core @@ -16,8 +16,8 @@ filesets: - lowrisc:prim:assert - lowrisc:prim:buf - lowrisc:prim:flop + - lowrisc:prim:mubi_pkg files: - - rtl/prim_mubi_pkg.sv - rtl/prim_mubi4_sender.sv - rtl/prim_mubi4_sync.sv - rtl/prim_mubi4_dec.sv diff --git a/vendor/lowrisc_ip/ip/prim/prim_mubi_pkg.core b/vendor/lowrisc_ip/ip/prim/prim_mubi_pkg.core new file mode 100644 index 0000000000..57a1f61a2e --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/prim_mubi_pkg.core @@ -0,0 +1,45 @@ +CAPI=2: +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# ------------------- W A R N I N G: A U T O - G E N E R A T E D C O D E !! -------------------// +# PLEASE DO NOT HAND-EDIT THIS FILE. IT HAS BEEN AUTO-GENERATED WITH THE FOLLOWING COMMAND: +# +# util/design/gen-mubi.py +# +name: "lowrisc:prim:mubi_pkg:0.1" +description: "Multibit types and functions" +filesets: + files_rtl: + depend: + - lowrisc:prim:assert + files: + - rtl/prim_mubi_pkg.sv + file_type: systemVerilogSource + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + - lint/prim_mubi.waiver + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + +targets: + default: &default_target + 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/prim_onehot_check.core b/vendor/lowrisc_ip/ip/prim/prim_onehot_check.core index ed8a7aaf17..35643db4e4 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_onehot_check.core +++ b/vendor/lowrisc_ip/ip/prim/prim_onehot_check.core @@ -10,8 +10,6 @@ filesets: depend: - lowrisc:prim:util - lowrisc:prim:assert - # TODO: remove then #13337 is resolved. - - lowrisc:prim:prim_pkg files: - rtl/prim_onehot_check.sv file_type: systemVerilogSource diff --git a/vendor/lowrisc_ip/ip/prim/prim_otp.core b/vendor/lowrisc_ip/ip/prim/prim_otp.core deleted file mode 100644 index 90d0eca468..0000000000 --- a/vendor/lowrisc_ip/ip/prim/prim_otp.core +++ /dev/null @@ -1,50 +0,0 @@ -CAPI=2: -# Copyright lowRISC contributors (OpenTitan project). -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 - -name: "lowrisc:prim:otp" -description: "One-Time Programmable (OTP) memory" -filesets: - primgen_dep: - depend: - - lowrisc:prim:prim_pkg - - lowrisc:prim:primgen - # TODO(#6604): these two dependencies are needed to - # make sure the corresponding prims are generated by primgen. - - lowrisc:prim:clock_gating - - lowrisc:prim:clock_inv - - files_verilator_waiver: - depend: - # common waivers - - lowrisc:lint:common - - 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 - -generate: - impl: - generator: primgen - parameters: - prim_name: otp - -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_attr.core b/vendor/lowrisc_ip/ip/prim/prim_pad_attr.core deleted file mode 100644 index 10219fbfcb..0000000000 --- a/vendor/lowrisc_ip/ip/prim/prim_pad_attr.core +++ /dev/null @@ -1,48 +0,0 @@ -CAPI=2: -# Copyright lowRISC contributors (OpenTitan project). -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 - -name: "lowrisc:prim:pad_attr" -description: "PAD wrapper attributes" -filesets: - primgen_dep: - depend: - - lowrisc:prim:prim_pkg - - lowrisc:prim:pad_wrapper_pkg - - lowrisc:prim:primgen - - - files_verilator_waiver: - depend: - # common waivers - - lowrisc:lint:common - - files_ascentlint_waiver: - depend: - # common waivers - - lowrisc:lint:common - files: - - lint/prim_pad_attr.waiver - file_type: waiver - - files_veriblelint_waiver: - depend: - # common waivers - - lowrisc:lint:common - -generate: - impl: - generator: primgen - parameters: - prim_name: pad_attr - -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 deleted file mode 100644 index e700faf1ce..0000000000 --- a/vendor/lowrisc_ip/ip/prim/prim_pad_wrapper.core +++ /dev/null @@ -1,49 +0,0 @@ -CAPI=2: -# Copyright lowRISC contributors (OpenTitan project). -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 - -name: "lowrisc:prim:pad_wrapper" -description: "PAD wrapper" -filesets: - primgen_dep: - depend: - - lowrisc:prim:prim_pkg - - lowrisc:prim:pad_wrapper_pkg - - lowrisc:prim:primgen - - - files_verilator_waiver: - depend: - # common waivers - - lowrisc:lint:common - 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 - -generate: - impl: - generator: primgen - parameters: - prim_name: pad_wrapper - -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_pkg.core b/vendor/lowrisc_ip/ip/prim/prim_pkg.core deleted file mode 100644 index eea8326962..0000000000 --- a/vendor/lowrisc_ip/ip/prim/prim_pkg.core +++ /dev/null @@ -1,23 +0,0 @@ -CAPI=2: -# Copyright lowRISC contributors (OpenTitan project). -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 -name: "lowrisc:prim:prim_pkg:0.1" -description: "Constants used by the primitives" -filesets: - primgen_dep: - depend: - - lowrisc:prim:primgen - -generate: - impl: - generator: primgen - parameters: - action: generate_prim_pkg - -targets: - default: - filesets: - - primgen_dep - generate: - - impl diff --git a/vendor/lowrisc_ip/ip/prim/prim_buf.core b/vendor/lowrisc_ip/ip/prim/prim_racl_error_arb.core similarity index 69% rename from vendor/lowrisc_ip/ip/prim/prim_buf.core rename to vendor/lowrisc_ip/ip/prim/prim_racl_error_arb.core index 9f10e8d670..d350e02584 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_buf.core +++ b/vendor/lowrisc_ip/ip/prim/prim_racl_error_arb.core @@ -3,14 +3,16 @@ CAPI=2: # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -name: "lowrisc:prim:buf" -description: "Generic buffer" +name: "lowrisc:prim:racl_error_arb" +description: "RACL error arbiter" filesets: - primgen_dep: + files_rtl: depend: - - lowrisc:prim:prim_pkg - - lowrisc:prim:primgen - - lowrisc:prim:assert + - lowrisc:prim:arbiter + - lowrisc:virtual_constants:top_racl_pkg + files: + - rtl/prim_racl_error_arb.sv + file_type: systemVerilogSource files_verilator_waiver: depend: @@ -23,7 +25,7 @@ filesets: # common waivers - lowrisc:lint:common files: - - lint/prim_buf.waiver + - lint/prim_racl_error_arb.waiver file_type: waiver files_veriblelint_waiver: @@ -31,18 +33,10 @@ filesets: # common waivers - lowrisc:lint:common -generate: - impl: - generator: primgen - parameters: - prim_name: buf - targets: default: filesets: - tool_verilator ? (files_verilator_waiver) - tool_ascentlint ? (files_ascentlint_waiver) - tool_veriblelint ? (files_veriblelint_waiver) - - primgen_dep - generate: - - impl + - files_rtl diff --git a/vendor/lowrisc_ip/ip/prim/prim_ram_1p.core b/vendor/lowrisc_ip/ip/prim/prim_ram_1p.core deleted file mode 100644 index b12882c61c..0000000000 --- a/vendor/lowrisc_ip/ip/prim/prim_ram_1p.core +++ /dev/null @@ -1,48 +0,0 @@ -CAPI=2: -# Copyright lowRISC contributors (OpenTitan project). -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 - -name: "lowrisc:prim:ram_1p" -description: "1 port random-access memory" -filesets: - primgen_dep: - depend: - - lowrisc:prim:prim_pkg - - lowrisc:prim:ram_1p_pkg - - lowrisc:prim:primgen - - - files_verilator_waiver: - depend: - # common waivers - - lowrisc:lint:common - - 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 - -generate: - impl: - generator: primgen - parameters: - prim_name: ram_1p - -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_scr.core b/vendor/lowrisc_ip/ip/prim/prim_ram_1p_scr.core index dea8ca6774..e17b39afd9 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_ram_1p_scr.core +++ b/vendor/lowrisc_ip/ip/prim/prim_ram_1p_scr.core @@ -15,7 +15,6 @@ filesets: - lowrisc:prim:buf - lowrisc:prim:cipher - lowrisc:prim:util_get_scramble_params - - lowrisc:dv_verilator:memutil_dpi_scrambled files: - rtl/prim_ram_1p_scr.sv file_type: systemVerilogSource diff --git a/vendor/lowrisc_ip/ip/prim/prim_ram_1r1w.core b/vendor/lowrisc_ip/ip/prim/prim_ram_1r1w.core deleted file mode 100644 index 18acb86209..0000000000 --- a/vendor/lowrisc_ip/ip/prim/prim_ram_1r1w.core +++ /dev/null @@ -1,48 +0,0 @@ -CAPI=2: -# Copyright lowRISC contributors (OpenTitan project). -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 - -name: "lowrisc:prim:ram_1r1w" -description: "Random-access memory with 1 read-only port and 1 write-only port" -filesets: - primgen_dep: - depend: - - lowrisc:prim:prim_pkg - - lowrisc:prim:ram_2p_pkg - - lowrisc:prim:primgen - - - files_verilator_waiver: - depend: - # common waivers - - lowrisc:lint:common - - files_ascentlint_waiver: - depend: - # common waivers - - lowrisc:lint:common - files: - - lint/prim_ram_1r1w.waiver - file_type: waiver - - files_veriblelint_waiver: - depend: - # common waivers - - lowrisc:lint:common - -generate: - impl: - generator: primgen - parameters: - prim_name: ram_1r1w - -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_1r1w_async_adv.core b/vendor/lowrisc_ip/ip/prim/prim_ram_1r1w_async_adv.core index 6a4c35431b..a43f273119 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_ram_1r1w_async_adv.core +++ b/vendor/lowrisc_ip/ip/prim/prim_ram_1r1w_async_adv.core @@ -16,7 +16,28 @@ filesets: - rtl/prim_ram_1r1w_async_adv.sv file_type: systemVerilogSource + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + - lint/prim_ram_1r1w_async_adv.waiver + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + 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/prim_ram_2p.core b/vendor/lowrisc_ip/ip/prim/prim_ram_2p.core deleted file mode 100644 index 696c2248d6..0000000000 --- a/vendor/lowrisc_ip/ip/prim/prim_ram_2p.core +++ /dev/null @@ -1,48 +0,0 @@ -CAPI=2: -# Copyright lowRISC contributors (OpenTitan project). -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 - -name: "lowrisc:prim:ram_2p" -description: "2 port random-access memory" -filesets: - primgen_dep: - depend: - - lowrisc:prim:prim_pkg - - lowrisc:prim:ram_2p_pkg - - lowrisc:prim:primgen - - - files_verilator_waiver: - depend: - # common waivers - - lowrisc:lint:common - - 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 - -generate: - impl: - generator: primgen - parameters: - prim_name: ram_2p - -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 deleted file mode 100644 index 0aa76a4e31..0000000000 --- a/vendor/lowrisc_ip/ip/prim/prim_rom.core +++ /dev/null @@ -1,48 +0,0 @@ -CAPI=2: -# Copyright lowRISC contributors (OpenTitan project). -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 - -name: "lowrisc:prim:rom" -description: "Read-only memory (ROM)" -filesets: - primgen_dep: - depend: - - lowrisc:prim:prim_pkg - - lowrisc:prim:rom_pkg - - lowrisc:prim:primgen - - - files_verilator_waiver: - depend: - # common waivers - - lowrisc:lint:common - - 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 - -generate: - impl: - generator: primgen - parameters: - prim_name: rom - -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_adv.core b/vendor/lowrisc_ip/ip/prim/prim_rom_adv.core index fea85f95ff..e4ea1dc54c 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_rom_adv.core +++ b/vendor/lowrisc_ip/ip/prim/prim_rom_adv.core @@ -14,7 +14,17 @@ filesets: - rtl/prim_rom_adv.sv file_type: systemVerilogSource + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + - lowrisc:lint:comportable + files: + - lint/prim_rom_adv.waiver + file_type: waiver + targets: default: filesets: + - tool_ascentlint ? (files_ascentlint_waiver) - files_rtl diff --git a/vendor/lowrisc_ip/ip/prim/prim_sdc_example.core b/vendor/lowrisc_ip/ip/prim/prim_sdc_example.core new file mode 100644 index 0000000000..ca38ffe214 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/prim_sdc_example.core @@ -0,0 +1,34 @@ +CAPI=2: +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +name: "lowrisc:prim:sdc_example" +description: "Example module to verify constraints to keep redundant security features. This module is only used for synthesis" +filesets: + files_rtl: + depend: + - lowrisc:prim:all + - lowrisc:ip:lc_ctrl_pkg + - lowrisc:prim:clock_gating + - lowrisc:prim:lc_sender + - lowrisc:prim:lc_sync + files: + - rtl/prim_sdc_example.sv + file_type: systemVerilogSource + +parameters: + SYNTHESIS: + datatype: bool + paramtype: vlogdefine + +targets: + default: &default_target + filesets: + - files_rtl + syn: + <<: *default_target + default_tool: icarus + parameters: + - SYNTHESIS=true + toplevel: prim_sdc_example diff --git a/vendor/lowrisc_ip/ip/prim/prim_secded.core b/vendor/lowrisc_ip/ip/prim/prim_secded.core index 38cb2d36ac..a9ebaec7d7 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_secded.core +++ b/vendor/lowrisc_ip/ip/prim/prim_secded.core @@ -45,6 +45,7 @@ filesets: - rtl/prim_secded_inv_hamming_72_64_enc.sv - rtl/prim_secded_inv_hamming_76_68_dec.sv - rtl/prim_secded_inv_hamming_76_68_enc.sv + - rtl/prim_secded_inc.svh: {is_include_file: true} file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim/prim_usb_diff_rx.core b/vendor/lowrisc_ip/ip/prim/prim_usb_diff_rx.core deleted file mode 100644 index c323df0a2a..0000000000 --- a/vendor/lowrisc_ip/ip/prim/prim_usb_diff_rx.core +++ /dev/null @@ -1,48 +0,0 @@ -CAPI=2: -# Copyright lowRISC contributors (OpenTitan project). -# 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 - - lowrisc:prim:assert - - files_verilator_waiver: - depend: - # common waivers - - lowrisc:lint:common - 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 - -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/prim_util.core b/vendor/lowrisc_ip/ip/prim/prim_util.core index 1af57c66d5..5512c32923 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_util.core +++ b/vendor/lowrisc_ip/ip/prim/prim_util.core @@ -13,7 +13,16 @@ filesets: - rtl/prim_util_pkg.sv file_type: systemVerilogSource + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + - lint/prim_util.waiver + file_type: waiver + targets: default: filesets: + - tool_ascentlint ? (files_ascentlint_waiver) - files_rtl diff --git a/vendor/lowrisc_ip/ip/prim/prim_xnor2.core b/vendor/lowrisc_ip/ip/prim/prim_xnor2.core deleted file mode 100644 index becb3067a2..0000000000 --- a/vendor/lowrisc_ip/ip/prim/prim_xnor2.core +++ /dev/null @@ -1,48 +0,0 @@ -CAPI=2: -# Copyright lowRISC contributors (OpenTitan project). -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 - -name: "lowrisc:prim:xnor2" -description: "Generic 2-input xnor" -filesets: - primgen_dep: - depend: - - lowrisc:prim:prim_pkg - - lowrisc:prim:primgen - - lowrisc:prim:assert - - files_verilator_waiver: - depend: - # common waivers - - lowrisc:lint:common - file_type: vlt - - files_ascentlint_waiver: - depend: - # common waivers - - lowrisc:lint:common - files: - - lint/prim_xnor2.waiver - file_type: waiver - - files_veriblelint_waiver: - depend: - # common waivers - - lowrisc:lint:common - -generate: - impl: - generator: primgen - parameters: - prim_name: xnor2 - -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_xor2.core b/vendor/lowrisc_ip/ip/prim/prim_xor2.core deleted file mode 100644 index 7bf51d9f4c..0000000000 --- a/vendor/lowrisc_ip/ip/prim/prim_xor2.core +++ /dev/null @@ -1,48 +0,0 @@ -CAPI=2: -# Copyright lowRISC contributors (OpenTitan project). -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 - -name: "lowrisc:prim:xor2" -description: "Generic 2-input xor" -filesets: - primgen_dep: - depend: - - lowrisc:prim:prim_pkg - - lowrisc:prim:primgen - - lowrisc:prim:assert - - files_verilator_waiver: - depend: - # common waivers - - lowrisc:lint:common - file_type: vlt - - files_ascentlint_waiver: - depend: - # common waivers - - lowrisc:lint:common - files: - - lint/prim_xor2.waiver - file_type: waiver - - files_veriblelint_waiver: - depend: - # common waivers - - lowrisc:lint:common - -generate: - impl: - generator: primgen - parameters: - prim_name: xor2 - -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_receiver.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_alert_receiver.sv index 5ffc4a97ad..b532b1bdd9 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_alert_receiver.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_alert_receiver.sv @@ -34,7 +34,9 @@ module prim_alert_receiver import prim_mubi_pkg::mubi4_t; #( // enables additional synchronization logic - parameter bit AsyncOn = 1'b0 + parameter bit AsyncOn = 1'b0, + // Number of cycles a differential skew is tolerated on the differential alert signal. + parameter int unsigned SkewCycles = 1 ) ( input clk_i, input rst_ni, @@ -74,7 +76,8 @@ module prim_alert_receiver ); prim_diff_decode #( - .AsyncOn(AsyncOn) + .AsyncOn(AsyncOn), + .SkewCycles(SkewCycles) ) u_decode_alert ( .clk_i, .rst_ni, @@ -162,7 +165,7 @@ module prim_alert_receiver integ_fail_o = 1'b0; alert_o = 1'b0; send_init = 1'b0; - // by default, a ping request leads to a toogle on the differential ping pair + // by default, a ping request leads to a toggle on the differential ping pair send_ping = ping_rise; unique case (state_q) @@ -305,13 +308,13 @@ module prim_alert_receiver !(state_q inside {InitReq, InitAckWait}) && mubi4_test_false_loose(init_trig_i) |-> - ##[0:1] integ_fail_o) + ##[0:SkewCycles] integ_fail_o) `ASSERT(PingResponse1_A, ##1 $rose(alert_tx_i.alert_p) && (alert_tx_i.alert_p ^ alert_tx_i.alert_n) ##2 state_q == Idle && ping_pending_q |-> - ##[0:1] ping_ok_o, + ##[0:SkewCycles] ping_ok_o, clk_i, !rst_ni || integ_fail_o || mubi4_test_true_strict(init_trig_i)) // alert `ASSERT(Alert_A, @@ -320,7 +323,7 @@ module prim_alert_receiver state_q == Idle && !ping_pending_q |-> - ##[0:1] alert_o, + ##[0:SkewCycles] alert_o, clk_i, !rst_ni || integ_fail_o || mubi4_test_true_strict(init_trig_i)) end else begin : gen_sync_assert // signal integrity check propagation 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 9288758767..127bcdf203 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_alert_sender.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_alert_sender.sv @@ -14,7 +14,7 @@ // // In case the alert sender parameter IsFatal is set to 1, an incoming alert // alert_req_i is latched in a local register until the next reset, causing the -// alert sender to behave as if alert_req_i were continously asserted. +// alert sender to behave as if alert_req_i were continuously asserted. // The alert_state_o output reflects the state of this internal latching register. // // The alert sender also exposes an alert test input, which can be used to trigger @@ -46,6 +46,8 @@ module prim_alert_sender #( // enables additional synchronization logic parameter bit AsyncOn = 1'b1, + // Number of cycles a differential skew is tolerated on the differential ack/ping signal. + parameter int unsigned SkewCycles = 1, // alert sender will latch the incoming alert event permanently and // keep on sending alert events until the next reset. parameter bit IsFatal = 1'b0 @@ -82,7 +84,8 @@ module prim_alert_sender ); prim_diff_decode #( - .AsyncOn(AsyncOn) + .AsyncOn(AsyncOn), + .SkewCycles(SkewCycles) ) u_decode_ping ( .clk_i, .rst_ni, @@ -108,7 +111,8 @@ module prim_alert_sender ); prim_diff_decode #( - .AsyncOn(AsyncOn) + .AsyncOn(AsyncOn), + .SkewCycles(SkewCycles) ) u_decode_ack ( .clk_i, .rst_ni, @@ -309,18 +313,20 @@ module prim_alert_sender // check propagation of sigint issues to output within three cycles, or four due to CDC // shift sequence to the right to avoid reset effects. `ASSERT(SigIntPing_A, ##1 PingSigInt_S |-> - ##[3:4] alert_tx_o.alert_p == alert_tx_o.alert_n) + ##[SkewCycles+2:SkewCycles+3] alert_tx_o.alert_p == alert_tx_o.alert_n) `ASSERT(SigIntAck_A, ##1 AckSigInt_S |-> - ##[3:4] alert_tx_o.alert_p == alert_tx_o.alert_n) + ##[SkewCycles+2:SkewCycles+3] alert_tx_o.alert_p == alert_tx_o.alert_n) `endif // Test in-band FSM reset request (via signal integrity error) - `ASSERT(InBandInitFsm_A, PingSigInt_S or AckSigInt_S |-> ##[3:4] state_q == Idle) - `ASSERT(InBandInitPing_A, PingSigInt_S or AckSigInt_S |-> ##[3:4] !ping_set_q) + `ASSERT(InBandInitFsm_A, PingSigInt_S or AckSigInt_S |-> + ##[SkewCycles+2:SkewCycles+3] state_q == Idle) + `ASSERT(InBandInitPing_A, PingSigInt_S or AckSigInt_S |-> + ##[SkewCycles+2:SkewCycles+3] !ping_set_q) // output must be driven diff unless sigint issue detected `ASSERT(DiffEncoding_A, (alert_rx_i.ack_p ^ alert_rx_i.ack_n) && (alert_rx_i.ping_p ^ alert_rx_i.ping_n) |-> - ##[3:5] alert_tx_o.alert_p ^ alert_tx_o.alert_n) + ##[SkewCycles+2:SkewCycles+4] alert_tx_o.alert_p ^ alert_tx_o.alert_n) // handshakes can take indefinite time if blocked due to sigint on outgoing // lines (which is not visible here). thus, we only check whether the @@ -383,7 +389,7 @@ module prim_alert_sender `endif `ifdef FPV_ALERT_NO_SIGINT_ERR - // Assumptions for FPV security countermeasures to ensure the alert protocol functions collectly. + // Assumptions for FPV security countermeasures to ensure the alert protocol functions correctly. `ASSUME_FPV(AckPFollowsAlertP_S, alert_rx_i.ack_p == $past(alert_tx_o.alert_p)) `ASSUME_FPV(AckNFollowsAlertN_S, alert_rx_i.ack_n == $past(alert_tx_o.alert_n)) `ASSUME_FPV(TriggerAlertInit_S, $stable(rst_ni) == 0 |=> alert_rx_i.ping_p == alert_rx_i.ping_n) diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_alert_to_diff.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_alert_to_diff.sv new file mode 100644 index 0000000000..e8ba4ef81c --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_alert_to_diff.sv @@ -0,0 +1,63 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// prim_alert_to_diff: This module receives an alert signal (using the alert protocol) and +// translates it into a differentially encoded signal (without the alert protocol). +// It also handles integrity errors from the alert receiver, treating them as alerts. +// +// IMPORTANT: This primitive is NOT intended to be used in OpenTitan top-level designs. +// In top-level designs, prim_alert_{sender,receiver} pairs should be used instead. +// The intended use case of this primitive is to signal an alert through a differential +// encoding (for minimal integrity protection) to modules that do not support +// OpenTitan's alert protocol. + +module prim_alert_to_diff #( + // AsyncOn: Enables additional synchronization logic within the alert receiver. + parameter bit AsyncOn = 1'b0, + // Number of cycles a differential skew is tolerated on the alert signal + parameter int unsigned SkewCycles = 1 +) ( + input logic clk_i, + input logic rst_ni, + // Alert pair (interface signals for the alert protocol) + output prim_alert_pkg::alert_rx_t alert_rx_o, + input prim_alert_pkg::alert_tx_t alert_tx_i, + // Output diff pair (differentially encoded alert signal) + output logic diff_po, + output logic diff_no +); + + logic integ_error; + logic alert; + + // u_prim_alert_receiver: Instantiates the alert receiver module. + prim_alert_receiver #( + .AsyncOn(AsyncOn), + .SkewCycles(SkewCycles) + ) u_prim_alert_receiver ( + .clk_i, + .rst_ni, + .init_trig_i (prim_mubi_pkg::MuBi4False), + .ping_req_i (1'b0), + .ping_ok_o (), + .integ_fail_o (integ_error), + .alert_o (alert), + .alert_rx_o, + .alert_tx_i + ); + + // Combines the decoded alert and the integrity error signal. + // An alert is triggered if either a valid alert is received or an integrity error occurs. + logic combined_alert; + assign combined_alert = integ_error | alert; + + // Instantiates the differential encoder module. + prim_diff_encode u_prim_diff_encode ( + .clk_i, + .rst_ni, + .req_i(combined_alert), // Input request signal (combined alert). + .diff_po, + .diff_no + ); +endmodule 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 efe122e2ff..9e83b7c684 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_arbiter_fixed.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_arbiter_fixed.sv @@ -145,7 +145,7 @@ module prim_arbiter_fixed #( // Make sure no higher prio req is asserted `ASSERT(Priority_A, |req_i |-> req_i[idx_o] && (((N'(1'b1) << idx_o) - 1'b1) & req_i) == '0) - // we can only grant one requestor at a time + // we can only grant one requester at a time `ASSERT(CheckHotOne_A, $onehot0(gnt_o)) // A grant implies that the sink is ready `ASSERT(GntImpliesReady_A, |gnt_o |-> ready_i) diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_arbiter_ppc.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_arbiter_ppc.sv index ddd70173d3..f0e5e3dcb2 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_arbiter_ppc.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_arbiter_ppc.sv @@ -65,7 +65,6 @@ module prim_arbiter_ppc #( assign idx_o = '0; end else begin : gen_normal_case - logic [N-1:0] masked_req; logic [N-1:0] ppc_out; logic [N-1:0] arb_req; @@ -75,20 +74,15 @@ module prim_arbiter_ppc #( assign masked_req = mask & req_i; assign arb_req = (|masked_req) ? masked_req : req_i; - // PPC - // Even below code looks O(n) but DC optimizes it to O(log(N)) - // Using Parallel Prefix Computation - always_comb begin - ppc_out[0] = arb_req[0]; - for (int i = 1 ; i < N ; i++) begin - ppc_out[i] = ppc_out[i-1] | arb_req[i]; - end - end - - // Grant Generation: Leading-One detector - assign winner = ppc_out ^ {ppc_out[N-2:0], 1'b0}; - assign gnt_o = (ready_i) ? winner : '0; - + prim_leading_one_ppc #( + .N ( N ) + ) u_leading_one ( + .in_i ( arb_req ), + .leading_one_o ( winner ), + .ppc_out_o ( ppc_out ), + .idx_o ( idx_o ) + ); + assign gnt_o = (ready_i) ? winner : '0; assign valid_o = |req_i; // Mask Generation assign mask_next = {ppc_out[N-2:0], 1'b0}; @@ -119,15 +113,6 @@ module prim_arbiter_ppc #( logic [DW-1:0] unused_data [N]; assign unused_data = data_i; end - - always_comb begin - idx_o = '0; - for (int unsigned i = 0 ; i < N ; i++) begin - if (winner[i]) begin - idx_o = i[IdxW-1:0]; - end - end - end end //////////////// @@ -145,7 +130,7 @@ module prim_arbiter_ppc #( ##1 valid_o && ready_i && $past(ready_i) && $past(valid_o) && |(req_i & ~((N'(1) << $past(idx_o)+1) - 1)) |-> idx_o > $past(idx_o)) - // we can only grant one requestor at a time + // we can only grant one requester at a time `ASSERT(CheckHotOne_A, $onehot0(gnt_o)) // A grant implies that the sink is ready `ASSERT(GntImpliesReady_A, |gnt_o |-> ready_i) @@ -185,7 +170,7 @@ end `ASSUME(KStable_M, ##1 $stable(k)) `ASSUME(KRange_M, k < N) // this is used enable checking for stable and unstable ready_i and req_i signals in the same run. - // the symbolic variables act like a switch that the solver can trun on and off. + // the symbolic variables act like a switch that the solver can turn on and off. `ASSUME(ReadyIsStable_M, ##1 $stable(ReadyIsStable)) `ASSUME(ReqsAreStable_M, ##1 $stable(ReqsAreStable)) `ASSUME(ReadyStable_M, ##1 !ReadyIsStable || $stable(ready_i)) 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 712eb8bfb6..baabc99845 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_arbiter_tree.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_arbiter_tree.sv @@ -17,7 +17,7 @@ // each node of the arbiter tree. This means that the data can propagate through the tree // simultaneously with the requests, instead of waiting for the arbitration to determine the winner // index first. As a result, this design has a shorter critical path than other implementations, -// leading to better ovberall timing. +// leading to better overall timing. // // Note that the currently winning request is held if the data sink is not ready. This behavior is // required by some interconnect protocols (AXI, TL). The module contains an assertion that checks @@ -156,7 +156,7 @@ module prim_arbiter_tree #( assign data_tree[Pa] = (sel) ? data_tree[C1] : data_tree[C0]; // backward path (grants and prefix sum) - // this propagates the selction index back and computes a hot one mask + // this propagates the selection index back and computes a hot one mask assign sel_tree[C0] = sel_tree[Pa] & ~sel; assign sel_tree[C1] = sel_tree[Pa] & sel; // this performs a prefix sum for masking the input requests in the next cycle @@ -211,7 +211,7 @@ module prim_arbiter_tree #( ##1 valid_o && ready_i && $past(ready_i) && $past(valid_o) && |(req_i & ~((N'(1) << $past(idx_o)+1) - 1)) |-> idx_o > $past(idx_o)) - // we can only grant one requestor at a time + // we can only grant one requester at a time `ASSERT(CheckHotOne_A, $onehot0(gnt_o)) // A grant implies that the sink is ready `ASSERT(GntImpliesReady_A, |gnt_o |-> ready_i) @@ -251,7 +251,7 @@ end `ASSUME(KStable_M, ##1 $stable(k)) `ASSUME(KRange_M, k < N) // this is used enable checking for stable and unstable ready_i and req_i signals in the same run. - // the symbolic variables act like a switch that the solver can trun on and off. + // the symbolic variables act like a switch that the solver can turn on and off. `ASSUME(ReadyIsStable_M, ##1 $stable(ReadyIsStable)) `ASSUME(ReqsAreStable_M, ##1 $stable(ReqsAreStable)) `ASSUME(ReadyStable_M, ##1 !ReadyIsStable || $stable(ready_i)) diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_ascon_duplex.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_ascon_duplex.sv new file mode 100644 index 0000000000..2cbb7935b4 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_ascon_duplex.sv @@ -0,0 +1,621 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Ascon duplex function implementation + +// Ascon uses big endian encoding! +// Thus prim_ascon_duplex expects partial input blocks to fill up from left to right. +// This means data_in_i[127:120] must always be set for non empty inputs! + +// TODO: Add countermeasures: mubi for control signals, +// random values for state_to_round input, blinding for output signals +// TODO: Add backpressure logic, if output is not ready +// TODO: Add check what to do, if data_in_valid_bytes_i is greater than blocksize + +module prim_ascon_duplex + import prim_ascon_pkg::*; + ( + input logic clk_i, + input logic rst_ni, + + input duplex_variant_e ascon_variant, + input duplex_op_e ascon_operation, + + input logic start_i, + output logic done_o, + + output prim_mubi_pkg::mubi4_t idle_o, + + // It is assumed that no_ad, no_msg, key, and nonce are always + // valid and constant, when the cipher is triggered by the start command + input prim_mubi_pkg::mubi4_t no_ad_i, + input prim_mubi_pkg::mubi4_t no_msg_i, + + input logic [127:0] key_i, + input logic [127:0] nonce_i, + + // Cipher Input Port + input logic [127:0] data_in_i, + input logic [4:0] data_in_valid_bytes_i, + input prim_mubi_pkg::mubi4_t last_block_ad_i, + input prim_mubi_pkg::mubi4_t last_block_msg_i, + input logic data_in_valid_i, + output logic data_in_ready_o, + + // Cipher Output Port + output logic [127:0] data_out_o, + input logic data_out_ready_i, + output logic data_out_valid_o, + + output logic [127:0] tag_out_o, + output logic tag_out_valid_o, + + output duplex_fsm_state_e fsm_state_o, + + output logic err_o +); + +// TODO: Add backpressure check +logic unused_data_out_ready_i; +assign unused_data_out_ready_i = data_out_ready_i; + +logic round_count_error; +logic sparse_fsm_error; + +logic set_round_counter; +logic inc_round_counter; + +logic [4:0][63:0] ascon_state_q, ascon_state_d; + +// Ascon's 320 bit state +always_ff @(posedge clk_i or negedge rst_ni) begin : ascon_state_reg + if (!rst_ni) begin + ascon_state_q <= '0; + end else begin + ascon_state_q <= ascon_state_d; + end +end + +logic [319:0] state_to_round; +logic [319:0] state_from_round; + +logic [4:0][63:0] round_to_mux; +assign round_to_mux = state_from_round; + +duplex_fsm_state_e fsm_state_d, fsm_state_q; +perm_offset_e perm_offset; + +assign fsm_state_o = fsm_state_q; + +logic [63:0] iv; +assign iv = (ascon_variant == ASCON_128) ? IV_128 : IV_128A; + +// internal combinatorial signals +prim_mubi_pkg::mubi4_t complete_block; + +// TODO add a check what to do, if data_in_valid_bytes_i is greater than blocksize +assign complete_block = (ascon_variant == ASCON_128 && data_in_valid_bytes_i == 8) + ||(ascon_variant == ASCON_128A && data_in_valid_bytes_i == 16) ? + prim_mubi_pkg::MuBi4True : prim_mubi_pkg::MuBi4False; + +// Padding: +// 1) Associated Data +// a) empty AD: No padding, AD-processing phase is skipped! +// b) incomplete last block: A 10* padding is added to the input data. +// The padded associated data is XORed to the state. +// c) complete last block: No padding to the input, but an additional state in the FSM +// is used to perform the padding. A 10+ block is XORed to the state. +// 2) Encryption: +// a) empty or incomplete last block: A 10* padding is added to the input data. +// The padded associated data is XORed blockwise. +// b) complete last block: No padding to the input, but an additional state in the FSM +// is used to perform the padding. A 10+ block is XORed to the sate. +// 3) Decryption: +// a) empty or incomplete last block: The padded (output) PLAINTEXT is XORed to the state. +// This is equivalent to: +// The unpadded part of the Ciphertext replaces the corresponding part of S_r +// The remaining part of S_r is Xored with 10*. +// b) complete last block: No padding to the input, but an additional state in the FSM +// is used to perform the padding. A 10+ block is XORed to the state, + +// Padding logic +logic [127:0] empty_padding; +assign empty_padding = get_padding_mask(5'b00000); + +logic [127:0] valid_bytes_bit_mask; +assign valid_bytes_bit_mask = bin2thermo(data_in_valid_bytes_i); + +logic [127:0] padding_byte_bit_mask; +assign padding_byte_bit_mask = get_padding_mask(data_in_valid_bytes_i); + +logic [127:0] data_in_valid_bytes; +assign data_in_valid_bytes = data_in_i & valid_bytes_bit_mask; + +// data output +logic [127:0] data_out; +assign data_out = (data_in_i ^ {ascon_state_q[0], ascon_state_q[1]}) & valid_bytes_bit_mask; + +logic [127:0] data_in_padded; +logic [127:0] data_out_padded; // is only used internally for decryption. + +// For BOTH encryption AND decryption the PLAINTEXT is XORed to the state! +// For encryption this is straight forward: S_r = S_r XOR P +// For decryption this means: S_r = S_r XOR P = S_r XOR (S_r XOR C) = C +// Thus the ciphertext replaces the rate. However, we cannot simply implement +// S_r = C, because this does not work for incomplete blocks, where only a part +// of the rate is replaced by C and the other part remains: +// S_r = S_l || S_(r-l) = C_l || S_(r-l) +// Therefore, it is easier to always XOR the padded plaintext + +always_comb begin + if (prim_mubi_pkg::mubi4_test_true_strict(complete_block)) begin + data_in_padded = data_in_valid_bytes; + data_out_padded = data_out; + end else begin + data_in_padded = data_in_valid_bytes | padding_byte_bit_mask; + data_out_padded = data_out | padding_byte_bit_mask; + end +end + +// TODO add blinding +assign data_out_o = data_out; +assign tag_out_o = ({ascon_state_q[3], ascon_state_q[4]} ^ key_i); + +// Due to Ascon's round constants the current_round +// contains an offset: +// for P12 we count: from 0 to 11 = 12 rounds, +// for P8 we count: from 4 to 11 = 8 rounds, +// for P6 we count: from 5 to 11 = 6 rounds +logic [AsconRoundCountW-1:0] current_round; + +prim_count #( + .Width(AsconRoundCountW) +) u_round_counter ( + .clk_i, + .rst_ni, + .clr_i(1'b0), + .set_i(set_round_counter), + .set_cnt_i(perm_offset), + .incr_en_i(inc_round_counter), + .decr_en_i(1'b0), + .step_i(AsconRoundCountW'(1)), + .commit_i(1'b1), + .cnt_o(current_round), + .cnt_after_commit_o(), + .err_o(round_count_error) + ); + +// Duplexswitch muxes +// Selects data input source +padding_mux_e sel_padding; + +// Main multiplexer per word +ascon_word_mux_e sel_mux_word0; +ascon_word_mux_e sel_mux_word1; +ascon_word_mux_e sel_mux_word2; +ascon_word_mux_e sel_mux_word3; +ascon_word_mux_e sel_mux_word4; + +// Multiplexer before XOR +word_low_key_hi_mux_e sel_mux_key_word1; +key_hi_low_mux_e sel_mux_key_word2; +key_hi_low_mux_e sel_mux_key_word3; + +// Selects round input +ascon_round_input_mux_e sel_round_input; + +// Set domain separation +logic set_dom_sep; + +// Intermediate signals +logic [4:0][63:0] xor_with_state; +logic [63:0] word4_dom_sep; +logic [127:0] data_to_duplex; + +// Enc Dec Padding Mux +always_comb begin : Padding + unique case (sel_padding) + DATA_IN_PAD: data_to_duplex = data_in_padded; + DATA_OUT_PAD: data_to_duplex = data_out_padded; + EMPTY_PAD: data_to_duplex = empty_padding; + default: data_to_duplex = empty_padding; + endcase +end + +// State input mux +always_comb begin : state_input + unique case (sel_round_input) + STATE: state_to_round = ascon_state_q; + BLINDING: state_to_round = '0; + default: state_to_round = '0; + endcase +end + +// Main mux word0 +assign xor_with_state[0] = data_to_duplex[127:64]; +always_comb begin : state_word0 + unique case (sel_mux_word0) + INIT: ascon_state_d[0] = iv; + ABSORB: ascon_state_d[0] = ascon_state_q[0] ^ xor_with_state[0]; + KEEP: ascon_state_d[0] = ascon_state_q[0]; + ROUND: ascon_state_d[0] = round_to_mux[0]; + default: ascon_state_d[0] = ascon_state_q[0]; + endcase +end + +// Select key high or data low for XOR +always_comb begin : key_word1 + unique case (sel_mux_key_word1) + WORD: xor_with_state[1] = data_to_duplex[63:0]; + KEY: xor_with_state[1] = key_i[127:64]; + default: xor_with_state[1] = key_i[127:64]; + endcase +end + +// Main mux word1 +always_comb begin : state_word1 + unique case (sel_mux_word1) + INIT: ascon_state_d[1] = key_i[127:64]; + ABSORB: ascon_state_d[1] = ascon_state_q[1] ^ xor_with_state[1]; + KEEP: ascon_state_d[1] = ascon_state_q[1]; + ROUND: ascon_state_d[1] = round_to_mux[1]; + default: ascon_state_d[1] = ascon_state_q[1]; + endcase +end + +// Select key high or low for XOR +always_comb begin : key_word2 + unique case (sel_mux_key_word2) + KEY_LOW: xor_with_state[2] = key_i[63:0]; + KEY_HI: xor_with_state[2] = key_i[127:64]; + default: xor_with_state[2] = key_i[127:64]; + endcase +end + +// Main mux word2 +always_comb begin : state_word2 + unique case (sel_mux_word2) + INIT: ascon_state_d[2] = key_i[63:0]; + ABSORB: ascon_state_d[2] = ascon_state_q[2] ^ xor_with_state[2]; + KEEP : ascon_state_d[2] = ascon_state_q[2]; + ROUND: ascon_state_d[2] = round_to_mux[2]; + default: ascon_state_d[2] = ascon_state_q[2]; + endcase +end + +// Select key high or low for XOR +always_comb begin : key_word3 + unique case (sel_mux_key_word3) + KEY_LOW: xor_with_state[3] = key_i[63:0]; + KEY_HI: xor_with_state[3] = key_i[127:64]; + default: xor_with_state[3] = key_i[127:64]; + endcase +end + +// Main mux word3 +always_comb begin : state_word3 + unique case (sel_mux_word3) + INIT: ascon_state_d[3] = nonce_i[127:64]; + ABSORB: ascon_state_d[3] = ascon_state_q[3] ^ xor_with_state[3]; + KEEP: ascon_state_d[3] = ascon_state_q[3]; + ROUND: ascon_state_d[3] = round_to_mux[3]; + default: ascon_state_d[3] = ascon_state_q[3]; + endcase +end + +// Set domain separation bit +assign word4_dom_sep = {ascon_state_q[4][63:1], ascon_state_q[4][0] ^ set_dom_sep}; +// For word 4 only the lower part of the key can be xored to the state +assign xor_with_state[4] = key_i[63:0]; + +// Main mux word4 +always_comb begin : state_word4 + unique case (sel_mux_word4) + INIT: ascon_state_d[4] = nonce_i[63:0]; + ABSORB: ascon_state_d[4] = word4_dom_sep ^ xor_with_state[4]; + KEEP: ascon_state_d[4] = word4_dom_sep; + ROUND: ascon_state_d[4] = round_to_mux[4]; + default: ascon_state_d[4] = word4_dom_sep; + endcase +end + +always_comb begin : p_fsm + // Default assignments + fsm_state_d = fsm_state_q; + data_in_ready_o = 1'b0; + data_out_valid_o = 1'b0; + tag_out_valid_o = 1'b0; + sparse_fsm_error = 1'b0; + set_round_counter = 1'b0; + inc_round_counter = 1'b0; + perm_offset = P12; + done_o = 1'b0; + idle_o = prim_mubi_pkg::MuBi4False; + + // Default: Don't update state + set_dom_sep = 1'b0; + sel_mux_word0 = KEEP; + sel_mux_word1 = KEEP; + sel_mux_word2 = KEEP; + sel_mux_word3 = KEEP; + sel_mux_word4 = KEEP; + + sel_mux_key_word3 = KEY_HI; + sel_mux_key_word2 = KEY_LOW; + sel_mux_key_word1 = KEY; + + sel_padding = EMPTY_PAD; + + sel_round_input = BLINDING; + + unique case (fsm_state_q) + Idle: begin + idle_o = prim_mubi_pkg::MuBi4True; + if (start_i) begin + fsm_state_d = Init; + end + end + Init: begin + sel_mux_word0 = INIT; + sel_mux_word1 = INIT; + sel_mux_word2 = INIT; + sel_mux_word3 = INIT; + sel_mux_word4 = INIT; + fsm_state_d = PermInit; + perm_offset = P12; + set_round_counter = 1'b1; + end + PermInit: begin + sel_round_input = STATE; + sel_mux_word0 = ROUND; + sel_mux_word1 = ROUND; + sel_mux_word2 = ROUND; + sel_mux_word3 = ROUND; + sel_mux_word4 = ROUND; + if (current_round == ROUND_MAX) begin + fsm_state_d = Xor0Key; + end else begin + inc_round_counter = 1'b1; + end + end + Xor0Key: begin + sel_mux_word3 = ABSORB; + sel_mux_key_word3 = KEY_HI; + sel_mux_word4 = ABSORB; + if (prim_mubi_pkg::mubi4_test_true_strict(no_ad_i)) begin + fsm_state_d = XorDomSep; + end else begin + fsm_state_d = AbsorbAD; + end + end + AbsorbAD: begin + // There will be AD, otherwise we wouldn't be in this state/path + data_in_ready_o = 1'b1; + if (data_in_valid_i) begin + sel_mux_word0 = ABSORB; + sel_padding = DATA_IN_PAD; + if (ascon_variant == ASCON_128A) begin + sel_mux_word1 = ABSORB; + sel_mux_key_word1 = WORD; + end + if (prim_mubi_pkg::mubi4_test_true_strict(last_block_ad_i)) begin + if (prim_mubi_pkg::mubi4_test_true_strict(complete_block)) begin + fsm_state_d = PermADEmpty; + end else begin + fsm_state_d = PermADLast; + end + end else begin // there are more blocks to come + fsm_state_d = PermAD; + end + end + if (ascon_variant == ASCON_128) begin + perm_offset = P6; + end else begin //ASCON_128A + perm_offset = P8; + end + set_round_counter = 1'b1; + end + PermAD: begin + sel_round_input = STATE; + sel_mux_word0 = ROUND; + sel_mux_word1 = ROUND; + sel_mux_word2 = ROUND; + sel_mux_word3 = ROUND; + sel_mux_word4 = ROUND; + if (current_round == ROUND_MAX) begin + fsm_state_d = AbsorbAD; + end else begin + inc_round_counter = 1'b1; + end + end + PermADLast: begin + sel_round_input = STATE; + sel_mux_word0 = ROUND; + sel_mux_word1 = ROUND; + sel_mux_word2 = ROUND; + sel_mux_word3 = ROUND; + sel_mux_word4 = ROUND; + if (current_round == ROUND_MAX) begin + fsm_state_d = XorDomSep; + end else begin + inc_round_counter = 1'b1; + end + end + PermADEmpty: begin + sel_round_input = STATE; + sel_mux_word0 = ROUND; + sel_mux_word1 = ROUND; + sel_mux_word2 = ROUND; + sel_mux_word3 = ROUND; + sel_mux_word4 = ROUND; + if (current_round == ROUND_MAX) begin + fsm_state_d = AbsorbADEmpty; + end else begin + inc_round_counter = 1'b1; + end + end + AbsorbADEmpty: begin + sel_mux_word0 = ABSORB; + sel_padding = EMPTY_PAD; + fsm_state_d = PermADLast; + if (ascon_variant == ASCON_128) begin + perm_offset = P6; + end else begin //ASCON_128A + perm_offset = P8; + // This should be optimized by the tool. + // It is left here, so that the structure of the case + // is the same as AbsorbAD. + sel_mux_word1 = ABSORB; + sel_padding = EMPTY_PAD; + end + set_round_counter = 1'b1; + end + XorDomSep: begin + set_dom_sep = 1'b1; + sel_mux_word4 = KEEP; + if (prim_mubi_pkg::mubi4_test_true_strict(no_msg_i)) begin + fsm_state_d = AbsorbMSGEmpty; + end else begin + fsm_state_d = AbsorbMSG; + end + end + AbsorbMSG: begin + data_in_ready_o = 1'b1; + if (data_in_valid_i) begin + data_out_valid_o = 1'b1; + if (ascon_operation == ASCON_ENC) begin + sel_mux_word0 = ABSORB; + sel_padding = DATA_IN_PAD; + if (ascon_variant == ASCON_128A) begin + sel_mux_word1 = ABSORB; + end + end else begin // ASCON_DEC + sel_mux_word0 = ABSORB; + sel_padding = DATA_OUT_PAD; + if (ascon_variant == ASCON_128A) begin + sel_mux_word1 = ABSORB; + sel_mux_key_word1 = WORD; + end + end + if (prim_mubi_pkg::mubi4_test_true_strict(last_block_msg_i)) begin + if (prim_mubi_pkg::mubi4_test_true_strict(complete_block)) begin // we need extra padding + fsm_state_d = PermMSGEmpty; + end else begin // padding is done on the fly + fsm_state_d = XorKey0; + end + end else begin + fsm_state_d = PermMSG; + end + end + + if (ascon_variant == ASCON_128) begin + perm_offset = P6; + end else begin //ASCON_128A + perm_offset = P8; + end + set_round_counter = 1'b1; + end + PermMSG: begin + sel_round_input = STATE; + sel_mux_word0 = ROUND; + sel_mux_word1 = ROUND; + sel_mux_word2 = ROUND; + sel_mux_word3 = ROUND; + sel_mux_word4 = ROUND; + if (current_round == ROUND_MAX) begin + fsm_state_d = AbsorbMSG; + end else begin + inc_round_counter = 1'b1; + end + end + PermMSGEmpty: begin + sel_round_input = STATE; + sel_mux_word0 = ROUND; + sel_mux_word1 = ROUND; + sel_mux_word2 = ROUND; + sel_mux_word3 = ROUND; + sel_mux_word4 = ROUND; + if (current_round == ROUND_MAX) begin + fsm_state_d = AbsorbMSGEmpty; + end else begin + inc_round_counter = 1'b1; + end + end + AbsorbMSGEmpty: begin + // The padding for an empty block is the same for encryption and decryption. + sel_padding = EMPTY_PAD; + sel_mux_word0 = ABSORB; + if (ascon_variant == ASCON_128A) begin + // This should be optimized by the tool. + // It is left here, so that the structure of the case + // is the same as AbsorbAD. + sel_mux_word1 = ABSORB; + sel_mux_key_word1 = WORD; + end + fsm_state_d = XorKey0; + end + XorKey0: begin + if (ascon_variant == ASCON_128) begin + sel_mux_word1 = ABSORB; + sel_mux_key_word1 = KEY; + sel_mux_word2 = ABSORB; + sel_mux_key_word2 = KEY_LOW; + end else begin //ASCON_128a + sel_mux_word2 = ABSORB; + sel_mux_key_word2 = KEY_HI; + sel_mux_word3 = ABSORB; + sel_mux_key_word3 = KEY_LOW; + end + fsm_state_d = PermFinal; + set_round_counter = 1'b1; + perm_offset = P12; + end + PermFinal: begin + sel_round_input = STATE; + sel_mux_word0 = ROUND; + sel_mux_word1 = ROUND; + sel_mux_word2 = ROUND; + sel_mux_word3 = ROUND; + sel_mux_word4 = ROUND; + if (current_round == ROUND_MAX) begin + fsm_state_d = SqueezeTagXorKey; + end else begin + inc_round_counter = 1'b1; + end + end + SqueezeTagXorKey: begin + tag_out_valid_o = 1'b1; + fsm_state_d = Idle; + done_o = 1'b1; + end + Error: begin + fsm_state_d = Error; + sparse_fsm_error = 1'b1; + end + default: begin + fsm_state_d = Error; + sparse_fsm_error = 1'b1; + end + endcase +end + +`PRIM_FLOP_SPARSE_FSM(u_state_regs, fsm_state_d, fsm_state_q, duplex_fsm_state_e, Idle) + +logic mubi_error; +assign mubi_error = prim_mubi_pkg::mubi4_test_invalid(no_ad_i) + | prim_mubi_pkg::mubi4_test_invalid(no_msg_i) + | prim_mubi_pkg::mubi4_test_invalid(complete_block) + | prim_mubi_pkg::mubi4_test_invalid(last_block_ad_i) + | prim_mubi_pkg::mubi4_test_invalid(last_block_msg_i); + +assign err_o = round_count_error | sparse_fsm_error | mubi_error; + +prim_ascon_round u_prim_ascon_round ( + .state_o(state_from_round), + .state_i(state_to_round), + .rcon_i(get_ascon_rcon(current_round)) +); + + +endmodule diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_ascon_pkg.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_ascon_pkg.sv new file mode 100644 index 0000000000..85ca6bae05 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_ascon_pkg.sv @@ -0,0 +1,192 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +package prim_ascon_pkg; + +parameter int AsconRoundCountW = 4; + +// Due to Ascon's round constants the current_round +// contains an offset: +// for P12 we count: from 0 to 11 = 12 rounds, +// for P8 we count: from 4 to 11 = 8 rounds, +// for P6 we count: from 5 to 11 = 6 rounds + +typedef enum logic [3:0] { + P12 = 4'b0000, + P8 = 4'b0100, + P6 = 4'b0110 +} perm_offset_e; + +parameter int DUPLEX_OP_WIDTH = 3; + +typedef enum logic [DUPLEX_OP_WIDTH-1:0] { + ASCON_ENC = 3'b001, + ASCON_DEC = 3'b010, + ASCON_HASH = 3'b100 +} duplex_op_e; + +parameter int DUPLEX_VARIANT_WIDTH = 2; + +typedef enum logic [DUPLEX_VARIANT_WIDTH-1:0] { + ASCON_128 = 2'b01, + ASCON_128A = 2'b10 +} duplex_variant_e; + +localparam logic [63:0] IV_128 = 64'h80400c0600000000; +localparam logic [63:0] IV_128A = 64'h80800c0800000000; + +localparam logic [3:0] ROUND_MAX = 4'b1011; + +// Round constants +function automatic logic [7:0] get_ascon_rcon(logic [3:0] round); + logic [7:0] result; + unique case (round) + 4'b0000: result = 8'hf0; + 4'b0001: result = 8'he1; + 4'b0010: result = 8'hd2; + 4'b0011: result = 8'hc3; + 4'b0100: result = 8'hb4; + 4'b0101: result = 8'ha5; + 4'b0110: result = 8'h96; + 4'b0111: result = 8'h87; + 4'b1000: result = 8'h78; + 4'b1001: result = 8'h69; + 4'b1010: result = 8'h5a; + 4'b1011: result = 8'h4b; + default: result = 8'h00; + endcase + + return result; +endfunction + +parameter int KEY_HI_LOW_MUX_WIDTH = 1; +typedef enum logic [KEY_HI_LOW_MUX_WIDTH-1:0] { + KEY_LOW = 1'b0, + KEY_HI = 1'b1 +} key_hi_low_mux_e; + +parameter int WORD_LOW_KEY_HI_MUX_WIDTH = 1; +typedef enum logic [WORD_LOW_KEY_HI_MUX_WIDTH-1:0] { + WORD = 1'b0, + KEY = 1'b1 +} word_low_key_hi_mux_e; + +parameter int ASCON_WORD_MUX_WIDTH = 2; +typedef enum logic [ASCON_WORD_MUX_WIDTH-1:0] { + INIT = 2'b00, + ABSORB = 2'b01, + KEEP = 2'b10, + ROUND = 2'b11 +} ascon_word_mux_e; + +parameter int ROUND_INPUT_MUX_WIDTH = 1; +typedef enum logic [ROUND_INPUT_MUX_WIDTH-1:0] { + STATE = 1'b0, + BLINDING = 1'b1 +} ascon_round_input_mux_e; + +parameter int PADDING_MUX_WIDTH = 2; +typedef enum logic [PADDING_MUX_WIDTH-1:0] { + DATA_IN_PAD = 2'b00, + DATA_OUT_PAD = 2'b01, + EMPTY_PAD = 2'b10 +} padding_mux_e; + +// Encoding generated with: +// $ ./util/design/sparse-fsm-encode.py -d 3 -m 18 -n 10 \ +// -s 3538518573 --language=sv +// +// Hamming distance histogram: +// +// 0: -- +// 1: -- +// 2: -- +// 3: ||||||||||| (13.73%) +// 4: |||||||||||||||| (20.92%) +// 5: |||||||||||||||||||| (24.84%) +// 6: |||||||||||||||| (20.92%) +// 7: ||||||||||| (14.38%) +// 8: |||| (5.23%) +// 9: -- +// 10: -- +// +// Minimum Hamming distance: 3 +// Maximum Hamming distance: 8 +// Minimum Hamming weight: 3 +// Maximum Hamming weight: 8 +// +localparam int AsconDuplexFSMStateWidth = 10; +typedef enum logic [AsconDuplexFSMStateWidth-1:0] { + Idle = 10'b1010101110, + Init = 10'b0110000110, + PermInit = 10'b1011110110, + Xor0Key = 10'b0001010011, + AbsorbAD = 10'b1110010000, + PermAD = 10'b1101101101, + XorDomSep = 10'b0100110010, + AbsorbMSG = 10'b0011100011, + PermMSG = 10'b0001001100, + AbsorbMSGEmpty = 10'b0100101100, + XorKey0 = 10'b1000011011, + PermFinal = 10'b0011010000, + SqueezeTagXorKey = 10'b1111010111, + PermADLast = 10'b1010000010, + AbsorbADEmpty = 10'b1101111011, + PermMSGEmpty = 10'b1011111000, + PermADEmpty = 10'b0010111100, + Error = 10'b0100011110 +} duplex_fsm_state_e; + +function automatic logic [127:0] bin2thermo(logic [4:0] valid_bytes); + logic [127:0] valid_bytes_mask; + unique case (valid_bytes) + 5'b00000 : valid_bytes_mask = {128{1'b0}}; + 5'b00001 : valid_bytes_mask = { {8{1'b1}}, {120{1'b0}}}; + 5'b00010 : valid_bytes_mask = { {16{1'b1}}, {112{1'b0}}}; + 5'b00011 : valid_bytes_mask = { {24{1'b1}}, {104{1'b0}}}; + 5'b00100 : valid_bytes_mask = { {32{1'b1}}, {96{1'b0}}}; + 5'b00101 : valid_bytes_mask = { {40{1'b1}}, {88{1'b0}}}; + 5'b00110 : valid_bytes_mask = { {48{1'b1}}, {80{1'b0}}}; + 5'b00111 : valid_bytes_mask = { {56{1'b1}}, {72{1'b0}}}; + 5'b01000 : valid_bytes_mask = { {64{1'b1}}, {64{1'b0}}}; + 5'b01001 : valid_bytes_mask = { {72{1'b1}}, {56{1'b0}}}; + 5'b01010 : valid_bytes_mask = { {80{1'b1}}, {48{1'b0}}}; + 5'b01011 : valid_bytes_mask = { {88{1'b1}}, {40{1'b0}}}; + 5'b01100 : valid_bytes_mask = { {96{1'b1}}, {32{1'b0}}}; + 5'b01101 : valid_bytes_mask = {{104{1'b1}}, {24{1'b0}}}; + 5'b01110 : valid_bytes_mask = {{112{1'b1}}, {16{1'b0}}}; + 5'b01111 : valid_bytes_mask = {{120{1'b1}}, {8{1'b0}}}; + default : valid_bytes_mask = {128{1'b1}}; + endcase + + return valid_bytes_mask; +endfunction + +function automatic logic [127:0] get_padding_mask(logic [4:0] valid_bytes); + logic [127:0] padding_byte_mask; + unique case (valid_bytes) + 5'b00000 : padding_byte_mask = { 8'h80, {120{1'b0}}}; + 5'b00001 : padding_byte_mask = { {8{1'b0}}, 8'h80, {112{1'b0}}}; + 5'b00010 : padding_byte_mask = { {16{1'b0}}, 8'h80, {104{1'b0}}}; + 5'b00011 : padding_byte_mask = { {24{1'b0}}, 8'h80, {96{1'b0}}}; + 5'b00100 : padding_byte_mask = { {32{1'b0}}, 8'h80, {88{1'b0}}}; + 5'b00101 : padding_byte_mask = { {40{1'b0}}, 8'h80, {80{1'b0}}}; + 5'b00110 : padding_byte_mask = { {48{1'b0}}, 8'h80, {72{1'b0}}}; + 5'b00111 : padding_byte_mask = { {56{1'b0}}, 8'h80, {64{1'b0}}}; + 5'b01000 : padding_byte_mask = { {64{1'b0}}, 8'h80, {56{1'b0}}}; + 5'b01001 : padding_byte_mask = { {72{1'b0}}, 8'h80, {48{1'b0}}}; + 5'b01010 : padding_byte_mask = { {80{1'b0}}, 8'h80, {40{1'b0}}}; + 5'b01011 : padding_byte_mask = { {88{1'b0}}, 8'h80, {32{1'b0}}}; + 5'b01100 : padding_byte_mask = { {96{1'b0}}, 8'h80, {24{1'b0}}}; + 5'b01101 : padding_byte_mask = {{104{1'b0}}, 8'h80, {16{1'b0}}}; + 5'b01110 : padding_byte_mask = {{112{1'b0}}, 8'h80, {8{1'b0}}}; + 5'b01111 : padding_byte_mask = {{120{1'b0}}, 8'h80 }; + default : padding_byte_mask = {128{1'b0}}; + endcase + + return padding_byte_mask; +endfunction + + +endpackage : prim_ascon_pkg diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_ascon_round.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_ascon_round.sv new file mode 100644 index 0000000000..2a14c9c2a6 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_ascon_round.sv @@ -0,0 +1,68 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Ascon round function implementation + + +module prim_ascon_round ( + output logic [319:0] state_o, + input logic [319:0] state_i, + input logic [7:0] rcon_i +); + + logic [319:0] ark_w, sbox_w; + + // Add round constant + assign ark_w = state_i ^ {64'h0, 64'h0, 56'h0, rcon_i, 64'h0, 64'h0}; + + // Substitution layer + logic [63:0] x_w [5]; + logic [ 4:0] xtranspose_w [64]; + logic [ 4:0] ytranspose_w [64]; + logic [63:0] y_w [5]; + + assign x_w[0] = ark_w[ 63: 0]; + assign x_w[1] = ark_w[127: 64]; + assign x_w[2] = ark_w[191:128]; + assign x_w[3] = ark_w[255:192]; + assign x_w[4] = ark_w[319:256]; + + for (genvar i = 0; i < 64; i = i + 1) begin : gen_sbox_transpose + assign xtranspose_w[i] = {x_w[4][i], + x_w[3][i], + x_w[2][i], + x_w[1][i], + x_w[0][i]}; + prim_ascon_sbox u_sbox ( + .state_i(xtranspose_w[i]), + .state_o(ytranspose_w[i]) + ); + assign {y_w[4][i], + y_w[3][i], + y_w[2][i], + y_w[1][i], + y_w[0][i]} = ytranspose_w[i]; + end + + assign sbox_w = {y_w[4], y_w[3], y_w[2], y_w[1], y_w[0]}; + + // Linear layer + logic [63:0] xl_w [5]; + logic [63:0] yl_w [5]; + + assign xl_w[0] = sbox_w[ 63: 0]; + assign xl_w[1] = sbox_w[127: 64]; + assign xl_w[2] = sbox_w[191:128]; + assign xl_w[3] = sbox_w[255:192]; + assign xl_w[4] = sbox_w[319:256]; + + assign yl_w[0] = xl_w[0] ^ {xl_w[0][18:0], xl_w[0][63:19]} ^ {xl_w[0][27:0], xl_w[0][63:28]}; + assign yl_w[1] = xl_w[1] ^ {xl_w[1][60:0], xl_w[1][63:61]} ^ {xl_w[1][38:0], xl_w[1][63:39]}; + assign yl_w[2] = xl_w[2] ^ {xl_w[2][ 0], xl_w[2][63: 1]} ^ {xl_w[2][ 5:0], xl_w[2][63: 6]}; + assign yl_w[3] = xl_w[3] ^ {xl_w[3][ 9:0], xl_w[3][63:10]} ^ {xl_w[3][16:0], xl_w[3][63:17]}; + assign yl_w[4] = xl_w[4] ^ {xl_w[4][ 6:0], xl_w[4][63: 7]} ^ {xl_w[4][40:0], xl_w[4][63:41]}; + + assign state_o = {yl_w[4], yl_w[3], yl_w[2], yl_w[1], yl_w[0]}; + +endmodule diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_ascon_sbox.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_ascon_sbox.sv new file mode 100644 index 0000000000..d0716e71b4 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_ascon_sbox.sv @@ -0,0 +1,35 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Ascon SBox unprotected implementation + +module prim_ascon_sbox ( + output logic [4:0] state_o, + input logic [4:0] state_i +); + + logic [4:0] temp_w [4]; + + assign temp_w[0] = state_i; + assign temp_w[1] = {temp_w[0][3] ^ temp_w[0][4], + temp_w[0][3], + temp_w[0][1] ^ temp_w[0][2], + temp_w[0][1], + temp_w[0][0] ^ temp_w[0][4] + }; + assign temp_w[2] = {temp_w[1][4] ^ ((~temp_w[1][0]) & temp_w[1][1]), + temp_w[1][3] ^ ((~temp_w[1][4]) & temp_w[1][0]), + temp_w[1][2] ^ ((~temp_w[1][3]) & temp_w[1][4]), + temp_w[1][1] ^ ((~temp_w[1][2]) & temp_w[1][3]), + temp_w[1][0] ^ ((~temp_w[1][1]) & temp_w[1][2]) + }; + assign temp_w[3] = {temp_w[2][4], + temp_w[2][3] ^ temp_w[2][2], + ~temp_w[2][2], + temp_w[2][1] ^ temp_w[2][0], + temp_w[2][0] ^ temp_w[2][4] + }; + assign state_o = temp_w[3]; + +endmodule diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_assert.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_assert.sv index 94c31188df..43030af17f 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_assert.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_assert.sv @@ -127,8 +127,10 @@ // Assert that signal has a known value (each bit is either '0' or '1') after reset if enable is // set. It can be called as a module (or interface) body item. `define ASSERT_KNOWN_IF(__name, __sig, __enable, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ +`ifndef FPV_ON \ `ASSERT_KNOWN(__name``KnownEnable, __enable, __clk, __rst) \ - `ASSERT_IF(__name, !$isunknown(__sig), __enable, __clk, __rst) + `ASSERT_IF(__name, !$isunknown(__sig), __enable, __clk, __rst) \ +`endif ////////////////////////////////// // For formal verification only // @@ -177,9 +179,9 @@ property __name``_p; \ __type initial_state; \ (!$stable(__state) & __name``_cond, initial_state = $past(__state)) |-> \ - (__state != initial_state) until (__rst == 1'b1); \ + (__state != initial_state) until !(__name``_cond); \ endproperty \ - `ASSERT(__name, __name``_p, __clk, __rst) \ + `ASSERT(__name, __name``_p, __clk, 0) \ `endif `include "prim_assert_sec_cm.svh" diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_assert_sec_cm.svh b/vendor/lowrisc_ip/ip/prim/rtl/prim_assert_sec_cm.svh index a2fe824bdf..0bf6844176 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_assert_sec_cm.svh +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_assert_sec_cm.svh @@ -39,6 +39,19 @@ `ASSUME_FPV(``NAME_``TriggerAfterAlertInit_S, \ $stable(rst_ni) == 0 |-> HIER_.ERR_NAME_ == 0 [*10]) +// When an error signal rises, expect to see the associated ALERT_IN_ signal go high in at most +// MAX_CYCLES_ +// +// This is expected to cause an alert to be signalled, but avoids needing to reason about the +// internals of the alert sender (which are checked with formal properties in the prim_alert_rxtx* +// cores). +// +// The NAME_, HIER_, GATE_, MAX_CYCLES_ and ERR_NAME_ arguments are the same as for +// `ASSERT_ERROR_TRIGGER_ERR. +`define ASSERT_ERROR_TRIGGER_ALERT_IN(NAME_, HIER_, ALERT_IN_, GATE_, MAX_CYCLES_, ERR_NAME_) \ + `ASSERT_ERROR_TRIGGER_ERR(NAME_, HIER_, ALERT_IN_, GATE_, MAX_CYCLES_, ERR_NAME_, \ + `ASSERT_DEFAULT_CLK, `ASSERT_DEFAULT_RST) + //////////////////////////////////////////////////////////////////////////////// // // Assertions for CMs that trigger alerts @@ -61,6 +74,38 @@ `ASSERT_PRIM_ONEHOT_ERROR_TRIGGER_ALERT(NAME_, \ REG_TOP_HIER_.u_prim_reg_we_check.u_prim_onehot_check, ALERT_, GATE_, MAX_CYCLES_) +`define ASSERT_PRIM_FIFO_SYNC_SINGLETON_ERROR_TRIGGER_ALERT(NAME, HIER_, ALERT_, GATE_ = 0, MAX_CYCLES_ = `_SEC_CM_ALERT_MAX_CYC) \ + `ASSERT_ERROR_TRIGGER_ALERT(NAME_, HIER_, ALERT_, GATE_, MAX_CYCLES_, err_o) + +//////////////////////////////////////////////////////////////////////////////// +// +// The input flavour of assertions for CMs that trigger alerts +// +// Note that the default value for MAX_CYCLES_ in these assertions is much smaller than +// _SEC_CM_ALERT_MAX_CYC. Because we are asserting something about the *input* for the alert system, +// the timing can be much tighter: we default to two cycles. +// +//////////////////////////////////////////////////////////////////////////////// + +`define ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT_IN(NAME_, HIER_, ALERT_, GATE_ = 0, MAX_CYCLES_ = 2) \ + `ASSERT_ERROR_TRIGGER_ALERT_IN(NAME_, HIER_, ALERT_, GATE_, MAX_CYCLES_, err_o) + +`define ASSERT_PRIM_DOUBLE_LFSR_ERROR_TRIGGER_ALERT_IN(NAME_, HIER_, ALERT_, GATE_ = 0, MAX_CYCLES_ = 2) \ + `ASSERT_ERROR_TRIGGER_ALERT_IN(NAME_, HIER_, ALERT_, GATE_, MAX_CYCLES_, err_o) + +`define ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT_IN(NAME_, HIER_, ALERT_, GATE_ = 0, MAX_CYCLES_ = 2) \ + `ASSERT_ERROR_TRIGGER_ALERT_IN(NAME_, HIER_, ALERT_, GATE_, MAX_CYCLES_, unused_err_o) + +`define ASSERT_PRIM_ONEHOT_ERROR_TRIGGER_ALERT_IN(NAME_, HIER_, ALERT_, GATE_ = 0, MAX_CYCLES_ = 2) \ + `ASSERT_ERROR_TRIGGER_ALERT_IN(NAME_, HIER_, ALERT_, GATE_, MAX_CYCLES_, err_o) + +`define ASSERT_PRIM_REG_WE_ONEHOT_ERROR_TRIGGER_ALERT_IN(NAME_, REG_TOP_HIER_, ALERT_, GATE_ = 0, MAX_CYCLES_ = 2) \ + `ASSERT_PRIM_ONEHOT_ERROR_TRIGGER_ALERT_IN(NAME_, \ + REG_TOP_HIER_.u_prim_reg_we_check.u_prim_onehot_check, ALERT_, GATE_, MAX_CYCLES_) + +`define ASSERT_PRIM_FIFO_SYNC_SINGLETON_ERROR_TRIGGER_ALERT_IN(NAME, HIER_, ALERT_, GATE_ = 0, MAX_CYCLES_ = 2) \ + `ASSERT_ERROR_TRIGGER_ALERT_IN(NAME_, HIER_, ALERT_, GATE_, MAX_CYCLES_, err_o) + //////////////////////////////////////////////////////////////////////////////// // // Assertions for CMs that trigger some other form of error 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 9dead6cf63..61847c534e 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 @@ -50,16 +50,24 @@ end \ `endif -`define ASSERT_AT_RESET(__name, __prop, __rst = `ASSERT_DEFAULT_RST) \ - // `__rst` is active-high for these macros, so trigger on its posedge. \ - // The values inside the property are sampled just before the trigger, \ - // which is necessary to make the evaluation of `__prop` on a reset edge \ - // meaningful. On any reset posedge at the start of time, `__rst` itself \ - // is unknown, and at that time `__prop` is likely not initialized either, \ - // so this assertion does not evaluate `__prop` when `__rst` is unknown. \ - __name: assert property (@(posedge __rst) $isunknown(__rst) || (__prop)) \ - else begin \ - `ASSERT_ERROR(__name) \ +`define ASSERT_AT_RESET(__name, __prop, __rst = `ASSERT_DEFAULT_RST) \ + // `__rst` is active-high for these macros, so trigger on its posedge. \ + // The values inside the property are sampled just before the trigger, \ + // which is necessary to make the evaluation of `__prop` on a reset edge \ + // meaningful. On any reset posedge at the start of time, `__rst` itself \ + // is unknown, and at that time `__prop` is likely not initialized either, \ + // so this assertion does not evaluate `__prop` when `__rst` is unknown. \ + // \ + // This extra behaviour is not used for FPV, because Jasper doesn't support \ + // it and instead prints the WNL038 warning. Avoid the check and warning \ + // message in this case. \ +`ifndef FPV_ON \ + __name: assert property (@(posedge __rst) $isunknown(__rst) || (__prop)) \ +`else \ + __name: assert property (@(posedge __rst) (__prop)) \ +`endif \ + else begin \ + `ASSERT_ERROR(__name) \ end `define ASSERT_AT_RESET_AND_FINAL(__name, __prop, __rst = `ASSERT_DEFAULT_RST) \ @@ -79,7 +87,9 @@ end `define ASSERT_KNOWN(__name, __sig, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ - `ASSERT(__name, !$isunknown(__sig), __clk, __rst) +`ifndef FPV_ON \ + `ASSERT(__name, !$isunknown(__sig), __clk, __rst) \ +`endif `define COVER(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ __name: cover property (@(posedge __clk) disable iff ((__rst) !== '0) (__prop)); diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_clock_gp_mux2.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_clock_gp_mux2.sv deleted file mode 100644 index ac259ab863..0000000000 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_clock_gp_mux2.sv +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright lowRISC contributors (OpenTitan project). -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -// Glitch free clock mux using parallel two flop synchronizers - -module prim_clock_gp_mux2 #( - parameter bit NoFpgaBufG = 1'b0, - parameter bit FpgaBufGlobal = 1, - parameter bit GlitchProtect = 1 -) ( - input clk0_i, - input clk1_i, - input sel_i, - input rst_ni, - input test_en_i, - output logic clk_o -); - -logic [1:0] clk_gp; -logic [1:0] intq; -logic [1:0] stage_d; -logic [1:0] stage_q; -logic [1:0] clk_glitch_off; - -assign clk_gp = {clk1_i, clk0_i}; -assign stage_d = {sel_i & !stage_q[0], !sel_i & !stage_q[1]}; - -generate - genvar i; - for (i = 0; i < 2; i++) begin: gen_two_flops - always_ff @(posedge clk_gp[i] or negedge rst_ni) begin: stage1 - if (!rst_ni) begin - intq[i] <= 1'b0; - end else begin - intq[i] <= stage_d[i]; - end - end - - always_ff @(negedge clk_gp[i] or negedge rst_ni) begin: stage2 - if (!rst_ni) begin - stage_q[i] <= 1'b0; - end else begin - stage_q[i] <= intq[i]; - end - end - - prim_clock_gating #( - .FpgaBufGlobal(FpgaBufGlobal) - ) u_cg ( - .clk_i(clk_gp[i]), - .en_i(stage_q[i]), - .test_en_i(1'b0), - .clk_o(clk_glitch_off[i]) - ); - - end -endgenerate - -assign clk_o = |clk_glitch_off; - -endmodule diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_clock_meas.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_clock_meas.sv index 45c0ec2ee4..20b2b0b0cd 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_clock_meas.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_clock_meas.sv @@ -270,7 +270,7 @@ module prim_clock_meas #( `ASSERT_INIT(RefCntVal_A, RefCnt >= 1) // if we've reached the max count, enable must be 0 next. - // Otherwise the width of the counter is too small to accommodate the usecase + // Otherwise the width of the counter is too small to accommodate the use case `ASSERT(MaxWidth_A, (cnt == Cnt-1) |=> !cnt_en ) diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_count.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_count.sv index c0e77647f4..f2d10fe6fc 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_count.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_count.sv @@ -140,7 +140,18 @@ module prim_count // The sum of both counters must always equal the counter maximum. logic [Width:0] sum; assign sum = (cnt_q[0] + cnt_q[1]); - assign err_o = (sum != {1'b0, {Width{1'b1}}}); + + // Register the error signal to avoid potential CDC issues downstream. + logic err_d, err_q; + assign err_d = (sum != {1'b0, {Width{1'b1}}}); + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + err_q <= 1'b0; + end else begin + err_q <= err_d; + end + end + assign err_o = err_q; // Output count values assign cnt_o = cnt_q[0]; @@ -155,7 +166,7 @@ module prim_count // We need to disable most assertions in that case using a helper signal. // We can't rely on err_o since some error patterns cannot be detected (e.g. all error - // patterns that still fullfill the sum constraint). + // patterns that still fulfil the sum constraint). logic fpv_err_present; assign fpv_err_present = |fpv_force; @@ -190,7 +201,7 @@ module prim_count rst_ni |=> $past(!commit_i) || (cnt_o == $past(cnt_after_commit_o)), - clk_i, err_o || fpv_err_present || !rst_ni) + clk_i, err_d || fpv_err_present || !rst_ni) // Clear if (PossibleActions & Clr) begin : g_check_clr_fwd_a @@ -199,7 +210,7 @@ module prim_count |=> (cnt_o == ResetValue) && (cnt_q[1] == ({Width{1'b1}} - ResetValue)), - clk_i, err_o || fpv_err_present || !rst_ni) + clk_i, err_d || fpv_err_present || !rst_ni) end // Set @@ -209,7 +220,7 @@ module prim_count |=> (cnt_o == $past(set_cnt_i)) && (cnt_q[1] == ({Width{1'b1}} - $past(set_cnt_i))), - clk_i, err_o || fpv_err_present || !rst_ni) + clk_i, err_d || fpv_err_present || !rst_ni) end // Do not count if both increment and decrement are asserted. @@ -218,7 +229,7 @@ module prim_count rst_ni && incr_en_i && decr_en_i && !(clr_i || set_i) |=> $stable(cnt_o) && $stable(cnt_q[1]), - clk_i, err_o || fpv_err_present || !rst_ni) + clk_i, err_d || fpv_err_present || !rst_ni) end // Increment @@ -227,24 +238,24 @@ module prim_count rst_ni && incr_en_i && !(clr_i || set_i || decr_en_i) && commit_i |=> cnt_o == min($past(cnt_o) + $past({2'b0, step_i}), {2'b0, {Width{1'b1}}}), - clk_i, err_o || fpv_err_present || !rst_ni) + clk_i, err_d || fpv_err_present || !rst_ni) `ASSERT(IncrDnCnt_A, rst_ni && incr_en_i && !(clr_i || set_i || decr_en_i) && commit_i |=> cnt_q[1] == max($past(signed'({2'b0, cnt_q[1]})) - $past({2'b0, step_i}), '0), - clk_i, err_o || fpv_err_present || !rst_ni) + clk_i, err_d || fpv_err_present || !rst_ni) `ASSERT(UpCntIncrStable_A, incr_en_i && !(clr_i || set_i || decr_en_i) && cnt_o == {Width{1'b1}} |=> $stable(cnt_o), - clk_i, err_o || fpv_err_present || !rst_ni) + clk_i, err_d || fpv_err_present || !rst_ni) `ASSERT(DnCntIncrStable_A, rst_ni && incr_en_i && !(clr_i || set_i || decr_en_i) && cnt_q[1] == '0 |=> $stable(cnt_q[1]), - clk_i, err_o || fpv_err_present || !rst_ni) + clk_i, err_d || fpv_err_present || !rst_ni) end // Decrement @@ -253,24 +264,24 @@ module prim_count rst_ni && decr_en_i && !(clr_i || set_i || incr_en_i) && commit_i |=> cnt_o == max($past(signed'({2'b0, cnt_o})) - $past({2'b0, step_i}), '0), - clk_i, err_o || fpv_err_present || !rst_ni) + clk_i, err_d || fpv_err_present || !rst_ni) `ASSERT(DecrDnCnt_A, rst_ni && decr_en_i && !(clr_i || set_i || incr_en_i) && commit_i |=> cnt_q[1] == min($past(cnt_q[1]) + $past({2'b0, step_i}), {2'b0, {Width{1'b1}}}), - clk_i, err_o || fpv_err_present || !rst_ni) + clk_i, err_d || fpv_err_present || !rst_ni) `ASSERT(UpCntDecrStable_A, decr_en_i && !(clr_i || set_i || incr_en_i) && cnt_o == '0 |=> $stable(cnt_o), - clk_i, err_o || fpv_err_present || !rst_ni) + clk_i, err_d || fpv_err_present || !rst_ni) `ASSERT(DnCntDecrStable_A, rst_ni && decr_en_i && !(clr_i || set_i || incr_en_i) && cnt_q[1] == {Width{1'b1}} |=> $stable(cnt_q[1]), - clk_i, err_o || fpv_err_present || !rst_ni) + clk_i, err_d || fpv_err_present || !rst_ni) end // A backwards check for count changes. This asserts that the count only changes if one of the @@ -279,10 +290,14 @@ module prim_count rst_ni ##1 $changed(cnt_o) && $changed(cnt_q[1]) |-> $past(clr_i || set_i || (commit_i && (incr_en_i || decr_en_i))), - clk_i, err_o || fpv_err_present || !rst_ni) + clk_i, err_d || fpv_err_present || !rst_ni) // Check that count errors are reported properly in err_o - `ASSERT(CntErrReported_A, ((cnt_q[1] + cnt_q[0]) != {Width{1'b1}}) == err_o) + // + // This is essentially a "|=> implication", but is structured in a way to avoid generating a cover + // property for the left hand side if PrimCountFpv is not defined (because we won't have a way to + // inject an error if not) + `ASSERT(CntErrReported_A, ##1 $past((cnt_q[1] + cnt_q[0]) != {Width{1'b1}}) == err_o) `ifdef PrimCountFpv `COVER(CntErr_C, err_o) `endif diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_diff_decode.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_diff_decode.sv index 8c2804cb11..daaca6c138 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_diff_decode.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_diff_decode.sv @@ -19,7 +19,13 @@ module prim_diff_decode #( // enables additional synchronization logic - parameter bit AsyncOn = 1'b0 + parameter bit AsyncOn = 1'b0, + // Number of cycles a differential skew is tolerated before a signal integrity issue is flagged. + // Only has an effect if AsyncOn = 1 + // 0 means no skew is tolerated (any mismatch is an immediate signal integrity error). + // 1 means a one-cycle skew is tolerated. + // Values larger than 1 are also supported. + parameter int unsigned SkewCycles = 1 ) ( input clk_i, input rst_ni, @@ -44,13 +50,17 @@ module prim_diff_decode #( /////////////////////////////////////////////////////////////// if (AsyncOn) begin : gen_async - typedef enum logic [1:0] {IsStd, IsSkewed, SigInt} state_e; + typedef enum logic [1:0] {IsStd, IsSkewing, SigInt} state_e; state_e state_d, state_q; logic diff_p_edge, diff_n_edge, diff_check_ok, level; // 2 sync regs, one reg for edge detection logic diff_pq, diff_nq, diff_pd, diff_nd; + // Counter for skew cycles tolerated before flagging an issue + // The width needs to accommodate SkewCycles + 1 to count up to SkewCycles. + logic [prim_util_pkg::vbits(SkewCycles + 1)-1:0] skew_cnt_d, skew_cnt_q; + prim_flop_2sync #( .Width(1), .ResetValue('0) @@ -87,7 +97,7 @@ module prim_diff_decode #( // sigint detection is a bit more involved in async case since // we might have skew on the diff pair, which can result in a - // one cycle sampling delay between the two wires + // N cycle sampling delay between the two wires // so we need a simple pattern matcher // the following waves are legal // clk | | | | | | | | @@ -100,17 +110,18 @@ module prim_diff_decode #( // _______ ________ // n \_______ ... _______/ // - // i.e., level changes may be off by one cycle - which is permissible - // as long as this condition is only one cycle long. + // i.e., level changes may be off by N cycle - which is permissible + // as long as this condition is only N cycle long. always_comb begin : p_diff_fsm // default - state_d = state_q; - level_d = level_q; - rise_o = 1'b0; - fall_o = 1'b0; - sigint_o = 1'b0; + state_d = state_q; + level_d = level_q; + skew_cnt_d = skew_cnt_q; + rise_o = 1'b0; + fall_o = 1'b0; + sigint_o = 1'b0; unique case (state_q) // we remain here as long as @@ -126,33 +137,49 @@ module prim_diff_decode #( end end end else begin - if (diff_p_edge || diff_n_edge) begin - state_d = IsSkewed; - end else begin - state_d = SigInt; + if (SkewCycles == 0) begin + // If no skew is tolerated, immediate signal integrity error + state_d = SigInt; sigint_o = 1'b1; + end else begin + // Mismatch with an edge: likely start of a tolerated skew + state_d = IsSkewing; + skew_cnt_d = 1; end end end // diff pair must be correctly encoded, otherwise we got a sigint - IsSkewed: begin + IsSkewing: begin if (diff_check_ok) begin - state_d = IsStd; - level_d = level; + state_d = IsStd; + level_d = level; + // Reset the skew counter + skew_cnt_d = '0; + // Assert event that was delayed due to skew resolution if (level) rise_o = 1'b1; else fall_o = 1'b1; end else begin - state_d = SigInt; - sigint_o = 1'b1; + if (skew_cnt_q < SkewCycles) begin + // Still within tolerated skew cycles + skew_cnt_d = skew_cnt_q + 1; + end else begin + // Maximum skew cycles exceeded, raise an integrity issue + state_d = SigInt; + sigint_o = 1'b1; + skew_cnt_d = '0; + end end end - // Signal integrity issue detected, remain here - // until resolved + // Signal integrity issue detected, remain here until resolved SigInt: begin sigint_o = 1'b1; if (diff_check_ok) begin state_d = IsStd; sigint_o = 1'b0; + level_d = level; + // Assert any event that was pending while in SigInt + if (level) rise_o = 1'b1; + else fall_o = 1'b1; end end default : ; @@ -161,15 +188,17 @@ module prim_diff_decode #( always_ff @(posedge clk_i or negedge rst_ni) begin : p_sync_reg if (!rst_ni) begin - state_q <= IsStd; - diff_pq <= 1'b0; - diff_nq <= 1'b1; - level_q <= 1'b0; + state_q <= IsStd; + diff_pq <= 1'b0; + diff_nq <= 1'b1; + level_q <= 1'b0; + skew_cnt_q <= '0; end else begin - state_q <= state_d; - diff_pq <= diff_pd; - diff_nq <= diff_nd; - level_q <= level_d; + state_q <= state_d; + diff_pq <= diff_pd; + diff_nq <= diff_nd; + level_q <= level_d; + skew_cnt_q <= skew_cnt_d; end end @@ -229,48 +258,59 @@ module prim_diff_decode #( // assertions for asynchronous case `ifdef INC_ASSERT `ifndef FPV_ALERT_NO_SIGINT_ERR - // correctly detect sigint issue (only one transition cycle of permissible due to skew) - `ASSERT(SigintCheck0_A, gen_async.diff_pd == gen_async.diff_nd [*2] |-> sigint_o) - // the synchronizer adds 2 cycles of latency with respect to input signals. - `ASSERT(SigintCheck1_A, - ##1 (gen_async.diff_pd ^ gen_async.diff_nd) && - $stable(gen_async.diff_pd) && $stable(gen_async.diff_nd) ##1 - $rose(gen_async.diff_pd) && $stable(gen_async.diff_nd) ##1 - $stable(gen_async.diff_pd) && $fell(gen_async.diff_nd) - |-> rise_o) - `ASSERT(SigintCheck2_A, - ##1 (gen_async.diff_pd ^ gen_async.diff_nd) && - $stable(gen_async.diff_pd) && $stable(gen_async.diff_nd) ##1 - $fell(gen_async.diff_pd) && $stable(gen_async.diff_nd) ##1 - $stable(gen_async.diff_pd) && $rose(gen_async.diff_nd) - |-> fall_o) - `ASSERT(SigintCheck3_A, - ##1 (gen_async.diff_pd ^ gen_async.diff_nd) && - $stable(gen_async.diff_pd) && $stable(gen_async.diff_nd) ##1 - $rose(gen_async.diff_nd) && $stable(gen_async.diff_pd) ##1 - $stable(gen_async.diff_nd) && $fell(gen_async.diff_pd) - |-> fall_o) - `ASSERT(SigintCheck4_A, - ##1 (gen_async.diff_pd ^ gen_async.diff_nd) && - $stable(gen_async.diff_pd) && $stable(gen_async.diff_nd) ##1 - $fell(gen_async.diff_nd) && $stable(gen_async.diff_pd) ##1 - $stable(gen_async.diff_nd) && $rose(gen_async.diff_pd) - |-> rise_o) - `endif + // Correctly detect signal integrity issue: + // If diff_pd and diff_nd are equal for (SkewCycles + 1) consecutive cycles, sigint_o must be + // asserted. + `ASSERT(SigintCheck0_A, + gen_async.diff_pd == gen_async.diff_nd [* (SkewCycles + 1)] |-> sigint_o) - // correctly detect edges + // The following assertions (SigintCheck1_A to SigintCheck4_A) describe specific + // 1-cycle skew patterns that should lead to an edge. These are highly + // specific to SkewCycles = 1. Therefore, they are only included when SkewCycles is 1. + // the synchronizer adds 2 cycles of latency with respect to input signals. + if (SkewCycles == 1) begin : gen_specific_skew_asserts + `ASSERT(SigintCheck1_A, + ##1 (gen_async.diff_pd ^ gen_async.diff_nd) && + $stable(gen_async.diff_pd) && $stable(gen_async.diff_nd) ##1 + $rose(gen_async.diff_pd) && $stable(gen_async.diff_nd) ##1 + $stable(gen_async.diff_pd) && $fell(gen_async.diff_nd) + |-> rise_o) + `ASSERT(SigintCheck2_A, + ##1 (gen_async.diff_pd ^ gen_async.diff_nd) && + $stable(gen_async.diff_pd) && $stable(gen_async.diff_nd) ##1 + $fell(gen_async.diff_pd) && $stable(gen_async.diff_nd) ##1 + $stable(gen_async.diff_pd) && $rose(gen_async.diff_nd) + |-> fall_o) + `ASSERT(SigintCheck3_A, + ##1 (gen_async.diff_pd ^ gen_async.diff_nd) && + $stable(gen_async.diff_pd) && $stable(gen_async.diff_nd) ##1 + $rose(gen_async.diff_nd) && $stable(gen_async.diff_pd) ##1 + $stable(gen_async.diff_nd) && $fell(gen_async.diff_pd) + |-> fall_o) + `ASSERT(SigintCheck4_A, + ##1 (gen_async.diff_pd ^ gen_async.diff_nd) && + $stable(gen_async.diff_pd) && $stable(gen_async.diff_nd) ##1 + $fell(gen_async.diff_nd) && $stable(gen_async.diff_pd) ##1 + $stable(gen_async.diff_nd) && $rose(gen_async.diff_pd) + |-> rise_o) + end + `endif + // Correctly detect edges: an event should be asserted within SkewCycles cycles after a valid + // transition `ASSERT(RiseCheck_A, !sigint_o ##1 $rose(gen_async.diff_pd) && (gen_async.diff_pd ^ gen_async.diff_nd) |-> - ##[0:1] rise_o, clk_i, !rst_ni || sigint_o) + ##[0:SkewCycles] rise_o, clk_i, !rst_ni || sigint_o) `ASSERT(FallCheck_A, !sigint_o ##1 $fell(gen_async.diff_pd) && (gen_async.diff_pd ^ gen_async.diff_nd) |-> - ##[0:1] fall_o, clk_i, !rst_ni || sigint_o) + ##[0:SkewCycles] fall_o, clk_i, !rst_ni || sigint_o) `ASSERT(EventCheck_A, !sigint_o ##1 $changed(gen_async.diff_pd) && (gen_async.diff_pd ^ gen_async.diff_nd) |-> - ##[0:1] event_o, clk_i, !rst_ni || sigint_o) - // correctly detect level + ##[0:SkewCycles] event_o, clk_i, !rst_ni || sigint_o) + // Correctly detect level: the output level should match diff_pd once the differential pair is + // stable `ASSERT(LevelCheck0_A, - !sigint_o && (gen_async.diff_pd ^ gen_async.diff_nd) [*2] |-> + // Stable for SkewCycles + 1 cycles + !sigint_o && (gen_async.diff_pd ^ gen_async.diff_nd) [* (SkewCycles + 1)] |-> gen_async.diff_pd == level_o, clk_i, !rst_ni || sigint_o) `endif diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_diff_encode.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_diff_encode.sv new file mode 100644 index 0000000000..e91d18bd9e --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_diff_encode.sv @@ -0,0 +1,61 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// This module encodes a single bit signal to a differentially encoded signal. +// +// In case the differential pair crosses an asynchronous boundary, it has +// to be re-synchronized to the local clock. + +module prim_diff_encode ( + input logic clk_i, + input logic rst_ni, + // Single line input signal + input logic req_i, + // Output diff pair + output logic diff_po, + output logic diff_no +); + // Buff the input signal to avoid any optimization + logic req; + prim_sec_anchor_buf #( + .Width(1) + ) u_prim_buf_in_req ( + .in_i(req_i), + .out_o(req) + ); + + // Differentially encode input + logic diff_p, diff_n; + assign diff_p = req; + assign diff_n = ~req; + + // This prevents further tool optimizations of the differential signal. + prim_sec_anchor_buf #( + .Width(2) + ) u_prim_buf_ack ( + .in_i({diff_n, diff_p}), + .out_o({diff_n_buf, diff_p_buf}) + ); + + // Flop differentially encoded signal at the output + prim_flop #( + .Width(1), + .ResetValue(1'b0) + ) u_diff_p ( + .clk_i, + .rst_ni, + .d_i ( diff_p_buf ), + .q_o ( diff_po ) + ); + + prim_flop #( + .Width(1), + .ResetValue(1'b1) + ) u_diff_n ( + .clk_i, + .rst_ni, + .d_i ( diff_n_buf ), + .q_o ( diff_no ) + ); +endmodule : prim_diff_encode diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_diff_to_alert.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_diff_to_alert.sv new file mode 100644 index 0000000000..7cda793246 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_diff_to_alert.sv @@ -0,0 +1,70 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// prim_diff_to_alert: This module receives a differentially encoded alert request and translates +// that to an alert signal with the alert protocol. + +module prim_diff_to_alert #( + // AsyncOn: Enables additional synchronization logic within the alert receiver. + parameter bit AsyncOn = 1'b1, + // Number of cycles a differential skew is tolerated on the alert signal + parameter int unsigned SkewCycles = 1, + // Alert sender will latch the incoming alert event permanently and + // keep on sending alert events until the next reset. + parameter bit IsFatal = 1'b1 +) ( + input logic clk_i, + input logic rst_ni, + // Input diff pair (differentially encoded alert signal) + input logic diff_pi, + input logic diff_ni, + // Alert pair (interface signals for the alert protocol) + input prim_alert_pkg::alert_rx_t alert_rx_i, + output prim_alert_pkg::alert_tx_t alert_tx_o +); + logic diff_p_sync, diff_n_sync; + + if (AsyncOn) begin : gen_async + prim_flop_2sync #( + .Width(2), + .ResetValue(2'b10) + ) u_sync ( + .clk_i, + .rst_ni, + .d_i ( {diff_ni, diff_pi} ), + .q_o ( {diff_n_sync, diff_p_sync} ) + ); + end else begin : gen_sync + assign diff_p_sync = diff_pi; + assign diff_n_sync = diff_ni; + end + + // This prevents further tool optimizations of the differential signal. + logic diff_p_buf, diff_n_buf; + prim_sec_anchor_buf #( + .Width(2) + ) u_prim_buf_ack ( + .in_i ( {diff_n_sync, diff_p_sync} ), + .out_o ( {diff_n_buf, diff_p_buf} ) + ); + + // Treat any positive value on `diff_p_buf` and any negative value on `diff_n_buf` as alert. + logic alert_req; + assign alert_req = diff_p_buf | ~diff_n_buf; + + prim_alert_sender #( + .AsyncOn(AsyncOn), + .SkewCycles(SkewCycles), + .IsFatal(IsFatal) + ) u_prim_alert_sender ( + .clk_i, + .rst_ni, + .alert_test_i ( 1'b0 ), + .alert_req_i ( alert_req ), + .alert_ack_o (), + .alert_state_o (), + .alert_rx_i, + .alert_tx_o + ); +endmodule diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_esc_receiver.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_esc_receiver.sv index 2f01b93f0c..df169b790c 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_esc_receiver.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_esc_receiver.sv @@ -29,6 +29,9 @@ module prim_esc_receiver // when this primitive is instantiated. parameter int PING_CNT_DW = 16, + // Number of cycles a differential skew is tolerated on the differential escalation signal. + parameter int unsigned SkewCycles = 1, + // This counter monitors incoming ping requests and auto-escalates if the alert handler // ceases to send them regularly. The maximum number of cycles between subsequent ping requests // is N_ESC_SEV x (2 x 2 x 2**PING_CNT_DW), see also implementation of the ping timer @@ -73,7 +76,8 @@ module prim_esc_receiver ); prim_diff_decode #( - .AsyncOn(1'b0) + .AsyncOn(1'b0), + .SkewCycles(SkewCycles) ) u_decode_esc ( .clk_i, .rst_ni, @@ -126,11 +130,21 @@ module prim_esc_receiver // - requested via the escalation sender/receiver path, // - the ping monitor timeout is reached, // - the two ping monitor counters are in an inconsistent state. - logic esc_req; + // Register the escalation request to avoid potential CDC issues downstream. + logic esc_req, esc_req_d, esc_req_q; + assign esc_req_d = esc_req || (&timeout_cnt) || timeout_cnt_error; + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + esc_req_q <= 1'b0; + end else begin + esc_req_q <= esc_req_d; + end + end + prim_sec_anchor_buf #( .Width(1) ) u_prim_buf_esc_req ( - .in_i(esc_req || (&timeout_cnt) || timeout_cnt_error), + .in_i (esc_req_q), .out_o(esc_req_o) ); @@ -257,7 +271,7 @@ module prim_esc_receiver `ASSERT(SigIntCheck0_A, esc_tx_i.esc_p == esc_tx_i.esc_n |=> esc_rx_o.resp_p == esc_rx_o.resp_n) `ASSERT(SigIntCheck1_A, esc_tx_i.esc_p == esc_tx_i.esc_n |=> state_q == SigInt) // auto-escalate in case of signal integrity issue - `ASSERT(SigIntCheck2_A, esc_tx_i.esc_p == esc_tx_i.esc_n |=> esc_req_o) + `ASSERT(SigIntCheck2_A, esc_tx_i.esc_p == esc_tx_i.esc_n |=> esc_req_d) // correct diff encoding `ASSERT(DiffEncCheck_A, esc_tx_i.esc_p ^ esc_tx_i.esc_n |=> esc_rx_o.resp_p ^ esc_rx_o.resp_n) // disable in case of signal integrity issue @@ -271,10 +285,10 @@ module prim_esc_receiver // detect escalation pulse `ASSERT(EscEnCheck_A, esc_tx_i.esc_p && (esc_tx_i.esc_p ^ esc_tx_i.esc_n) && state_q != SigInt - ##1 esc_tx_i.esc_p && (esc_tx_i.esc_p ^ esc_tx_i.esc_n) |-> esc_req_o) + ##1 esc_tx_i.esc_p && (esc_tx_i.esc_p ^ esc_tx_i.esc_n) |-> esc_req_d) // make sure the counter does not wrap around `ASSERT(EscCntWrap_A, &timeout_cnt |=> timeout_cnt != 0) // if the counter expires, escalation should be asserted - `ASSERT(EscCntEsc_A, &timeout_cnt |-> esc_req_o) + `ASSERT(EscCntEsc_A, &timeout_cnt |-> esc_req_d) endmodule : prim_esc_receiver diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_esc_sender.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_esc_sender.sv index fba0bab890..b534227125 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_esc_sender.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_esc_sender.sv @@ -23,7 +23,10 @@ module prim_esc_sender import prim_esc_pkg::*; -( +#( + // Number of cycles a differential skew is tolerated on the differential response signal. + parameter int unsigned SkewCycles = 1 +) ( input clk_i, input rst_ni, // this triggers a ping test. keep asserted until ping_ok_o is pulsed high. @@ -56,7 +59,8 @@ module prim_esc_sender ); prim_diff_decode #( - .AsyncOn(1'b0) + .AsyncOn(1'b0), + .SkewCycles(SkewCycles) ) u_decode_resp ( .clk_i, .rst_ni, diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_assert.svh b/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_assert.svh new file mode 100644 index 0000000000..83320918ec --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_assert.svh @@ -0,0 +1,47 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Macros that define assertions that relate to FIFO implementations + +`ifndef PRIM_FIFO_ASSERT_SVH +`define PRIM_FIFO_ASSERT_SVH + +// Use PRIM_COUNT_ERROR_TRIGGER_ALERT appropriately to check that the three prim_counts generated by +// a prim_fifo_sync with depth at least two do indeed generate an alert if they detect an error. +// +// - NAME_ is used as the root of the names of the generated assertions. +// - HIER_ is a hierarchical path to the prim_fifo_sync in question. +// - ALERT_ is the name of the alert that should be generated. +// - GATE_ is a signal that, if true, will cause an error to be ignored. +// - MAX_CYCLES_ is the number of cycles allowed until the alert must be generated. +`define ASSERT_PRIM_FIFO_SYNC_ERROR_TRIGGERS_ALERT(NAME_, HIER_, ALERT_, GATE_ = 0, MAX_CYCLES_ = `_SEC_CM_ALERT_MAX_CYC) \ + `ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT(``NAME_``WptrCheck_A, \ + HIER_.gen_normal_fifo.u_fifo_cnt.gen_secure_ptrs.u_wptr, \ + ALERT_, \ + GATE_, \ + MAX_CYCLES_) \ + `ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT(``NAME_``RptrCheck_A, \ + HIER_.gen_normal_fifo.u_fifo_cnt.gen_secure_ptrs.u_rptr, \ + ALERT_, \ + GATE_, \ + MAX_CYCLES_) + +// An analagous assertion to PRIM_COUNT_ERROR_TRIGGER_ALERT, but specialised for the case where the +// fifo has depth 1, which means there aren't actually three prim_count instances but instead there +// is just a single error signal. +// +// - NAME_ is used as a root for the name of the generated assertion. +// - HIER_ is a hierarchical path to the prim_fifo_sync in question. +// - ALERT_ is the name of the alert that should be generated. +// - GATE_ is a signal that, if true, will cause an error to be ignored. +// - MAX_CYCLES_ is the number of cycles allowed until the alert must be generated. +`define ASSERT_PRIM_FIFO_SYNC_ERROR_TRIGGERS_ALERT1(NAME_, HIER_, ALERT_, GATE_ = 0, MAX_CYCLES_ = `_SEC_CM_ALERT_MAX_CYC) \ + `ASSERT_ERROR_TRIGGER_ALERT(``NAME_``FullCheck_A, \ + HIER_, \ + ALERT_, \ + GATE_, \ + MAX_CYCLES_, \ + err_o) + +`endif // PRIM_FIFO_ASSERT_SVH 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 bbdfcf9029..a74d3a81d3 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async.sv @@ -249,8 +249,8 @@ module prim_fifo_async #( logic unused_decsub_msb; dec_tmp = '0; - for (int i = PTR_WIDTH-2; i >= 0; i--) begin - dec_tmp[i] = dec_tmp[i+1] ^ grayval[i]; + for (int unsigned i = PTR_WIDTH-1; i > 0; i--) begin + dec_tmp[i-1] = dec_tmp[i] ^ grayval[i-1]; end dec_tmp_sub = (PTR_WIDTH)'(Depth) - dec_tmp - 1'b1; if (grayval[PTR_WIDTH-1]) begin diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async_sram_adapter.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async_sram_adapter.sv index 5d6462d722..32114708bd 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async_sram_adapter.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async_sram_adapter.sv @@ -267,8 +267,7 @@ module prim_fifo_async_sram_adapter #( // - r_rptr_inc: Can request more // - !r_rptr_inc: Can't request always_comb begin : r_sram_req - r_sram_req_o = 1'b 0; - // Karnough Map (!empty): sram_req + // Karnaugh Map (!empty): sram_req // {sram_rv, rfifo_ack} | 00 | 01 | 11 | 10 // ---------------------------------------------------------- // stored | 0 | 1 | impossible | 1 | 0 @@ -311,7 +310,7 @@ module prim_fifo_async_sram_adapter #( // read clock domain rdata storage logic store_en; - // Karnough Map (r_sram_rvalid_i): + // Karnaugh Map (r_sram_rvalid_i): // rfifo_ack | 0 | 1 | // --------------------- // stored 0 | 1 | 0 | @@ -404,11 +403,14 @@ module prim_fifo_async_sram_adapter #( `ASSERT(NoWAckInFull_A, w_wptr_inc |-> !w_full, clk_wr_i, !rst_wr_ni) + // If a valid/ready handshake happens for the write pointer, that pointer should increment by one `ASSERT(WptrIncrease_A, - w_wptr_inc |=> w_wptr_v == PtrVW'($past(w_wptr_v,2) + 1), + w_wptr_inc |=> w_wptr_q == $past(w_wptr_q) + PtrW'(1), clk_wr_i, !rst_wr_ni) + // Check that the Gray coding works correctly, so the increment to w_wptr_gray_q changes exactly + // one bit. `ASSERT(WptrGrayOneBitAtATime_A, - w_wptr_inc |=> $countones(w_wptr_gray_q ^ $past(w_wptr_gray_q,2)) == 1, + w_wptr_inc |=> $countones(w_wptr_gray_q ^ $past(w_wptr_gray_q)) == 1, clk_wr_i, !rst_wr_ni) `ASSERT(NoRAckInEmpty_A, r_rptr_inc |-> !r_empty, 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 6fc3560cbe..ed4317f9d1 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_sync.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_sync.sv @@ -6,11 +6,17 @@ `include "prim_assert.sv" +// This include isn't really needed by code in prim_fifo_sync.sv! But it ensures that we always +// evaluate the contents of prim_fifo_assert.svh if we happen to include this file, avoiding a +// problem where we might include a FIFO but not use any of the assertions that this file defines. +`include "prim_fifo_assert.svh" + module prim_fifo_sync #( parameter int unsigned Width = 16, parameter bit Pass = 1'b1, // if == 1 allow requests to pass through empty FIFO parameter int unsigned Depth = 4, parameter bit OutputZeroIfEmpty = 1'b1, // if == 1 always output 0 when FIFO is empty + parameter bit NeverClears = 1'b0, // if set, the clr_i port is never high parameter bit Secure = 1'b0, // use prim count for pointers // derived parameter localparam int DepthW = prim_util_pkg::vbits(Depth+1) @@ -46,7 +52,7 @@ module prim_fifo_sync #( // host facing assign wready_o = rready_i; - assign full_o = rready_i; + assign full_o = 1'b1; // this avoids lint warnings logic unused_clr; @@ -55,6 +61,81 @@ module prim_fifo_sync #( // No error assign err_o = 1'b 0; + // FIFO has space for a single element (and doesn't need proper counters) + end else if (Depth == 1) begin : gen_singleton_fifo + + // full_q is true if the (singleton) queue has data + logic full_d, full_q; + + assign full_o = full_q; + assign depth_o = full_q; + assign wready_o = ~full_q; + + // We can always read from the storage if it contains something, so rvalid_o is true if full_q + // is true. Enabling pass-through mode also allows data to flow through if wvalid_i is true. + assign rvalid_o = full_q || (Pass && wvalid_i); + + // For there to be data on the next cycle, there must either be new data coming in (so !rvalid_o + // && wvalid_i) or we must be keeping the current data (so rvalid_o && !rready_i). Using + // rvalid_o instead of full_q ensures we get the right behaviour with pass-through. + // + // In either case, any stored data will be forgotten if clr_i is true. + assign full_d = (rvalid_o ? !rready_i : wvalid_i) && !clr_i; + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + full_q <= 1'b0; + end else begin + full_q <= full_d; + end + end + + logic [Width-1:0] storage; + always_ff @(posedge clk_i) begin + if (wvalid_i && wready_o) storage <= wdata_i; + end + + logic [Width-1:0] rdata_int; + assign rdata_int = (full_q || Pass == 1'b0) ? storage : wdata_i; + + assign rdata_o = (OutputZeroIfEmpty && !rvalid_o) ? Width'(0) : rdata_int; + + // The larger FIFO implementation uses prim_count for read and write pointers. If Secure is + // true, prim_count duplicates and checks these pointers to guard against fault injection. We do + // something similar here, duplicating and checking a "1 bit counter". + // + // The duplication is inverted, which means we expect full_q ^ inv_full to be true and generate + // an error signal if it is not. This error signal gets registered to avoid potential CDC issues + // downstream. + if (!Secure) begin : gen_not_secure + assign err_o = 1'b0; + end else begin : gen_secure + logic inv_full; + + prim_flop #( + .Width(1), + .ResetValue(1'b1) + ) u_inv_full ( + .clk_i, + .rst_ni, + .d_i (~full_d), + .q_o (inv_full) + ); + + logic err_d, err_q; + assign err_d = ~(full_q ^ inv_full); + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + err_q <= 1'b0; + end else begin + err_q <= err_d; + end + end + + assign err_o = err_q; + end + // Normal FIFO construction end else begin : gen_normal_fifo @@ -79,11 +160,11 @@ module prim_fifo_sync #( // The latter can be '0' when under reset, while the former is an indication that no more // entries can be written. assign wready_o = ~full_o & ~under_rst; - assign rvalid_o = ~empty & ~under_rst; prim_fifo_sync_cnt #( .Depth(Depth), - .Secure(Secure) + .Secure(Secure), + .NeverClears(NeverClears) ) u_fifo_cnt ( .clk_i, .rst_ni, @@ -97,41 +178,28 @@ module prim_fifo_sync #( .depth_o, .err_o ); - assign fifo_incr_wptr = wvalid_i & wready_o & ~under_rst; + assign fifo_incr_wptr = wvalid_i & wready_o; assign fifo_incr_rptr = rvalid_o & rready_i & ~under_rst; - // the generate blocks below are needed to avoid lint errors due to array indexing - // in the where the fifo only has one storage element logic [Depth-1:0][Width-1:0] storage; logic [Width-1:0] storage_rdata; - if (Depth == 1) begin : gen_depth_eq1 - assign storage_rdata = storage[0]; - always_ff @(posedge clk_i) - if (fifo_incr_wptr) begin - storage[0] <= wdata_i; - end + assign storage_rdata = storage[fifo_rptr]; - logic unused_ptrs; - assign unused_ptrs = ^{fifo_wptr, fifo_rptr}; - - // fifo with more than one storage element - end else begin : gen_depth_gt1 - assign storage_rdata = storage[fifo_rptr]; - - always_ff @(posedge clk_i) - if (fifo_incr_wptr) begin - storage[fifo_wptr] <= wdata_i; - end - end + always_ff @(posedge clk_i) + if (fifo_incr_wptr) begin + storage[fifo_wptr] <= wdata_i; + end logic [Width-1:0] rdata_int; if (Pass == 1'b1) begin : gen_pass assign rdata_int = (fifo_empty && wvalid_i) ? wdata_i : storage_rdata; assign empty = fifo_empty & ~wvalid_i; + assign rvalid_o = ~empty & ~under_rst; end else begin : gen_nopass assign rdata_int = storage_rdata; assign empty = fifo_empty; + assign rvalid_o = ~empty; end if (OutputZeroIfEmpty == 1'b1) begin : gen_output_zero @@ -141,16 +209,34 @@ module prim_fifo_sync #( end `ASSERT(depthShallNotExceedParamDepth, !empty |-> depth_o <= DepthW'(Depth)) + `ASSERT(OnlyRvalidWhenNotUnderRst_A, rvalid_o -> ~under_rst) end // block: gen_normal_fifo + if (NeverClears) begin : gen_never_clears + `ASSERT(NeverClears_A, !clr_i) + end + ////////////////////// // Known Assertions // ////////////////////// - `ASSERT(DataKnown_A, rvalid_o |-> !$isunknown(rdata_o)) + `ASSERT_KNOWN_IF(DataKnown_A, rdata_o, rvalid_o) `ASSERT_KNOWN(DepthKnown_A, depth_o) `ASSERT_KNOWN(RvalidKnown_A, rvalid_o) `ASSERT_KNOWN(WreadyKnown_A, wready_o) +`ifdef INC_ASSERT + // When Depth=1 and Secure=1, there is a specialized countermeasure that works by replicating + // the full_q flag. To set the logic value below to one, the user must use the + // ASSERT_PRIM_FIFO_SYNC_SINGLETON_ERROR_TRIGGER_ALERT macro (which checks that the error signal + // causes an alert). + // + // If the user hasn't done so, unused_assert_connected will be zero and ASSERT_INIT_NET will + // fail. + logic unused_assert_connected; + if (Depth == 1 && Secure) begin : gen_secure_singleton + `ASSERT_INIT_NET(AssertConnected_A, unused_assert_connected === 1'b1) + end +`endif endmodule diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_sync_cnt.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_sync_cnt.sv index 1f0670ddb7..7595a513a4 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_sync_cnt.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_sync_cnt.sv @@ -11,6 +11,8 @@ module prim_fifo_sync_cnt #( parameter int unsigned Depth = 4, // Whether to instantiate hardened counters parameter bit Secure = 1'b0, + // If this is set, the clr_i port will always be false + parameter bit NeverClears = 1'b0, // Width of the read and write pointers for the FIFO localparam int unsigned PtrW = prim_util_pkg::vbits(Depth), // Width of the 'current depth' output @@ -72,7 +74,9 @@ module prim_fifo_sync_cnt #( if (Secure) begin : gen_secure_ptrs logic wptr_err; prim_count #( - .Width(WrapPtrW) + .Width(WrapPtrW), + .PossibleActions((NeverClears ? 0 : prim_count_pkg::Clr) | + prim_count_pkg::Set | prim_count_pkg::Incr) ) u_wptr ( .clk_i, .rst_ni, @@ -90,7 +94,9 @@ module prim_fifo_sync_cnt #( logic rptr_err; prim_count #( - .Width(WrapPtrW) + .Width(WrapPtrW), + .PossibleActions((NeverClears ? 0 : prim_count_pkg::Clr) | + prim_count_pkg::Set | prim_count_pkg::Incr) ) u_rptr ( .clk_i, .rst_ni, @@ -136,4 +142,8 @@ module prim_fifo_sync_cnt #( assign err_o = '0; end + if (NeverClears) begin : gen_never_clears + `ASSERT(NeverClears_A, !clr_i) + end + endmodule // prim_fifo_sync_cnt diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_gf_mult.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_gf_mult.sv index f8f34eea69..de7e101bc7 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_gf_mult.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_gf_mult.sv @@ -3,7 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 // // This module performs a the multiplication of two operands in Galois field GF(2^Width) modulo the -// provided irreducible polynomial using a parallel Mastrovito multipler [3]. To cut long paths +// provided irreducible polynomial using a parallel Mastrovito multiplier [3]. To cut long paths // potentially occurring for large data widths, the implementation provides a parameter // StagesPerCycle to decompose the multiplication into Width/StagesPerCycle iterative steps // (Digit-Serial/Parallel Multiplier [4]). 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 e2a6e438f2..0332ee3f52 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_intr_hw.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_intr_hw.sv @@ -14,6 +14,8 @@ // - INTR_STATE : the current state of the interrupt (may be RO or W1C depending on "IntrT") // - INTR_TEST : sw-access-only register which asserts the interrupt for testing purposes +`include "prim_assert.sv" + module prim_intr_hw # ( // This module can be instantiated once per interrupt field (Width == 1), or // "bussified" with all fields of the interrupt vector (Width == $width(vec)). diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_keccak.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_keccak.sv index 42984515c3..76c1f23ac6 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_keccak.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_keccak.sv @@ -2,7 +2,10 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 // -// prim_keccak is single round permutation module +// This module implements a single-round Keccak permutation. It is unhardened. For an +// implementation with side-channel hardening, refer to the keccak_2share module used in the +// KMAC hardware IP block. + `include "prim_assert.sv" module prim_keccak #( parameter int Width = 1600, // b= {25, 50, 100, 200, 400, 800, 1600} diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sender.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sender.sv index 849eba82fc..00445c4231 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sender.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sender.sv @@ -52,7 +52,7 @@ module prim_lc_sender #( // This unused companion logic helps remove lint errors // for modules where clock and reset are used for assertions only // or nothing at all. - // This logic will be removed for sythesis since it is unloaded. + // This logic will be removed for synthesis since it is unloaded. lc_ctrl_pkg::lc_tx_t unused_logic; always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sync.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sync.sv index 5f2f7d5ff7..1f5e057023 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sync.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sync.sv @@ -6,7 +6,7 @@ // 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 +// https://opentitan.org/book/hw/ip/lc_ctrl/doc/interfaces.html#control-signal-propagation `include "prim_assert.sv" diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_leading_one_ppc.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_leading_one_ppc.sv new file mode 100644 index 0000000000..de1e017f7f --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_leading_one_ppc.sv @@ -0,0 +1,42 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Leading one detector based on parallel prefix computation +// See also: prim_arbiter_ppc + +module prim_leading_one_ppc #( + parameter int unsigned N = 8, + localparam int IdxW = prim_util_pkg::vbits(N) +) ( + input [ N-1:0] in_i, + output logic [ N-1:0] leading_one_o, + output logic [ N-1:0] ppc_out_o, + output logic [IdxW-1:0] idx_o +); + logic [N-1:0] ppc_out; + + // PPC + // Even below code looks O(n) but DC optimizes it to O(log(N)) + // Using Parallel Prefix Computation + always_comb begin + ppc_out[0] = in_i[0]; + for (int i = 1 ; i < N ; i++) begin + ppc_out[i] = ppc_out[i-1] | in_i[i]; + end + end + + // Leading-One detector + assign leading_one_o = ppc_out ^ {ppc_out[N-2:0], 1'b0}; + assign ppc_out_o = ppc_out; + + always_comb begin + idx_o = '0; + for (int unsigned i = 0 ; i < N ; i++) begin + if (leading_one_o[i]) begin + idx_o = i[IdxW-1:0]; + end + end + end + +endmodule diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_lfsr.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_lfsr.sv index e2400a101d..ba15006473 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_lfsr.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_lfsr.sv @@ -419,7 +419,6 @@ module prim_lfsr #( // Check that the permutation is indeed a permutation. logic [LfsrDw-1:0] sbox_perm_test; always_comb begin : p_perm_check - sbox_perm_test = '0; for (int k = 0; k < LfsrDw; k++) begin sbox_perm_test[sbox_in_indices[k]] = 1'b1; end diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi12_sender.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi12_sender.sv index 168b39e175..8990d44a91 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi12_sender.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi12_sender.sv @@ -49,7 +49,7 @@ module prim_mubi12_sender // This unused companion logic helps remove lint errors // for modules where clock and reset are used for assertions only - // This logic will be removed for sythesis since it is unloaded. + // This logic will be removed for synthesis since it is unloaded. mubi12_t unused_logic; always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi12_sync.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi12_sync.sv index 6376682d3d..54795a3e6e 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi12_sync.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi12_sync.sv @@ -26,7 +26,7 @@ module prim_mubi12_sync // This controls whether the mubi module institutes stability checks when // AsyncOn is set. If stability checks are on, a 3rd stage of storage is // added after the synchronizers and the outputs only updated if the 3rd - // stage and sychronizer agree. If they do not agree, the ResetValue is + // stage and synchronizer agree. If they do not agree, the ResetValue is // output instead. parameter bit StabilityCheck = 0, // Reset value for the sync flops diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi16_sender.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi16_sender.sv index 190d13435f..d2c2033a72 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi16_sender.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi16_sender.sv @@ -49,7 +49,7 @@ module prim_mubi16_sender // This unused companion logic helps remove lint errors // for modules where clock and reset are used for assertions only - // This logic will be removed for sythesis since it is unloaded. + // This logic will be removed for synthesis since it is unloaded. mubi16_t unused_logic; always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi16_sync.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi16_sync.sv index f73f5bb2e9..d7f28f8546 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi16_sync.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi16_sync.sv @@ -26,7 +26,7 @@ module prim_mubi16_sync // This controls whether the mubi module institutes stability checks when // AsyncOn is set. If stability checks are on, a 3rd stage of storage is // added after the synchronizers and the outputs only updated if the 3rd - // stage and sychronizer agree. If they do not agree, the ResetValue is + // stage and synchronizer agree. If they do not agree, the ResetValue is // output instead. parameter bit StabilityCheck = 0, // Reset value for the sync flops diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi20_sender.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi20_sender.sv index 73fc7d021c..9bc0a42d75 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi20_sender.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi20_sender.sv @@ -49,7 +49,7 @@ module prim_mubi20_sender // This unused companion logic helps remove lint errors // for modules where clock and reset are used for assertions only - // This logic will be removed for sythesis since it is unloaded. + // This logic will be removed for synthesis since it is unloaded. mubi20_t unused_logic; always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi20_sync.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi20_sync.sv index e54c6214fa..8aef14c249 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi20_sync.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi20_sync.sv @@ -26,7 +26,7 @@ module prim_mubi20_sync // This controls whether the mubi module institutes stability checks when // AsyncOn is set. If stability checks are on, a 3rd stage of storage is // added after the synchronizers and the outputs only updated if the 3rd - // stage and sychronizer agree. If they do not agree, the ResetValue is + // stage and synchronizer agree. If they do not agree, the ResetValue is // output instead. parameter bit StabilityCheck = 0, // Reset value for the sync flops diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi24_sender.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi24_sender.sv index d01239b660..cd37deeae7 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi24_sender.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi24_sender.sv @@ -49,7 +49,7 @@ module prim_mubi24_sender // This unused companion logic helps remove lint errors // for modules where clock and reset are used for assertions only - // This logic will be removed for sythesis since it is unloaded. + // This logic will be removed for synthesis since it is unloaded. mubi24_t unused_logic; always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi24_sync.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi24_sync.sv index f7a5328145..63b070b8a8 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi24_sync.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi24_sync.sv @@ -26,7 +26,7 @@ module prim_mubi24_sync // This controls whether the mubi module institutes stability checks when // AsyncOn is set. If stability checks are on, a 3rd stage of storage is // added after the synchronizers and the outputs only updated if the 3rd - // stage and sychronizer agree. If they do not agree, the ResetValue is + // stage and synchronizer agree. If they do not agree, the ResetValue is // output instead. parameter bit StabilityCheck = 0, // Reset value for the sync flops diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi28_sender.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi28_sender.sv index 633a693a61..57c98e65ef 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi28_sender.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi28_sender.sv @@ -49,7 +49,7 @@ module prim_mubi28_sender // This unused companion logic helps remove lint errors // for modules where clock and reset are used for assertions only - // This logic will be removed for sythesis since it is unloaded. + // This logic will be removed for synthesis since it is unloaded. mubi28_t unused_logic; always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi28_sync.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi28_sync.sv index 1c63536b7c..f598184687 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi28_sync.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi28_sync.sv @@ -26,7 +26,7 @@ module prim_mubi28_sync // This controls whether the mubi module institutes stability checks when // AsyncOn is set. If stability checks are on, a 3rd stage of storage is // added after the synchronizers and the outputs only updated if the 3rd - // stage and sychronizer agree. If they do not agree, the ResetValue is + // stage and synchronizer agree. If they do not agree, the ResetValue is // output instead. parameter bit StabilityCheck = 0, // Reset value for the sync flops diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi32_sender.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi32_sender.sv index ba6343c84c..2c12cc42db 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi32_sender.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi32_sender.sv @@ -49,7 +49,7 @@ module prim_mubi32_sender // This unused companion logic helps remove lint errors // for modules where clock and reset are used for assertions only - // This logic will be removed for sythesis since it is unloaded. + // This logic will be removed for synthesis since it is unloaded. mubi32_t unused_logic; always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi32_sync.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi32_sync.sv index afae3b316a..019aceda77 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi32_sync.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi32_sync.sv @@ -26,7 +26,7 @@ module prim_mubi32_sync // This controls whether the mubi module institutes stability checks when // AsyncOn is set. If stability checks are on, a 3rd stage of storage is // added after the synchronizers and the outputs only updated if the 3rd - // stage and sychronizer agree. If they do not agree, the ResetValue is + // stage and synchronizer agree. If they do not agree, the ResetValue is // output instead. parameter bit StabilityCheck = 0, // Reset value for the sync flops diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi4_sender.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi4_sender.sv index b69eefd275..1278046507 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi4_sender.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi4_sender.sv @@ -49,7 +49,7 @@ module prim_mubi4_sender // This unused companion logic helps remove lint errors // for modules where clock and reset are used for assertions only - // This logic will be removed for sythesis since it is unloaded. + // This logic will be removed for synthesis since it is unloaded. mubi4_t unused_logic; always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi4_sync.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi4_sync.sv index b5aa0aa194..2ef5edfd81 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi4_sync.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi4_sync.sv @@ -26,7 +26,7 @@ module prim_mubi4_sync // This controls whether the mubi module institutes stability checks when // AsyncOn is set. If stability checks are on, a 3rd stage of storage is // added after the synchronizers and the outputs only updated if the 3rd - // stage and sychronizer agree. If they do not agree, the ResetValue is + // stage and synchronizer agree. If they do not agree, the ResetValue is // output instead. parameter bit StabilityCheck = 0, // Reset value for the sync flops diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi8_sender.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi8_sender.sv index e3379ad6b6..0324d57f1b 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi8_sender.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi8_sender.sv @@ -49,7 +49,7 @@ module prim_mubi8_sender // This unused companion logic helps remove lint errors // for modules where clock and reset are used for assertions only - // This logic will be removed for sythesis since it is unloaded. + // This logic will be removed for synthesis since it is unloaded. mubi8_t unused_logic; always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi8_sync.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi8_sync.sv index 9e1151dd8b..1d0f29bb9d 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi8_sync.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi8_sync.sv @@ -26,7 +26,7 @@ module prim_mubi8_sync // This controls whether the mubi module institutes stability checks when // AsyncOn is set. If stability checks are on, a 3rd stage of storage is // added after the synchronizers and the outputs only updated if the 3rd - // stage and sychronizer agree. If they do not agree, the ResetValue is + // stage and synchronizer agree. If they do not agree, the ResetValue is // output instead. parameter bit StabilityCheck = 0, // Reset value for the sync flops diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi_pkg.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi_pkg.sv index 0277329a8c..9ff2aac60c 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi_pkg.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi_pkg.sv @@ -37,13 +37,20 @@ package prim_mubi_pkg; return (val ? MuBi4True : MuBi4False); endfunction : mubi4_bool_to_mubi - // Test whether the multibit value signals an "enabled" condition. + // Test whether the multibit value of type "mubi4_t" signals an "enabled" condition. // The strict version of this function requires // the multibit value to equal True. function automatic logic mubi4_test_true_strict(mubi4_t val); return MuBi4True == val; endfunction : mubi4_test_true_strict + // Test whether the multibit value of type "logic vector" signals an "enabled" condition. + // The strict version of this function requires + // the multibit value to equal True. + function automatic logic mubi4_logic_test_true_strict(logic [3:0] val); + return MuBi4True == val; + endfunction : mubi4_logic_test_true_strict + // Test whether the multibit value signals a "disabled" condition. // The strict version of this function requires // the multibit value to equal False. @@ -169,13 +176,20 @@ package prim_mubi_pkg; return (val ? MuBi8True : MuBi8False); endfunction : mubi8_bool_to_mubi - // Test whether the multibit value signals an "enabled" condition. + // Test whether the multibit value of type "mubi8_t" signals an "enabled" condition. // The strict version of this function requires // the multibit value to equal True. function automatic logic mubi8_test_true_strict(mubi8_t val); return MuBi8True == val; endfunction : mubi8_test_true_strict + // Test whether the multibit value of type "logic vector" signals an "enabled" condition. + // The strict version of this function requires + // the multibit value to equal True. + function automatic logic mubi8_logic_test_true_strict(logic [7:0] val); + return MuBi8True == val; + endfunction : mubi8_logic_test_true_strict + // Test whether the multibit value signals a "disabled" condition. // The strict version of this function requires // the multibit value to equal False. @@ -301,13 +315,20 @@ package prim_mubi_pkg; return (val ? MuBi12True : MuBi12False); endfunction : mubi12_bool_to_mubi - // Test whether the multibit value signals an "enabled" condition. + // Test whether the multibit value of type "mubi12_t" signals an "enabled" condition. // The strict version of this function requires // the multibit value to equal True. function automatic logic mubi12_test_true_strict(mubi12_t val); return MuBi12True == val; endfunction : mubi12_test_true_strict + // Test whether the multibit value of type "logic vector" signals an "enabled" condition. + // The strict version of this function requires + // the multibit value to equal True. + function automatic logic mubi12_logic_test_true_strict(logic [11:0] val); + return MuBi12True == val; + endfunction : mubi12_logic_test_true_strict + // Test whether the multibit value signals a "disabled" condition. // The strict version of this function requires // the multibit value to equal False. @@ -433,13 +454,20 @@ package prim_mubi_pkg; return (val ? MuBi16True : MuBi16False); endfunction : mubi16_bool_to_mubi - // Test whether the multibit value signals an "enabled" condition. + // Test whether the multibit value of type "mubi16_t" signals an "enabled" condition. // The strict version of this function requires // the multibit value to equal True. function automatic logic mubi16_test_true_strict(mubi16_t val); return MuBi16True == val; endfunction : mubi16_test_true_strict + // Test whether the multibit value of type "logic vector" signals an "enabled" condition. + // The strict version of this function requires + // the multibit value to equal True. + function automatic logic mubi16_logic_test_true_strict(logic [15:0] val); + return MuBi16True == val; + endfunction : mubi16_logic_test_true_strict + // Test whether the multibit value signals a "disabled" condition. // The strict version of this function requires // the multibit value to equal False. @@ -565,13 +593,20 @@ package prim_mubi_pkg; return (val ? MuBi20True : MuBi20False); endfunction : mubi20_bool_to_mubi - // Test whether the multibit value signals an "enabled" condition. + // Test whether the multibit value of type "mubi20_t" signals an "enabled" condition. // The strict version of this function requires // the multibit value to equal True. function automatic logic mubi20_test_true_strict(mubi20_t val); return MuBi20True == val; endfunction : mubi20_test_true_strict + // Test whether the multibit value of type "logic vector" signals an "enabled" condition. + // The strict version of this function requires + // the multibit value to equal True. + function automatic logic mubi20_logic_test_true_strict(logic [19:0] val); + return MuBi20True == val; + endfunction : mubi20_logic_test_true_strict + // Test whether the multibit value signals a "disabled" condition. // The strict version of this function requires // the multibit value to equal False. @@ -697,13 +732,20 @@ package prim_mubi_pkg; return (val ? MuBi24True : MuBi24False); endfunction : mubi24_bool_to_mubi - // Test whether the multibit value signals an "enabled" condition. + // Test whether the multibit value of type "mubi24_t" signals an "enabled" condition. // The strict version of this function requires // the multibit value to equal True. function automatic logic mubi24_test_true_strict(mubi24_t val); return MuBi24True == val; endfunction : mubi24_test_true_strict + // Test whether the multibit value of type "logic vector" signals an "enabled" condition. + // The strict version of this function requires + // the multibit value to equal True. + function automatic logic mubi24_logic_test_true_strict(logic [23:0] val); + return MuBi24True == val; + endfunction : mubi24_logic_test_true_strict + // Test whether the multibit value signals a "disabled" condition. // The strict version of this function requires // the multibit value to equal False. @@ -829,13 +871,20 @@ package prim_mubi_pkg; return (val ? MuBi28True : MuBi28False); endfunction : mubi28_bool_to_mubi - // Test whether the multibit value signals an "enabled" condition. + // Test whether the multibit value of type "mubi28_t" signals an "enabled" condition. // The strict version of this function requires // the multibit value to equal True. function automatic logic mubi28_test_true_strict(mubi28_t val); return MuBi28True == val; endfunction : mubi28_test_true_strict + // Test whether the multibit value of type "logic vector" signals an "enabled" condition. + // The strict version of this function requires + // the multibit value to equal True. + function automatic logic mubi28_logic_test_true_strict(logic [27:0] val); + return MuBi28True == val; + endfunction : mubi28_logic_test_true_strict + // Test whether the multibit value signals a "disabled" condition. // The strict version of this function requires // the multibit value to equal False. @@ -961,13 +1010,20 @@ package prim_mubi_pkg; return (val ? MuBi32True : MuBi32False); endfunction : mubi32_bool_to_mubi - // Test whether the multibit value signals an "enabled" condition. + // Test whether the multibit value of type "mubi32_t" signals an "enabled" condition. // The strict version of this function requires // the multibit value to equal True. function automatic logic mubi32_test_true_strict(mubi32_t val); return MuBi32True == val; endfunction : mubi32_test_true_strict + // Test whether the multibit value of type "logic vector" signals an "enabled" condition. + // The strict version of this function requires + // the multibit value to equal True. + function automatic logic mubi32_logic_test_true_strict(logic [31:0] val); + return MuBi32True == val; + endfunction : mubi32_logic_test_true_strict + // Test whether the multibit value signals a "disabled" condition. // The strict version of this function requires // the multibit value to equal False. diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_otp_pkg.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_otp_pkg.sv deleted file mode 100644 index cefe43a57f..0000000000 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_otp_pkg.sv +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright lowRISC contributors (OpenTitan project). -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -// Common interface definitions for OTP primitives. - -package prim_otp_pkg; - - // The command is sparsely encoded to make it more difficult to tamper with. - parameter int CmdWidth = 7; - parameter int ErrWidth = 3; - - // Encoding generated with: - // $ ./util/design/sparse-fsm-encode.py -d 4 -m 5 -n 7 \ - // -s 696743973 --language=sv - // - // Hamming distance histogram: - // - // 0: -- - // 1: -- - // 2: -- - // 3: -- - // 4: |||||||||||||||||||| (100.00%) - // 5: -- - // 6: -- - // 7: -- - // - // Minimum Hamming distance: 4 - // Maximum Hamming distance: 4 - // Minimum Hamming weight: 3 - // Maximum Hamming weight: 5 - // - typedef enum logic [CmdWidth-1:0] { - Read = 7'b1000101, - Write = 7'b0110111, - // Raw commands ignore integrity - ReadRaw = 7'b1111001, - WriteRaw = 7'b1100010, - Init = 7'b0101100 - } cmd_e; - - typedef enum logic [ErrWidth-1:0] { - NoError = 3'h0, - MacroError = 3'h1, - MacroEccCorrError = 3'h2, - MacroEccUncorrError = 3'h3, - MacroWriteBlankError = 3'h4 - } err_e; - -endpackage : prim_otp_pkg diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_packer.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_packer.sv index 76339b4291..96f4b77626 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_packer.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_packer.sv @@ -102,7 +102,7 @@ module prim_packer #( // incr_en: Increase the pos by cnt_step. ack_in && !ack_out // decr_en: Decrease the pos by cnt_step. !ack_in && ack_out // set_en: Set to specific value in case of ack_in && ack_out. - // This case, the value could be increased or descreased based on + // This case, the value could be increased or decreased based on // the input size (inmask_ones) logic cnt_incr_en, cnt_decr_en, cnt_set_en; logic [PtrW-1:0] cnt_step, cnt_set; diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_pad_wrapper_pkg.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_pad_wrapper_pkg.sv index 668706698e..ab1f04c382 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_pad_wrapper_pkg.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_pad_wrapper_pkg.sv @@ -17,7 +17,8 @@ package prim_pad_wrapper_pkg; typedef enum logic [1:0] { NoScan = 2'h0, ScanIn = 2'h1, - ScanOut = 2'h2 + ScanOut = 2'h2, + ScanClock = 2'h3 } scan_role_e; // Pad attributes diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_prince.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_prince.sv index 5878823d4a..b193e0d8d4 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_prince.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_prince.sv @@ -69,7 +69,7 @@ module prim_prince #( // In this case we constantly use k1. assign k0_new_d = k1_d; end else begin : gen_new_keyschedule - // Imroved keyschedule proposed by https://eprint.iacr.org/2014/656.pdf + // Improved 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[2*DataWidth-1 : DataWidth]; diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_pulse_sync.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_pulse_sync.sv index 44d9b5f86e..13ed595d08 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_pulse_sync.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_pulse_sync.sv @@ -11,6 +11,8 @@ // Also note that a reset of either the source domain or the destination domain // in isolation may create a pulse at the destination. +`include "prim_assert.sv" + module prim_pulse_sync ( // source clock domain input logic clk_src_i, diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_racl_error_arb.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_racl_error_arb.sv new file mode 100644 index 0000000000..84f15e4d2c --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_racl_error_arb.sv @@ -0,0 +1,62 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +module prim_racl_error_arb + import top_racl_pkg::*; +#( + parameter int unsigned N = 8 +) ( + input logic clk_i, + input logic rst_ni, + input racl_error_log_t error_log_i[N], + output racl_error_log_t error_log_o +); + // Extract error valid to be used for the arbiter as a request signal + logic [N-1:0] error_valid, any_valid_overflow; + for (genvar i = 0; i < N; i++) begin : gen_extract_valid + assign error_valid[i] = error_log_i[i].valid; + assign any_valid_overflow[i] = error_log_i[i].valid & error_log_i[i].overflow; + end + + // If there are multiple errors in the same cycle, arbitrate and get the first error. + // Lower index in error_valid has higher priority. + logic [$bits(racl_error_log_t)-1:0] racl_error_logic; + racl_error_log_t racl_error_arb; + logic [N-1:0] gnt; + + prim_arbiter_fixed #( + .N ( N ), + .DW ( $bits(racl_error_log_t) ) + ) u_prim_err_arb ( + .clk_i, + .rst_ni, + .req_i ( error_valid ), + .data_i ( error_log_i ), + .gnt_o ( gnt ), + .idx_o ( ), + .valid_o ( ), + .data_o ( racl_error_logic ), + .ready_i ( 1'b1 ) + ); + assign racl_error_arb = racl_error_log_t'(racl_error_logic); + + // Assert the overflow if: + // 1. a valid incoming error already asserted the overflow + // 2. there are multiple errors occurring simultaneously, but only one is granted by the + // arbiter. See if another request is there besides out the masked granted one. + logic overflow; + assign overflow = |any_valid_overflow | (racl_error_arb.valid & |(error_valid & ~gnt)); + + // Assemble dinal arbitrated RACL error based on the arbitrated error and the computed overflow. + assign error_log_o.valid = racl_error_arb.valid; + assign error_log_o.racl_role = racl_error_arb.racl_role; + assign error_log_o.ctn_uid = racl_error_arb.ctn_uid; + assign error_log_o.read_access = racl_error_arb.read_access; + assign error_log_o.request_address = racl_error_arb.request_address; + assign error_log_o.overflow = overflow; + + // Arbitrated overflow is not used + logic unused_signals; + assign unused_signals = racl_error_arb.overflow; +endmodule 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 73a973e3df..83087d2b2b 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 @@ -17,6 +17,9 @@ module prim_ram_1p_adv import prim_ram_1p_pkg::*; #( parameter int Depth = 512, + // Setting InstDepth to a smaller value than Depth enables RAM tiling. RAM is tiled to + // ceil(Depth/InstDepth) prim_ram_1p instances, each InstDepth deep. + parameter int InstDepth = Depth, parameter int Width = 32, parameter int DataBitsPerMask = 1, // Number of data bits per bit of write mask parameter MemInitFile = "", // VMEM file to initialize the memory with @@ -32,25 +35,29 @@ module prim_ram_1p_adv import prim_ram_1p_pkg::*; #( // since this results in a more compact and faster implementation. parameter bit HammingECC = 0, - localparam int Aw = prim_util_pkg::vbits(Depth) + localparam int Aw = prim_util_pkg::vbits(Depth), + // Compute RAM tiling + localparam int NumRamInst = prim_util_pkg::ceil_div(Depth, InstDepth), + localparam int InstAw = prim_util_pkg::vbits(InstDepth) ) ( input clk_i, input rst_ni, - input req_i, - input write_i, - input [Aw-1:0] addr_i, - input [Width-1:0] wdata_i, - input [Width-1:0] wmask_i, - 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 + input req_i, + input write_i, + input [Aw-1:0] addr_i, + input [Width-1:0] wdata_i, + input [Width-1:0] wmask_i, + 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 // config - input ram_1p_cfg_t cfg_i, + input ram_1p_cfg_t [NumRamInst-1:0] cfg_i, + output ram_1p_cfg_rsp_t [NumRamInst-1:0] cfg_rsp_o, // When detecting multi-bit encoding errors, raise alert. - output logic alert_o + output logic alert_o ); import prim_mubi_pkg::mubi4_t; @@ -58,6 +65,7 @@ module prim_ram_1p_adv import prim_ram_1p_pkg::*; #( import prim_mubi_pkg::mubi4_bool_to_mubi; import prim_mubi_pkg::mubi4_test_invalid; import prim_mubi_pkg::mubi4_test_true_loose; + import prim_mubi_pkg::mubi4_test_true_strict; import prim_mubi_pkg::MuBi4True; import prim_mubi_pkg::MuBi4False; import prim_mubi_pkg::MuBi4Width; @@ -74,7 +82,7 @@ module prim_ram_1p_adv import prim_ram_1p_pkg::*; #( (Width <= 120) ? 8 : 8 ; localparam int TotalWidth = Width + ParWidth; - // If byte parity is enabled, the write enable bits are used to write memory colums + // If byte parity is enabled, the write enable bits are used to write memory columns // with 8 + 1 = 9 bit width (data plus corresponding parity bit). // If ECC is enabled, the DataBitsPerMask is ignored. localparam int LocalDataBitsPerMask = (EnableParity) ? 9 : @@ -102,23 +110,80 @@ module prim_ram_1p_adv import prim_ram_1p_pkg::*; #( assign req_q_b = mubi4_test_true_loose(req_q); assign write_q_b = mubi4_test_true_loose(write_q); - prim_ram_1p #( - .MemInitFile (MemInitFile), - - .Width (TotalWidth), - .Depth (Depth), - .DataBitsPerMask (LocalDataBitsPerMask) - ) u_mem ( - .clk_i, - - .req_i (req_q_b), - .write_i (write_q_b), - .addr_i (addr_q), - .wdata_i (wdata_q), - .wmask_i (wmask_q), - .rdata_o (rdata_sram), - .cfg_i - ); + logic [NumRamInst-1:0] inst_req_d, inst_req_q, rvalid_inst; + logic [InstAw-1:0] inst_addr; + logic [NumRamInst-1:0] [Width-1:0] inst_rdata; + + // The lower InstAw bits of the address are used to address within one RAM primitive + assign inst_addr = addr_q[InstAw-1:0]; + + // The upper bits Aw-1:InstAw of the address select which RAM instance is selected. A special case + // is needed when no tiling is performed and only a single RAM macro is instantiated. Here, we + // can directly use the request signal and no demuxing is needed. + if (NumRamInst == 1) begin : gen_single_inst_req + assign inst_req_d[0] = req_q_b; + end else begin : gen_multi_inst_req + always_comb begin + inst_req_d = '0; + + for (int i = 0; i < NumRamInst; i++) begin + if (req_q_b && (i == addr_q[Aw-1:InstAw])) begin + inst_req_d[i] = 1'b1; + end + end + end + end + + // Flop the instance request signal to know to know which + // tile to select for read data on the next cycle + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + inst_req_q <= '0; + end else begin + inst_req_q <= inst_req_d; + end + end + + // Ensure that only one RAM instance gets activated + `ASSERT(OneHotInstReq_A, $onehot0(inst_req_d)) + + for (genvar i = 0; i < NumRamInst; i++) begin : gen_ram_inst + prim_ram_1p #( + .MemInitFile (MemInitFile), + + .Width (TotalWidth), + .Depth (InstDepth), + .DataBitsPerMask (LocalDataBitsPerMask) + ) u_mem ( + .clk_i, + .rst_ni, + + .req_i (inst_req_d[i]), + .write_i (write_q_b), + .addr_i (inst_addr), + .wdata_i (wdata_q), + .wmask_i (wmask_q), + .rdata_o (inst_rdata[i]), + .cfg_i (cfg_i[i]), + .cfg_rsp_o (cfg_rsp_o[i]) + ); + end + + // Mux output data + always_comb begin + rdata_sram = '0; + + for (int i = 0; i < NumRamInst; i++) begin + // Determine which RAM tile we accessed based on the floped inst_req signal and we really + // got an rvalid. This determines if we mux the output data of that particular RAM tile. + rvalid_inst[i] = mubi4_test_true_strict( + mubi4_and_hi(mubi4_bool_to_mubi(inst_req_q[i]), rvalid_sram_q)); + + if(rvalid_inst[i]) begin + rdata_sram = inst_rdata[i]; + end + end + end assign rvalid_sram_d = mubi4_and_hi(req_q, mubi4_t'(~write_q)); 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 d31a7d5ca0..16a0732c67 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 @@ -25,6 +25,7 @@ module prim_ram_1p_scr import prim_ram_1p_pkg::*; #( parameter int Depth = 16*1024, // Needs to be a power of 2 if NumAddrScrRounds > 0. + parameter int InstDepth = Depth, parameter int Width = 32, // Needs to be byte aligned if byte parity is enabled. parameter int DataBitsPerMask = 8, // Needs to be set to 8 in case of byte parity. parameter bit EnableParity = 1, // Enable byte parity. @@ -58,39 +59,43 @@ module prim_ram_1p_scr import prim_ram_1p_pkg::*; #( // use the same key, but they use a different IV localparam int DataKeyWidth = 128, // Each 64 bit scrambling primitive requires a 64bit IV - localparam int NonceWidth = 64 * NumParScr + localparam int NonceWidth = 64 * NumParScr, + // Compute RAM tiling + localparam int NumRamInst = prim_util_pkg::ceil_div(Depth, InstDepth) ) ( - input clk_i, - input rst_ni, + input clk_i, + input rst_ni, // Key interface. Memory requests will not be granted if key_valid is set to 0. - input key_valid_i, - input [DataKeyWidth-1:0] key_i, - input [NonceWidth-1:0] nonce_i, + input key_valid_i, + input [DataKeyWidth-1:0] key_i, + input [NonceWidth-1:0] nonce_i, // Interface to TL-UL SRAM adapter - input req_i, - output logic gnt_o, - input write_i, - input [AddrWidth-1:0] addr_i, - input [Width-1:0] wdata_i, - input [Width-1:0] wmask_i, // Needs to be byte-aligned for parity + input req_i, + output logic gnt_o, + input write_i, + input [AddrWidth-1:0] addr_i, + input [Width-1:0] wdata_i, + input [Width-1:0] wmask_i, // Needs to be byte-aligned for parity // On integrity errors, the primitive surpresses any real transaction to the memory. - input intg_error_i, - 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 [31:0] raddr_o, // Read address for error reporting. + input intg_error_i, + 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 ram_1p_cfg_t cfg_i, + input ram_1p_cfg_t [NumRamInst-1:0] cfg_i, + output ram_1p_cfg_rsp_t [NumRamInst-1:0] cfg_rsp_o, + // Write currently pending inside this module. - output logic wr_collision_o, - output logic write_pending_o, + output logic wr_collision_o, + output logic write_pending_o, // When detecting multi-bit encoding errors, raise alert. - output logic alert_o + output logic alert_o ); import prim_mubi_pkg::mubi4_t; @@ -229,7 +234,7 @@ module prim_ram_1p_scr import prim_ram_1p_pkg::*; #( // We latch the non-scrambled address for error reporting. logic [AddrWidth-1:0] raddr_q; - assign raddr_o = 32'(raddr_q); + assign raddr_o = raddr_q; ////////////////////////////////////////////// // Keystream Generation for Data Scrambling // @@ -481,6 +486,7 @@ module prim_ram_1p_scr import prim_ram_1p_pkg::*; #( prim_ram_1p_adv #( .Depth(Depth), + .InstDepth(InstDepth), .Width(Width), .DataBitsPerMask(DataBitsPerMask), .EnableECC(1'b0), @@ -499,6 +505,7 @@ module prim_ram_1p_scr import prim_ram_1p_pkg::*; #( .rvalid_o ( ), .rerror_o, .cfg_i, + .cfg_rsp_o, .alert_o ( ram_alert ) ); diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1r1w_adv.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1r1w_adv.sv index a2924433c0..ff0511f1f9 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1r1w_adv.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1r1w_adv.sv @@ -50,7 +50,8 @@ module prim_ram_1r1w_adv import prim_ram_2p_pkg::*; #( output logic b_rvalid_o, // read response (b_rdata_o) is valid output logic [1:0] b_rerror_o, // Bit1: Uncorrectable, Bit0: Correctable - input ram_2p_cfg_t cfg_i + input ram_2p_cfg_t cfg_i, + output ram_2p_cfg_rsp_t cfg_rsp_o ); prim_ram_1r1w_async_adv #( @@ -77,7 +78,8 @@ module prim_ram_1r1w_adv import prim_ram_2p_pkg::*; #( .b_rdata_o, .b_rvalid_o, .b_rerror_o, - .cfg_i + .cfg_i, + .cfg_rsp_o ); endmodule : prim_ram_1r1w_adv diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1r1w_async_adv.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1r1w_async_adv.sv index 6e9d31b512..40e0697665 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1r1w_async_adv.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1r1w_async_adv.sv @@ -53,7 +53,8 @@ module prim_ram_1r1w_async_adv import prim_ram_2p_pkg::*; #( output logic [1:0] b_rerror_o, // Bit1: Uncorrectable, Bit0: Correctable // config - input ram_2p_cfg_t cfg_i + input ram_2p_cfg_t cfg_i, + output ram_2p_cfg_rsp_t cfg_rsp_o ); @@ -69,7 +70,7 @@ module prim_ram_1r1w_async_adv import prim_ram_2p_pkg::*; #( (Width <= 120) ? 8 : 8 ; localparam int TotalWidth = Width + ParWidth; - // If byte parity is enabled, the write enable bits are used to write memory colums + // If byte parity is enabled, the write enable bits are used to write memory columns // with 8 + 1 = 9 bit width (data plus corresponding parity bit). // If ECC is enabled, the DataBitsPerMask is ignored. localparam int LocalDataBitsPerMask = (EnableParity) ? 9 : @@ -101,6 +102,8 @@ module prim_ram_1r1w_async_adv import prim_ram_2p_pkg::*; #( ) u_mem ( .clk_a_i (clk_a_i), .clk_b_i (clk_b_i), + .rst_a_ni (rst_a_ni), + .rst_b_ni (rst_b_ni), .a_req_i (a_req_q), .a_addr_i (a_addr_q), @@ -111,7 +114,8 @@ module prim_ram_1r1w_async_adv import prim_ram_2p_pkg::*; #( .b_addr_i (b_addr_q), .b_rdata_o (b_rdata_sram), - .cfg_i + .cfg_i, + .cfg_rsp_o ); always_ff @(posedge clk_b_i or negedge rst_b_ni) begin 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 5c93fe2855..79f1a6191b 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 @@ -58,7 +58,8 @@ module prim_ram_2p_async_adv import prim_ram_2p_pkg::*; #( output logic [1:0] b_rerror_o, // Bit1: Uncorrectable, Bit0: Correctable // config - input ram_2p_cfg_t cfg_i + input ram_2p_cfg_t cfg_i, + output ram_2p_cfg_rsp_t cfg_rsp_o ); @@ -74,7 +75,7 @@ module prim_ram_2p_async_adv import prim_ram_2p_pkg::*; #( (Width <= 120) ? 8 : 8 ; localparam int TotalWidth = Width + ParWidth; - // If byte parity is enabled, the write enable bits are used to write memory colums + // If byte parity is enabled, the write enable bits are used to write memory columns // with 8 + 1 = 9 bit width (data plus corresponding parity bit). // If ECC is enabled, the DataBitsPerMask is ignored. localparam int LocalDataBitsPerMask = (EnableParity) ? 9 : @@ -129,7 +130,8 @@ module prim_ram_2p_async_adv import prim_ram_2p_pkg::*; #( .b_wmask_i (b_wmask_q), .b_rdata_o (b_rdata_sram), - .cfg_i + .cfg_i, + .cfg_rsp_o ); always_ff @(posedge clk_a_i or negedge rst_a_ni) begin diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_reg_cdc.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_reg_cdc.sv index 94a1f50c81..82fecedb8d 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_reg_cdc.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_reg_cdc.sv @@ -111,6 +111,24 @@ module prim_reg_cdc #( // This is the current destination value logic [DataWidth-1:0] dst_qs; logic src_update; + + // The dst_to_src signal (on the src clock) means that data should be moving from the dst clock + // domain to the src clock domain on this cycle. + // + // This either means that an operation from the src side is being acknowledged or (if it's + // possible for the value to change on the dst side) it means that a register read response is + // coming from the dst clock domain. The register value may have changed from last time so should + // be copied back. + logic dst_to_src; + if (DstWrReq) begin : gen_wr_req + assign dst_to_src = src_busy_q && src_ack || src_update && !busy; + end else begin : gen_passthru + assign dst_to_src = src_busy_q && src_ack; + + logic unused_dst_wr; + assign unused_dst_wr = src_update ^ busy; + end + always_ff @(posedge clk_src_i or negedge rst_src_ni) begin if (!rst_src_ni) begin src_q <= ResetVal; @@ -122,7 +140,7 @@ module prim_reg_cdc #( // change for the duration of the synchronization operation. src_q <= src_wd_i & BitMask; txn_bits_q <= {src_we_i, src_re_i, src_regwen_i}; - end else if (src_busy_q && src_ack || src_update && !busy) begin + end else if (dst_to_src) begin // sample data whenever a busy transaction finishes OR // when an update pulse is seen. // TODO: We should add a cover group to test different sync timings @@ -202,9 +220,21 @@ module prim_reg_cdc #( `ASSERT_KNOWN(SrcBusyKnown_A, src_busy_o, clk_src_i, !rst_src_ni) `ASSERT_KNOWN(DstReqKnown_A, dst_req, clk_dst_i, !rst_dst_ni) - // If busy goes high, we must eventually see an ack + // If busy goes high, we must eventually see an ack. + // + // This is fundamentally a liveness property and only really useful in a formal setting (since a + // simulation can never give a counterexample). Unfortunately, proving liveness properties can be + // intractable for formal tools. This assertion bounds the time, making it a safety property that + // the tool can handle more easily. + // + // The required bound depends on the ratio between the two clocks. If there are N edges of + // clk_dst_i for each edge of clk_src_i, we can expect a bound of 4*N to suffice (because there is + // a 2-flop synchroniser in each direction). + // + // The possible clock ratios rely on tool configuration, but we set N=10 (which matches the + // configuration for the main clock and the slow aon clock in our FPV tool setup). `ifdef FPV_ON - `ASSERT(HungHandShake_A, $rose(src_req) |-> strong(##[0:$] src_ack), clk_src_i, !rst_src_ni) + `ASSERT(HungHandShake_A, $rose(src_req) |-> ##[0:40] src_ack, clk_src_i, !rst_src_ni) // TODO: #14913 check if we can add additional sim assertions. `endif endmodule // prim_subreg_cdc diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_reg_cdc_arb.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_reg_cdc_arb.sv index 77fe83a414..3b0c096f7a 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_reg_cdc_arb.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_reg_cdc_arb.sv @@ -87,11 +87,6 @@ module prim_reg_cdc_arb #( SelHwReq } req_sel_e; - typedef enum logic [1:0] { - StIdle, - StWait - } state_e; - // Only honor the incoming destination update request if the incoming // value is actually different from what is already completed in the @@ -106,16 +101,15 @@ module prim_reg_cdc_arb #( logic dst_update_ack; req_sel_e id_q; - state_e state_q, state_d; + logic idle_q, idle_d; always_ff @(posedge clk_dst_i or negedge rst_dst_ni) begin if (!rst_dst_ni) begin - state_q <= StIdle; + idle_q <= 1'b1; end else begin - state_q <= state_d; + idle_q <= idle_d; end end - logic busy; logic dst_req_q, dst_req; always_ff @(posedge clk_dst_i or negedge rst_dst_ni) begin if (!rst_dst_ni) begin @@ -126,12 +120,19 @@ module prim_reg_cdc_arb #( // dst_lat_d is safe to used here because dst_req_q, if set, // always has priority over other hardware based events. dst_req_q <= '0; - end else if (dst_req_i && !dst_req_q && busy) begin + end else if (dst_req_i && !idle_q) begin // if destination request arrives when a handshake event // is already ongoing, hold on to request and send later dst_req_q <= 1'b1; end end + + // dst_req_q will be 0 when dst_req_i is set, this assertion checks the conditional branch + // (dst_req_i && !dst_req_q && !idle_q) can be simplified to avoid conditional coverage + // holes + `ASSERT(Not_Dst_req_q_while_dst_req_i_A, dst_req_i |-> !dst_req_q, + clk_dst_i, !rst_dst_ni) + assign dst_req = dst_req_q | dst_req_i; // Hold data at the beginning of a transaction @@ -154,7 +155,7 @@ module prim_reg_cdc_arb #( always_ff @(posedge clk_dst_i or negedge rst_dst_ni) begin if (!rst_dst_ni) begin id_q <= SelSwReq; - end else if (dst_update_req && dst_update_ack) begin + end else if (dst_update_ack) begin id_q <= SelSwReq; end else if (dst_req && dst_lat_d) begin id_q <= SelSwReq; @@ -165,9 +166,12 @@ module prim_reg_cdc_arb #( end end + // dst_update_ack should only be sent if there was a dst_update_req. + `ASSERT(DstAckReqChk_A, dst_update_ack |-> dst_update_req, clk_dst_i, !rst_dst_ni) + // if a destination update is received when the system is idle and there is no // software side request, hw update must be selected. - `ASSERT(DstUpdateReqCheck_A, ##1 dst_update & !dst_req & !busy |=> id_q == SelHwReq, + `ASSERT(DstUpdateReqCheck_A, ##1 dst_update & !dst_req & idle_q |=> id_q == SelHwReq, clk_dst_i, !rst_dst_ni) // if hw select was chosen, then it must be the case there was a destination update @@ -180,11 +184,11 @@ module prim_reg_cdc_arb #( // send out prim_subreg request only when proceeding // with software request - assign dst_req_o = ~busy & dst_req; + assign dst_req_o = idle_q & dst_req; logic dst_hold_req; always_comb begin - state_d = state_q; + idle_d = idle_q; dst_hold_req = '0; // depending on when the request is received, we @@ -192,37 +196,26 @@ module prim_reg_cdc_arb #( dst_lat_q = '0; dst_lat_d = '0; - busy = 1'b1; - - unique case (state_q) - StIdle: begin - busy = '0; - if (dst_req) begin - // there's a software issued request for change - state_d = StWait; - dst_lat_d = 1'b1; - end else if (dst_update) begin - state_d = StWait; - dst_lat_d = 1'b1; - end else if (dst_qs_o != dst_qs_i) begin - // there's a direct destination update - // that was blocked by an ongoing transaction - state_d = StWait; - dst_lat_q = 1'b1; - end - end - - StWait: begin - dst_hold_req = 1'b1; - if (dst_update_ack) begin - state_d = StIdle; - end + if (idle_q) begin + if (dst_req) begin + // there's a software issued request for change + idle_d = 1'b0; + dst_lat_d = 1'b1; + end else if (dst_update) begin + idle_d = 1'b0; + dst_lat_d = 1'b1; + end else if (dst_qs_o != dst_qs_i) begin + // there's a direct destination update + // that was blocked by an ongoing transaction + idle_d = 1'b0; + dst_lat_q = 1'b1; end - - default: begin - state_d = StIdle; + end else begin + dst_hold_req = 1'b1; + if (dst_update_ack) begin + idle_d = 1'b1; end - endcase // unique case (state_q) + end end // always_comb assign dst_update_req = dst_hold_req | dst_lat_d | dst_lat_q; @@ -243,10 +236,22 @@ module prim_reg_cdc_arb #( assign src_ack_o = src_req & (id_q == SelSwReq); assign src_update_o = src_req & (id_q == SelHwReq); - // once hardware makes an update request, we must eventually see an update pulse + // Once hardware makes an update request, we must eventually see an update pulse + // + // This is fundamentally a liveness property and only really useful in a formal setting (since a + // simulation can never give a counterexample). Unfortunately, proving liveness properties can + // be intractable for formal tools. This assertion bounds the time, making it a safety property + // that the tool can handle more easily. + // + // The required bound depends on the ratio between the two clocks. If there are N edges of + // clk_dst_i for each edge of clk_src_i, we can expect a bound of 2*N to suffice (this is + // waiting for u_dst_update_sync to synchronise dst_update_req to src_req). + // + // The possible clock ratios rely on tool configuration, but we set N=10 (which matches the + // configuration for the main clock and the slow aon clock in our FPV tool setup). `ifdef FPV_ON - `ASSERT(ReqTimeout_A, $rose(id_q == SelHwReq) |-> s_eventually(src_update_o), - clk_src_i, !rst_src_ni) + `ASSERT(ReqTimeout_A, $rose(id_q == SelHwReq) |-> ##[0:20] src_update_o, + clk_src_i, !rst_src_ni) // TODO: #14913 check if we can add additional sim assertions. `endif @@ -260,7 +265,7 @@ module prim_reg_cdc_arb #( async_flag <= '0; end else if (src_update_o) begin async_flag <= '0; - end else if (dst_update && !dst_req_o && !busy) begin + end else if (dst_update && !dst_req_o && idle_q) begin async_flag <= 1'b1; end end diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_rom_adv.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_rom_adv.sv index bfa0c5b3cb..326b21ee3d 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_rom_adv.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_rom_adv.sv @@ -30,20 +30,14 @@ module prim_rom_adv import prim_rom_pkg::*; #( .MemInitFile(MemInitFile) ) u_prim_rom ( .clk_i, + .rst_ni, .req_i, .addr_i, + .rvalid_o, .rdata_o, .cfg_i ); - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - rvalid_o <= 1'b0; - end else begin - rvalid_o <= req_i; - end - end - //////////////// // ASSERTIONS // //////////////// diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_sdc_example.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_sdc_example.sv new file mode 100644 index 0000000000..5d64d0da25 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_sdc_example.sv @@ -0,0 +1,694 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// The purpose of this module is to have a small and simple module that can be synthesized (and its +// netlist can be inspected) for easy constraint checking. +// The synthesis tool is not allowed to perform constant propagation, merging of redundant signals, +// and performing logic optimization accross preserved cells. +// +// 1. In the synthesized netlist, the following number of size_only instances must be present: +// e.g. grep -c -R u_size_only_x netlist.v (make sure the design is uniquified) +// |-------------------------------------------------------------------| +// | Test | buf | and2 | xor | xnor | flop | clock_mux2 | clock_gating | +// | -----| ----|------|-----|------|------|------------|--------------| +// | 1 | 192 | - | - | - | - | - | - | +// | 2 | - | - | 64 | - | - | - | - | +// | 3 | 48 | 48 | 48 | 48 | 144 | - | - | +// | 4 | 8 | 8 | 8 | 8 | 24 | - | - | +// | 5 | 36 | - | - | - | 24 | - | - | +// | 6 | 16 | - | - | - | 8 | - | - | +// | 7 | - | - | - | - | 32 | 2 | 2 | +// | 8 | 16 | - | - | - | 8 | - | - | +// | 9 | 12 | - | - | - | 12 | - | - | +// | -----| ----|------|-----|------|------|------------|--------------| +// |total | 328 | 56 | 120 | 56 | 252 | 2 | 2 | +// |-------------------------------------------------------------------| +// +// 2. None of the test_*_o signals can be driven by a constant 0 or 1. +// The instantiated size_only instances must prevent logic optimizations and keep +// the output comparators +// e.g. check_design -constant +// +// 3. None of the buffers or flip flops can be unloaded: +// e.g. check_design -unloaded_comb -unloaded +// +// 4. lc_en_o, mubi_o signals cannot be driven to a constant value +// (optimization accross preserevd instances cannot happen) +// +// 5. lc_en_i, mubi_i signals can only be connected to variables, or legal mubi/lc values +// e.g. grep -oE '(\.lc_en_i|\.mubi_i) \([^)]+' netlist.v + +`include "prim_assert.sv" + +module prim_sdc_example #( + localparam int unsigned Width = 8, // these localparams are constant, don't override + localparam int unsigned NumSender = 4, + localparam int unsigned NumTests = 12, + localparam int unsigned NumSenderLc = 2, + localparam int unsigned NumTestsLc = 6 +) ( + input logic clk_i, + input logic rst_ni, + + input logic [31:0] data_a_i, + input logic [31:0] data_b_i, + input logic [31:0] data_c_i, + + input logic en_i, + + output logic [31:0] test_res_o, + output logic test_xor_o, + output logic test_const_o, + output logic test_var_o, + output logic [1:0] test_mubi_out_o, + output logic [NumSender-1:0][NumTests-1:0] test_mubi_bool_out_o, + output logic [3:0][Width-1:0] test_clk_gen_o, + output logic [1:0] test_lc_out_o, + output logic [NumSenderLc-1:0][NumTestsLc-1:0] test_lc_bool_out_o +); + + import prim_mubi_pkg::*; + + ////////////////////////////////////////////////////// + // Test 1: basic buffers with arithmetic operations // + ////////////////////////////////////////////////////// + // It is not allowed that arithmetic operations are merged across prim_bufs + // The following size_only cells are expected: + // 6*32 size_only_buf + + localparam int unsigned NumStages = 3; + localparam int unsigned ConstA = 32'h0FF0_ABBA; + + logic [NumStages-1:0][31:0] res, res_buf; + logic [31:0] data_a, data_b, data_c; + + prim_buf #( + .Width(32) + ) u_prim_buf_data_a ( + .in_i (data_a_i), + .out_o(data_a) + ); + + prim_buf #( + .Width(32) + ) u_prim_buf_data_b ( + .in_i (data_b_i), + .out_o(data_b) + ); + + prim_buf #( + .Width(32) + ) u_prim_buf_data_c ( + .in_i (data_c_i), + .out_o(data_c) + ); + + assign res[0] = data_a + data_b; + + prim_buf #( + .Width(32) + ) u_prim_buf_res0 ( + .in_i (res[0]), + .out_o(res_buf[0]) + ); + + assign res[1] = res_buf[0] + ConstA; + + prim_buf #( + .Width(32) + ) u_prim_buf_res1 ( + .in_i (res[1]), + .out_o(res_buf[1]) + ); + + assign res[2] = res_buf[1] * data_c; + + prim_buf #( + .Width(32) + ) u_prim_buf_res2 ( + .in_i (res[2]), + .out_o(res_buf[2]) + ); + + assign test_res_o = res_buf[2]; + + //////////////////////////////////////////////////////////////// + // Test 2: two xor operations in a row result in the identity // + //////////////////////////////////////////////////////////////// + // This optimization is prevented by the preserved instances + // The following size_only cells are expected: + // 2*32 size_only_xor2 + // test_xor_o must be the result of a comparison and not tied to high + + logic [31:0] res_xor2_0, res_xor2_1; + + prim_xor2 #( + .Width(32) + ) u_prim_xor2_0 ( + .in0_i(data_a_i), + .in1_i(data_b_i), + .out_o(res_xor2_0) + ); + + prim_xor2 #( + .Width(32) + ) u_prim_xor2_1 ( + .in0_i(res_xor2_0), + .in1_i(data_b_i), + .out_o(res_xor2_1) + ); + + // The comparison below is always true because + // res_xor2_1 = res_xor2_0 ^ data_b_i = data_a_i ^ data_b_i ^ data_b_i = data_a_i + // But the comparison cannot be optimized because logic propagation is not allowed + // across preserved instances + assign test_xor_o = (res_xor2_1 == data_a_i) ? 1'b1 : 1'b0; + + ////////////////////////////////////////////////////////// + // Test 3: prim basic gates tests with constant inputs: // + ////////////////////////////////////////////////////////// + // These gates cannot be removed + // The following size_only cells are expected: + // 6*8 size_only_buf + // 6*8 size_only_and2 + // 6*8 size_only_xor + // 6*8 size_only_xnor + // 6*8*3 size_only_flop + + localparam int unsigned NumConst = 6; + localparam int unsigned NumGates = 7; + + localparam logic [Width-1:0] ConstIn0 [NumConst] = {8'hAB, + 8'hBA, + 8'h01, + 8'hFE, + 8'hF0, + 8'h0F}; + + localparam logic [Width-1:0] ConstIn1 [NumConst] = {8'h10, + 8'h25, + 8'h39, + 8'hBC, + 8'hD1, + 8'h5F}; + + logic [NumConst-1:0][NumGates-1:0][Width-1:0] const_out_not_removed; + + for (genvar idx = 0; idx < NumConst; idx++) begin : g_num_consts + prim_buf #( + .Width(Width) + ) u_prim_buf ( + .in_i (ConstIn0[idx]), + .out_o(const_out_not_removed[idx][0]) + ); + + prim_and2 #( + .Width(Width) + ) u_prim_and2 ( + .in0_i(ConstIn0[idx]), + .in1_i(ConstIn1[idx]), + .out_o(const_out_not_removed[idx][1]) + ); + + prim_xor2 #( + .Width(Width) + ) u_prim_xor2 ( + .in0_i(ConstIn0[idx]), + .in1_i(ConstIn1[idx]), + .out_o(const_out_not_removed[idx][2]) + ); + + prim_xnor2 #( + .Width(Width) + ) u_prim_xnor2 ( + .in0_i(ConstIn0[idx]), + .in1_i(ConstIn1[idx]), + .out_o(const_out_not_removed[idx][3]) + ); + + prim_flop #( + .Width(Width) + ) u_prim_flop ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .d_i (ConstIn0[idx]), + .q_o (const_out_not_removed[idx][4]) + ); + + prim_flop_en #( + .Width(Width) + ) u_prim_flop_en ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .en_i (en_i), + .d_i (ConstIn0[idx]), + .q_o (const_out_not_removed[idx][5]) + ); + + prim_flop_no_rst #( + .Width(Width) + ) u_prim_flop_no_rst ( + .clk_i(clk_i), + .d_i (ConstIn0[idx]), + .q_o (const_out_not_removed[idx][6]) + ); + end + + assign test_const_o = ^const_out_not_removed; + + /////////////////////////////////////////////////// + // Test 4: prim basic gates with variable inputs // + /////////////////////////////////////////////////// + // The following size_only cells are expected: + // 8 size_only_buf + // 8 size_only_and2 + // 8 size_only_xor + // 8 size_only_xnor + // 8*3 size_only_flop + + logic [NumGates-1:0][Width-1:0] var_out_not_removed; + + prim_buf #( + .Width(Width) + ) u_prim_buf ( + .in_i (data_a[Width-1:0]), + .out_o(var_out_not_removed[0]) + ); + prim_and2 #( + .Width(Width) + ) u_prim_and2 ( + .in0_i(data_a[Width-1:0]), + .in1_i(data_b[Width-1:0]), + .out_o(var_out_not_removed[1]) + ); + prim_xor2 #( + .Width(Width) + ) u_prim_xor2 ( + .in0_i(data_a[Width-1:0]), + .in1_i(data_b[Width-1:0]), + .out_o(var_out_not_removed[2]) + ); + prim_xnor2 #( + .Width(Width) + ) u_prim_xnor2 ( + .in0_i(data_a[Width-1:0]), + .in1_i(data_b[Width-1:0]), + .out_o(var_out_not_removed[3]) + ); + prim_flop #( + .Width(Width) + ) u_prim_flop ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .d_i (data_a[Width-1:0]), + .q_o (var_out_not_removed[4]) + ); + prim_flop_en #( + .Width(Width) + ) u_prim_flop_en ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .en_i (en_i), + .d_i (data_a[Width-1:0]), + .q_o (var_out_not_removed[5]) + ); + prim_flop_no_rst #( + .Width(Width) + ) u_prim_flop_no_rst ( + .clk_i(clk_i), + .d_i (data_a[Width-1:0]), + .q_o (var_out_not_removed[6]) + ); + + assign test_var_o = ^var_out_not_removed; + + /////////////////////////////////////////////// + // Test 5: mubi4_sender with constant inputs // + /////////////////////////////////////////////// + // Constant mubi signals cannot be used to perform optimizations at the output + // The following size_only cells are expected: + // 9*4 size_only_buf + // 4*6 size_only_flop + + mubi4_t [NumSender-1:0] mubi4_true_out; + mubi4_t [NumSender-1:0] mubi4_false_out; + mubi4_t [NumSender-1:0] mubi4_var_out; + + prim_mubi4_sender #( + .AsyncOn(0), + .EnSecBuf(0) + ) u_mubi4_sender_true0 ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .mubi_i(MuBi4True), + .mubi_o(mubi4_true_out[0]) + ); + + prim_mubi4_sender #( + .AsyncOn(0), + .EnSecBuf(0) + ) u_mubi4_sender_false0 ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .mubi_i(MuBi4False), + .mubi_o(mubi4_false_out[0]) + ); + + prim_mubi4_sender #( + .AsyncOn(0), + .EnSecBuf(0) + ) u_mubi4_sender_var0 ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .mubi_i(mubi4_bool_to_mubi(data_a_i[0])), + .mubi_o(mubi4_var_out[0]) + ); + + prim_mubi4_sender #( + .AsyncOn(1), + .EnSecBuf(0) + ) u_mubi4_sender_true1 ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .mubi_i(MuBi4True), + .mubi_o(mubi4_true_out[1]) + ); + + prim_mubi4_sender #( + .AsyncOn(1), + .EnSecBuf(0) + ) u_mubi4_sender_false1 ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .mubi_i(MuBi4False), + .mubi_o(mubi4_false_out[1]) + ); + + prim_mubi4_sender #( + .AsyncOn(1), + .EnSecBuf(0) + ) u_mubi4_sender_var1 ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .mubi_i(mubi4_bool_to_mubi(data_a_i[1])), + .mubi_o(mubi4_var_out[1]) + ); + + prim_mubi4_sender #( + .AsyncOn(0), + .EnSecBuf(1) + ) u_mubi4_sender_true2 ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .mubi_i(MuBi4False), + .mubi_o(mubi4_true_out[2]) + ); + + prim_mubi4_sender #( + .AsyncOn(0), + .EnSecBuf(1) + ) u_mubi4_sender_false2 ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .mubi_i(MuBi4False), + .mubi_o(mubi4_false_out[2]) + ); + + prim_mubi4_sender #( + .AsyncOn(0), + .EnSecBuf(1) + ) u_mubi4_sender_var2 ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .mubi_i(mubi4_bool_to_mubi(data_a_i[2])), + .mubi_o(mubi4_var_out[2]) + ); + + prim_mubi4_sender #( + .AsyncOn(1), + .EnSecBuf(1) + ) u_mubi4_sender_true3 ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .mubi_i(MuBi4False), + .mubi_o(mubi4_true_out[3]) + ); + + prim_mubi4_sender #( + .AsyncOn(1), + .EnSecBuf(1) + ) u_mubi4_sender_false3 ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .mubi_i(MuBi4False), + .mubi_o(mubi4_false_out[3]) + ); + + prim_mubi4_sender #( + .AsyncOn(1), + .EnSecBuf(1) + ) u_mubi4_sender_var3 ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .mubi_i(mubi4_bool_to_mubi(data_a_i[3])), + .mubi_o(mubi4_var_out[3]) + ); + + // none of these bool_out can be tied directly to low/high + for (genvar idx = 0; idx < NumSender; idx++) begin : g_out + assign test_mubi_bool_out_o[idx][0] = mubi4_test_true_strict(mubi4_true_out[idx]); + assign test_mubi_bool_out_o[idx][1] = mubi4_test_true_loose(mubi4_true_out[idx]); + assign test_mubi_bool_out_o[idx][2] = mubi4_test_false_strict(mubi4_true_out[idx]); + assign test_mubi_bool_out_o[idx][3] = mubi4_test_false_loose(mubi4_true_out[idx]); + assign test_mubi_bool_out_o[idx][4] = mubi4_test_true_strict(mubi4_false_out[idx]); + assign test_mubi_bool_out_o[idx][5] = mubi4_test_true_loose(mubi4_false_out[idx]); + assign test_mubi_bool_out_o[idx][6] = mubi4_test_false_strict(mubi4_false_out[idx]); + assign test_mubi_bool_out_o[idx][7] = mubi4_test_false_loose(mubi4_false_out[idx]); + assign test_mubi_bool_out_o[idx][8] = mubi4_test_true_strict(mubi4_var_out[idx]); + assign test_mubi_bool_out_o[idx][9] = mubi4_test_true_loose(mubi4_var_out[idx]); + assign test_mubi_bool_out_o[idx][10] = mubi4_test_false_strict(mubi4_var_out[idx]); + assign test_mubi_bool_out_o[idx][11] = mubi4_test_false_loose(mubi4_var_out[idx]); + end + + ////////////////////////////// + // Test 6: mubi_sync_copies // + ////////////////////////////// + // These gates cannot be removed + // The following size_only cells are expected: + // 2*2*4 size_only_buf + // 4*2 size_only_flop + + localparam int unsigned NumCopies = 2; + + mubi4_t [NumCopies-1:0] mubi_var0, mubi_var1; + mubi4_t [1:0] mubi_var_comp; + + prim_mubi4_sync #( + .NumCopies(NumCopies), + .AsyncOn(0) + ) u_prim_mubi4_sync0 ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .mubi_i(mubi4_bool_to_mubi(data_a_i[0])), + .mubi_o(mubi_var0) + ); + + prim_mubi4_sync #( + .NumCopies(NumCopies), + .AsyncOn(1) + ) u_prim_mubi4_sync1 ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .mubi_i(mubi4_bool_to_mubi(data_b_i[0])), + .mubi_o(mubi_var1) + ); + + // These comparisons can be simplified to just mubi_var0/1 but the sythesizer is not allowed to + // perform the optimizations + assign mubi_var_comp[0] = mubi4_or_hi (mubi_var0[0], mubi_var0[1]); + assign mubi_var_comp[1] = mubi4_and_hi(mubi_var1[0], mubi_var1[1]); + + assign test_mubi_out_o[0] = mubi4_test_false_loose(mubi_var_comp[0]); + assign test_mubi_out_o[1] = mubi4_test_true_loose(mubi_var_comp[1]); + + /////////////////////////////// + // Test 7: test_clock_gating // + /////////////////////////////// + // clock gate cannot be removed + // The following size_only cells are expected: + // 2 size_only_clock_gating + // 2 size_only_clock_mux2 + // 2*2*8 size_only_flop + + logic [1:0] clk, clk_muxed; + + // cannot be removed even though clock is always on/off + prim_clock_gating u_prim_clk_gate_const0 ( + .clk_i (clk_i), + .en_i (1'b0), + .test_en_i(1'b0), + .clk_o (clk[0]) + ); + prim_clock_gating u_prim_clk_gate_const1 ( + .clk_i (clk_i), + .en_i (1'b1), + .test_en_i(1'b0), + .clk_o (clk[1]) + ); + + // mux cannot be removed even though select is constant + prim_clock_mux2 u_prim_clock_mux_const0 ( + .clk0_i(clk_i), + .clk1_i(1'b0), + .sel_i (1'b0), + .clk_o (clk_muxed[0]) + ); + + // mux cannot be removed even though select and clkinput is constant + prim_clock_mux2 u_prim_clock_mux_const1 ( + .clk0_i(clk_i), + .clk1_i(1'b0), + .sel_i (1'b1), + .clk_o (clk_muxed[1]) + ); + + for (genvar idx = 0; idx < 2; idx++) begin : g_flops + prim_flop #( + .Width(Width) + ) u_prim_flop_clk_const ( + .clk_i (clk[idx]), + .rst_ni(rst_ni), + .d_i (data_a[Width-1:0]), + .q_o (test_clk_gen_o[0+2*idx]) + ); + prim_flop #( + .Width(Width) + ) u_prim_flop_clk_muxed ( + .clk_i (clk_muxed[idx]), + .rst_ni(rst_ni), + .d_i (data_b[Width-1:0]), + .q_o (test_clk_gen_o[1+2*idx]) + ); + end + + ////////////////////////// + // Test 8: lc_sync test // + ////////////////////////// + // All copies must be present and output logic cannot be optimized + // The following size_only cells are expected: + // 2*2*4 size_only_buf + // 4*2 size_only_flop + + localparam int unsigned NumCopiesLc = 2; + import lc_ctrl_pkg::*; + + lc_tx_t [NumCopiesLc-1:0] lc_var0, lc_var1; + lc_tx_t [1:0] lc_var_comp; + + prim_lc_sync #( + .NumCopies(NumCopiesLc), + .AsyncOn(0) + ) u_prim_lc_sync0 ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .lc_en_i(lc_tx_bool_to_lc_tx(data_a_i[0])), + .lc_en_o(lc_var0) + ); + + prim_lc_sync #( + .NumCopies(NumCopiesLc), + .AsyncOn(1) + ) u_prim_lc_sync1 ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .lc_en_i(lc_tx_bool_to_lc_tx(data_b_i[0])), + .lc_en_o(lc_var1) + ); + + // These comparisons can be simplified to just lc_var0/1 but the sythesizer is not allowed to + // perform the optimizations + assign lc_var_comp[0] = lc_tx_or_hi (lc_var0[0], lc_var0[1]); + assign lc_var_comp[1] = lc_tx_and_hi(lc_var1[0], lc_var1[1]); + + assign test_lc_out_o[0] = lc_tx_test_false_loose(lc_var_comp[0]); + assign test_lc_out_o[1] = lc_tx_test_true_loose(lc_var_comp[1]); + + //////////////////////////// + // Test 9: lc_sender test // + //////////////////////////// + // Send different lc_en signals through prim_sender and perform constant comparisons + // Output comparisons cannot be removed and output xor tree must remain + // The following size_only cells are expected: + // 3*4 size_only_buf + // 3*4 size_only_flop + + lc_tx_t [NumSenderLc-1:0] lc_on_out; + lc_tx_t [NumSenderLc-1:0] lc_off_out; + lc_tx_t [NumSenderLc-1:0] lc_var_out; + + prim_lc_sender #( + .AsyncOn(0) + ) u_lc_sender_on0 ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .lc_en_i(On), + .lc_en_o(lc_on_out[0]) + ); + + prim_lc_sender #( + .AsyncOn(0) + ) u_lc_sender_off0 ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .lc_en_i(Off), + .lc_en_o(lc_off_out[0]) + ); + + prim_lc_sender #( + .AsyncOn(0) + ) u_lc_sender_var0 ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .lc_en_i(lc_tx_bool_to_lc_tx(data_a_i[0])), + .lc_en_o(lc_var_out[0]) + ); + + prim_lc_sender #( + .AsyncOn(1) + ) u_lc_sender_on1 ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .lc_en_i(On), + .lc_en_o(lc_on_out[1]) + ); + + prim_lc_sender #( + .AsyncOn(1) + ) u_lc_sender_off1 ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .lc_en_i(Off), + .lc_en_o(lc_off_out[1]) + ); + + prim_lc_sender #( + .AsyncOn(1) + ) u_lc_sender_var1 ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .lc_en_i(lc_tx_bool_to_lc_tx(data_a_i[1])), + .lc_en_o(lc_var_out[1]) + ); + + // none of these lc_bool_out can be tied directly to low/high + for (genvar idx = 0; idx < NumSenderLc; idx++) begin : g_lc_bool_out + assign test_lc_bool_out_o[idx][0] = lc_tx_test_true_strict(lc_on_out[idx]); + assign test_lc_bool_out_o[idx][1] = lc_tx_test_false_strict(lc_on_out[idx]); + assign test_lc_bool_out_o[idx][2] = lc_tx_test_true_loose(lc_off_out[idx]); + assign test_lc_bool_out_o[idx][3] = lc_tx_test_false_loose(lc_off_out[idx]); + assign test_lc_bool_out_o[idx][4] = lc_tx_test_invalid(lc_var_out[idx]); + assign test_lc_bool_out_o[idx][5] = lc_tx_test_true_strict(lc_var_out[idx]); + end + +endmodule : prim_sdc_example diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_inc.svh b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_inc.svh new file mode 100644 index 0000000000..ee03dd1b1a --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_inc.svh @@ -0,0 +1,285 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED macros generated by +// util/design/secded_gen.py from util/design/data/secded_cfg.hjson + +// This macro instantiates a secded decoder for the given _TYPE and _WIDTH. +// The instance will be named _INST, the data input connected to _ENC_DATA, +// and the data output, syndrome, and error connected to _DATA, _SYND, and +// _ERR respectively. +`define SECDED_INST_DEC(_TYPE, _WIDTH, _INST, _ENC_DATA, _DATA, _SYND, _ERR) \ + case (_TYPE) \ + prim_secded_pkg::SecdedHsiao: begin : gen_dec_hsiao \ + case (_WIDTH) \ + 16: begin : gen_dec_hsiao_16 \ + prim_secded_22_16_dec _INST( \ + .data_i(_ENC_DATA), \ + .data_o(_DATA), \ + .syndrome_o(_SYND), \ + .err_o(_ERR)); \ + end \ + 22: begin : gen_dec_hsiao_22 \ + prim_secded_28_22_dec _INST( \ + .data_i(_ENC_DATA), \ + .data_o(_DATA), \ + .syndrome_o(_SYND), \ + .err_o(_ERR)); \ + end \ + 32: begin : gen_dec_hsiao_32 \ + prim_secded_39_32_dec _INST( \ + .data_i(_ENC_DATA), \ + .data_o(_DATA), \ + .syndrome_o(_SYND), \ + .err_o(_ERR)); \ + end \ + 57: begin : gen_dec_hsiao_57 \ + prim_secded_64_57_dec _INST( \ + .data_i(_ENC_DATA), \ + .data_o(_DATA), \ + .syndrome_o(_SYND), \ + .err_o(_ERR)); \ + end \ + 64: begin : gen_dec_hsiao_64 \ + prim_secded_72_64_dec _INST( \ + .data_i(_ENC_DATA), \ + .data_o(_DATA), \ + .syndrome_o(_SYND), \ + .err_o(_ERR)); \ + end \ + default: begin : gen_dec_hsiao_default \ + end \ + endcase \ + end \ + prim_secded_pkg::SecdedHamming: begin : gen_dec_hamming \ + case (_WIDTH) \ + 16: begin : gen_dec_hamming_16 \ + prim_secded_hamming_22_16_dec _INST( \ + .data_i(_ENC_DATA), \ + .data_o(_DATA), \ + .syndrome_o(_SYND), \ + .err_o(_ERR)); \ + end \ + 32: begin : gen_dec_hamming_32 \ + prim_secded_hamming_39_32_dec _INST( \ + .data_i(_ENC_DATA), \ + .data_o(_DATA), \ + .syndrome_o(_SYND), \ + .err_o(_ERR)); \ + end \ + 64: begin : gen_dec_hamming_64 \ + prim_secded_hamming_72_64_dec _INST( \ + .data_i(_ENC_DATA), \ + .data_o(_DATA), \ + .syndrome_o(_SYND), \ + .err_o(_ERR)); \ + end \ + 68: begin : gen_dec_hamming_68 \ + prim_secded_hamming_76_68_dec _INST( \ + .data_i(_ENC_DATA), \ + .data_o(_DATA), \ + .syndrome_o(_SYND), \ + .err_o(_ERR)); \ + end \ + default: begin : gen_dec_hamming_default \ + end \ + endcase \ + end \ + prim_secded_pkg::SecdedInvHsiao: begin : gen_dec_inv_hsiao \ + case (_WIDTH) \ + 16: begin : gen_dec_inv_hsiao_16 \ + prim_secded_inv_22_16_dec _INST( \ + .data_i(_ENC_DATA), \ + .data_o(_DATA), \ + .syndrome_o(_SYND), \ + .err_o(_ERR)); \ + end \ + 22: begin : gen_dec_inv_hsiao_22 \ + prim_secded_inv_28_22_dec _INST( \ + .data_i(_ENC_DATA), \ + .data_o(_DATA), \ + .syndrome_o(_SYND), \ + .err_o(_ERR)); \ + end \ + 32: begin : gen_dec_inv_hsiao_32 \ + prim_secded_inv_39_32_dec _INST( \ + .data_i(_ENC_DATA), \ + .data_o(_DATA), \ + .syndrome_o(_SYND), \ + .err_o(_ERR)); \ + end \ + 57: begin : gen_dec_inv_hsiao_57 \ + prim_secded_inv_64_57_dec _INST( \ + .data_i(_ENC_DATA), \ + .data_o(_DATA), \ + .syndrome_o(_SYND), \ + .err_o(_ERR)); \ + end \ + 64: begin : gen_dec_inv_hsiao_64 \ + prim_secded_inv_72_64_dec _INST( \ + .data_i(_ENC_DATA), \ + .data_o(_DATA), \ + .syndrome_o(_SYND), \ + .err_o(_ERR)); \ + end \ + default: begin : gen_dec_inv_hsiao_default \ + end \ + endcase \ + end \ + prim_secded_pkg::SecdedInvHamming: begin : gen_dec_inv_hamming \ + case (_WIDTH) \ + 16: begin : gen_dec_inv_hamming_16 \ + prim_secded_inv_hamming_22_16_dec _INST( \ + .data_i(_ENC_DATA), \ + .data_o(_DATA), \ + .syndrome_o(_SYND), \ + .err_o(_ERR)); \ + end \ + 32: begin : gen_dec_inv_hamming_32 \ + prim_secded_inv_hamming_39_32_dec _INST( \ + .data_i(_ENC_DATA), \ + .data_o(_DATA), \ + .syndrome_o(_SYND), \ + .err_o(_ERR)); \ + end \ + 64: begin : gen_dec_inv_hamming_64 \ + prim_secded_inv_hamming_72_64_dec _INST( \ + .data_i(_ENC_DATA), \ + .data_o(_DATA), \ + .syndrome_o(_SYND), \ + .err_o(_ERR)); \ + end \ + 68: begin : gen_dec_inv_hamming_68 \ + prim_secded_inv_hamming_76_68_dec _INST( \ + .data_i(_ENC_DATA), \ + .data_o(_DATA), \ + .syndrome_o(_SYND), \ + .err_o(_ERR)); \ + end \ + default: begin : gen_dec_inv_hamming_default \ + end \ + endcase \ + end \ + endcase + +// This macro instantiates a secded encoder for the given _TYPE and _WIDTH. +// The instance is named _INST, the data input connects to _DATA, and the +// data output connects to _ENC_DATA. +`define SECDED_INST_ENC(_TYPE, _WIDTH, _INST, _DATA, _ENC_DATA) \ + case (_TYPE) \ + prim_secded_pkg::SecdedHsiao: begin : gen_enc_hsiao \ + case (_WIDTH) \ + 16: begin : gen_enc_hsiao_16 \ + prim_secded_22_16_enc _INST( \ + .data_i(_DATA), \ + .data_o(_ENC_DATA)); \ + end \ + 22: begin : gen_enc_hsiao_22 \ + prim_secded_28_22_enc _INST( \ + .data_i(_DATA), \ + .data_o(_ENC_DATA)); \ + end \ + 32: begin : gen_enc_hsiao_32 \ + prim_secded_39_32_enc _INST( \ + .data_i(_DATA), \ + .data_o(_ENC_DATA)); \ + end \ + 57: begin : gen_enc_hsiao_57 \ + prim_secded_64_57_enc _INST( \ + .data_i(_DATA), \ + .data_o(_ENC_DATA)); \ + end \ + 64: begin : gen_enc_hsiao_64 \ + prim_secded_72_64_enc _INST( \ + .data_i(_DATA), \ + .data_o(_ENC_DATA)); \ + end \ + default: begin : gen_enc_hsiao_default \ + end \ + endcase \ + end \ + prim_secded_pkg::SecdedHamming: begin : gen_enc_hamming \ + case (_WIDTH) \ + 16: begin : gen_enc_hamming_16 \ + prim_secded_hamming_22_16_enc _INST( \ + .data_i(_DATA), \ + .data_o(_ENC_DATA)); \ + end \ + 32: begin : gen_enc_hamming_32 \ + prim_secded_hamming_39_32_enc _INST( \ + .data_i(_DATA), \ + .data_o(_ENC_DATA)); \ + end \ + 64: begin : gen_enc_hamming_64 \ + prim_secded_hamming_72_64_enc _INST( \ + .data_i(_DATA), \ + .data_o(_ENC_DATA)); \ + end \ + 68: begin : gen_enc_hamming_68 \ + prim_secded_hamming_76_68_enc _INST( \ + .data_i(_DATA), \ + .data_o(_ENC_DATA)); \ + end \ + default: begin : gen_enc_hamming_default \ + end \ + endcase \ + end \ + prim_secded_pkg::SecdedInvHsiao: begin : gen_enc_inv_hsiao \ + case (_WIDTH) \ + 16: begin : gen_enc_inv_hsiao_16 \ + prim_secded_inv_22_16_enc _INST( \ + .data_i(_DATA), \ + .data_o(_ENC_DATA)); \ + end \ + 22: begin : gen_enc_inv_hsiao_22 \ + prim_secded_inv_28_22_enc _INST( \ + .data_i(_DATA), \ + .data_o(_ENC_DATA)); \ + end \ + 32: begin : gen_enc_inv_hsiao_32 \ + prim_secded_inv_39_32_enc _INST( \ + .data_i(_DATA), \ + .data_o(_ENC_DATA)); \ + end \ + 57: begin : gen_enc_inv_hsiao_57 \ + prim_secded_inv_64_57_enc _INST( \ + .data_i(_DATA), \ + .data_o(_ENC_DATA)); \ + end \ + 64: begin : gen_enc_inv_hsiao_64 \ + prim_secded_inv_72_64_enc _INST( \ + .data_i(_DATA), \ + .data_o(_ENC_DATA)); \ + end \ + default: begin : gen_enc_inv_hsiao_default \ + end \ + endcase \ + end \ + prim_secded_pkg::SecdedInvHamming: begin : gen_enc_inv_hamming \ + case (_WIDTH) \ + 16: begin : gen_enc_inv_hamming_16 \ + prim_secded_inv_hamming_22_16_enc _INST( \ + .data_i(_DATA), \ + .data_o(_ENC_DATA)); \ + end \ + 32: begin : gen_enc_inv_hamming_32 \ + prim_secded_inv_hamming_39_32_enc _INST( \ + .data_i(_DATA), \ + .data_o(_ENC_DATA)); \ + end \ + 64: begin : gen_enc_inv_hamming_64 \ + prim_secded_inv_hamming_72_64_enc _INST( \ + .data_i(_DATA), \ + .data_o(_ENC_DATA)); \ + end \ + 68: begin : gen_enc_inv_hamming_68 \ + prim_secded_inv_hamming_76_68_enc _INST( \ + .data_i(_DATA), \ + .data_o(_ENC_DATA)); \ + end \ + default: begin : gen_enc_inv_hamming_default \ + end \ + endcase \ + end \ + endcase diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_pkg.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_pkg.sv index b5782845a5..4cd5fb718f 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_pkg.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_pkg.sv @@ -7,6 +7,13 @@ package prim_secded_pkg; + typedef enum int { + SecdedHsiao, + SecdedHamming, + SecdedInvHsiao, + SecdedInvHamming + } prim_secded_type_e; + typedef enum int { SecdedNone, Secded_22_16, @@ -29,6 +36,93 @@ package prim_secded_pkg; SecdedInvHamming_76_68 } prim_secded_e; + // This returns 1 iff the width is supported for the given secded type. + function automatic bit is_width_valid(prim_secded_type_e sd_type, int width); + unique case (sd_type) + SecdedHsiao: + unique case (width) + 16: return 1'b1; + 22: return 1'b1; + 32: return 1'b1; + 57: return 1'b1; + 64: return 1'b1; + default: return 1'b0; + endcase + SecdedHamming: + unique case (width) + 16: return 1'b1; + 32: return 1'b1; + 64: return 1'b1; + 68: return 1'b1; + default: return 1'b0; + endcase + SecdedInvHsiao: + unique case (width) + 16: return 1'b1; + 22: return 1'b1; + 32: return 1'b1; + 57: return 1'b1; + 64: return 1'b1; + default: return 1'b0; + endcase + SecdedInvHamming: + unique case (width) + 16: return 1'b1; + 32: return 1'b1; + 64: return 1'b1; + 68: return 1'b1; + default: return 1'b0; + endcase + default: return 1'b0; + endcase + endfunction : is_width_valid + + // This returns the syndrome width for the given width and secded type. + // Return 0 if the width is not supported. + function automatic int get_synd_width(prim_secded_type_e sd_type, int width); + unique case (sd_type) + SecdedHsiao: + unique case (width) + 16: return 6; + 22: return 6; + 32: return 7; + 57: return 7; + 64: return 8; + default: return 0; + endcase + SecdedHamming: + unique case (width) + 16: return 6; + 32: return 7; + 64: return 8; + 68: return 8; + default: return 0; + endcase + SecdedInvHsiao: + unique case (width) + 16: return 6; + 22: return 6; + 32: return 7; + 57: return 7; + 64: return 8; + default: return 0; + endcase + SecdedInvHamming: + unique case (width) + 16: return 6; + 32: return 7; + 64: return 8; + 68: return 8; + default: return 0; + endcase + default: return 0; + endcase + endfunction : get_synd_width + + function automatic int get_full_width(prim_secded_type_e sd_type, int width); + return width + get_synd_width(sd_type, width); + endfunction : get_full_width + function automatic int get_ecc_data_width(prim_secded_e ecc_type); case (ecc_type) Secded_22_16: return 16; diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_sha2.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_sha2.sv index e2a571cd39..9324a2e6da 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_sha2.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_sha2.sv @@ -4,6 +4,8 @@ // // SHA-256/384/512 configurable mode engine (64-bit word datapath) +`include "prim_assert.sv" + module prim_sha2 import prim_sha2_pkg::*; #( parameter bit MultimodeEn = 0, // assert to enable multi-mode digest feature @@ -40,6 +42,7 @@ module prim_sha2 import prim_sha2_pkg::*; input logic [7:0] digest_we_i, output sha_word64_t [7:0] digest_o, // tie off unused port slice when MultimodeEn = 0 output logic digest_on_blk_o, // digest being computed for a complete block + output fifoctl_state_e fifo_st_o, output logic hash_running_o, // `1` iff hash computation is active (as opposed to `idle_o`, which // is also `0` and thus 'busy' when waiting for a FIFO input) output logic idle_o @@ -128,7 +131,7 @@ module prim_sha2 import prim_sha2_pkg::*; if (digest_mode_flag_q == SHA2_256) begin hash_d = compress_multi_256(w_q[0][31:0], CubicRootPrime256[round_q[RndWidth256-1:0]], hash_q); - end else if ((digest_mode_flag_q == SHA2_512) || (digest_mode_flag_q == SHA2_384)) begin + end else begin // SHA384 || SHA512 hash_d = compress_512(w_q[0], CubicRootPrime512[round_q], hash_q); end end @@ -177,6 +180,14 @@ module prim_sha2 import prim_sha2_pkg::*; // assign digest to output assign digest_o = digest_q; + // When wipe_secret is high, sensitive internal variables are cleared by extending the wipe + // value specified in the register + `ASSERT(WipeHashAssert, + wipe_secret_i |=> (hash_q == {($bits(hash_q)/$bits(wipe_v_i)){$past(wipe_v_i)}})) + `ASSERT(WipeMsgSchArrAssert, + wipe_secret_i |=> (w_q == {($bits(w_q)/$bits(wipe_v_i)){$past(wipe_v_i)}})) + `ASSERT(WipeDigestAssert, + wipe_secret_i |=> (digest_q == {($bits(digest_q)/$bits(wipe_v_i)){$past(wipe_v_i)}})) end else begin : gen_256 // MultimodeEn = 0 // datapath signal definitions for SHA-2 256 only sha_word32_t shaf_rdata256; @@ -263,6 +274,15 @@ module prim_sha2 import prim_sha2_pkg::*; assign digest_o[i][31:0] = digest256_q[i]; assign digest_o[i][63:32] = 32'b0; end + + // When wipe_secret is high, sensitive internal variables are cleared by extending the wipe + // value specifed in the register + `ASSERT(WipeHashAssert, + wipe_secret_i |=> (hash256_q == {($bits(hash256_q)/$bits(wipe_v_i)){$past(wipe_v_i)}})) + `ASSERT(WipeMsgSchArrAssert, + wipe_secret_i |=> (w256_q == {($bits(w256_q)/$bits(wipe_v_i)){$past(wipe_v_i)}})) + `ASSERT(WipeDigestAssert, + wipe_secret_i |=> (digest256_q == {($bits(digest256_q)/$bits(wipe_v_i)){$past(wipe_v_i)}})) end // compute round counter (shared) @@ -306,21 +326,17 @@ module prim_sha2 import prim_sha2_pkg::*; else hash_done_o <= hash_done_next; end - typedef enum logic [1:0] { - FifoIdle, - FifoLoadFromFifo, - FifoWait - } fifoctl_state_e; - fifoctl_state_e fifo_st_q, fifo_st_d; + assign fifo_st_o = fifo_st_q; + always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) fifo_st_q <= FifoIdle; else fifo_st_q <= fifo_st_d; end always_comb begin - fifo_st_d = FifoIdle; + fifo_st_d = fifo_st_q; update_w_from_fifo = 1'b0; hash_done_next = 1'b0; @@ -335,6 +351,10 @@ module prim_sha2 import prim_sha2_pkg::*; // Wait until it is filled fifo_st_d = FifoLoadFromFifo; update_w_from_fifo = 1'b0; + if (msg_feed_complete) begin + fifo_st_d = FifoIdle; + hash_done_next = 1'b1; + end end else if (w_index_q == 4'd 15) begin fifo_st_d = FifoWait; // To increment w_index and it rolls over to 0 @@ -446,13 +466,26 @@ module prim_sha2 import prim_sha2_pkg::*; if (!sha_en_i || hash_go) sha_st_d = ShaIdle; end + logic update_digest_q, update_digest_d; + // Determine whether a digest is being computed for a complete block: when `update_digest` is set, // this module is not waiting for more data from the FIFO, and `message_length_i` is zero modulo a // complete block (512 bit for SHA2_256 and 1024 bit for SHA2_384 and SHA2_512). - assign digest_on_blk_o = update_digest && (fifo_st_q == FifoIdle) && ( + assign digest_on_blk_o = (update_digest || update_digest_q) && (fifo_st_q == FifoIdle) && ( (digest_mode_flag_q == SHA2_256 && message_length_i[8:0] == '0) || (digest_mode_flag_q inside {SHA2_384, SHA2_512} && message_length_i[9:0] == '0)); + assign update_digest_d = digest_on_blk_o ? 1'b0 : + update_digest ? 1'b1 : update_digest_q; + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + update_digest_q <= 1'b0; + end else begin + update_digest_q <= update_digest_d; + end + end + assign one_chunk_done = ((digest_mode_flag_q == SHA2_256 || ~MultimodeEn) && (round_q == 7'd63)) ? 1'b1 : (((digest_mode_flag_q == SHA2_384) || (digest_mode_flag_q == SHA2_512)) @@ -484,4 +517,12 @@ module prim_sha2 import prim_sha2_pkg::*; // Idle assign idle_o = (fifo_st_q == FifoIdle) && (sha_st_q == ShaIdle) && !hash_go; + + //////////////// + // Assertions // + //////////////// + + `ASSERT(ValidDigestModeFlag_A, run_hash |-> + digest_mode_flag_q inside {SHA2_256, SHA2_384, SHA2_512}) + endmodule : prim_sha2 diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_sha2_32.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_sha2_32.sv index adac15b607..9658b08c3c 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_sha2_32.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_sha2_32.sv @@ -43,6 +43,8 @@ module prim_sha2_32 import prim_sha2_pkg::*; // to hash. assign hash_go = hash_start_i | hash_continue_i; + fifoctl_state_e fifo_st; + // tie off unused ports/port slices if (!MultimodeEn) begin : gen_tie_unused logic unused_signals; @@ -78,8 +80,13 @@ module prim_sha2_32 import prim_sha2_pkg::*; // accumulate most significant 32 bits of word and mask bits word_buffer_d.data[63:32] = fifo_rdata_i.data; word_buffer_d.mask[7:4] = fifo_rdata_i.mask; - word_part_inc = 1'b1; - fifo_rready_o = 1'b1; + if (fifo_st == FifoLoadFromFifo) begin + fifo_rready_o = 1'b1; // load word from FIFO + word_part_inc = 1'b1; + end else begin + fifo_rready_o = 1'b0; // do not load from FIFO + word_part_inc = 1'b0; + end end else begin // SHA2_256 so pad and push out the word word_valid = 1'b1; // store the word with most significant padding @@ -98,8 +105,8 @@ module prim_sha2_32 import prim_sha2_pkg::*; fifo_rready_o = 1'b0; end end + end else if (word_part_count_q == 2'b01) begin - fifo_rready_o = 1'b1; // buffer still has room for another word // accumulate least significant 32 bits and mask word_buffer_d.data [31:0] = fifo_rdata_i.data; word_buffer_d.mask [3:0] = fifo_rdata_i.mask; @@ -116,12 +123,12 @@ module prim_sha2_32 import prim_sha2_pkg::*; end if (sha_ready == 1'b1) begin // word has been consumed - fifo_rready_o = 1'b1; // word pushed out to SHA engine so word buffer ready + fifo_rready_o = 1'b1; // word pushed out to SHA engine so word buffer ready word_part_reset = 1'b1; word_part_inc = 1'b0; end else begin - fifo_rready_o = 1'b1; - word_part_inc = 1'b1; + fifo_rready_o = 1'b0; + word_part_inc = 1'b0; end end else if (word_part_count_q == 2'b10) begin // word buffer is full and not loaded out yet // fifo_rready_o is now deasserted: accumulated word is waiting to be pushed out @@ -206,6 +213,7 @@ module prim_sha2_32 import prim_sha2_pkg::*; .digest_we_i (digest_we_i), .digest_o (digest_o), .digest_on_blk_o (digest_on_blk_o), + .fifo_st_o (fifo_st), .hash_running_o (hash_running_o), .idle_o (idle_o) ); @@ -259,6 +267,7 @@ module prim_sha2_32 import prim_sha2_pkg::*; .digest_we_i (digest_we_i), .digest_o (digest_o), .digest_on_blk_o (digest_on_blk_o), + .fifo_st_o (fifo_st), .hash_running_o (hash_running_o), .idle_o (idle_o) ); diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_sha2_pad.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_sha2_pad.sv index 1dc010dfef..a7fd1d1f2f 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_sha2_pad.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_sha2_pad.sv @@ -114,10 +114,9 @@ module prim_sha2_pad import prim_sha2_pkg::*; 2'b 00: shaf_rdata_o = 64'h 0000_0000_8000_0000; 2'b 01: shaf_rdata_o = {32'h 0000_0000, fifo_rdata_i.data[31:24], 24'h 8000_00}; 2'b 10: shaf_rdata_o = {32'h 0000_0000, fifo_rdata_i.data[31:16], 16'h 8000}; - 2'b 11: shaf_rdata_o = {32'h 0000_0000, fifo_rdata_i.data[31: 8], 8'h 80}; - default: shaf_rdata_o = 64'h0; + default: shaf_rdata_o = {32'h 0000_0000, fifo_rdata_i.data[31: 8], 8'h 80}; // 2'b11 endcase - end else if ((digest_mode_flag_q == SHA2_384) || (digest_mode_flag_q == SHA2_512)) begin + end else begin // SHA384 || SHA512 unique case (message_length_i[5:3]) 3'b 000: shaf_rdata_o = 64'h 8000_0000_0000_0000; 3'b 001: shaf_rdata_o = {fifo_rdata_i.data[63:56], 56'h 8000_0000_0000_00}; @@ -126,11 +125,9 @@ module prim_sha2_pad import prim_sha2_pkg::*; 3'b 100: shaf_rdata_o = {fifo_rdata_i.data[63:32], 32'h 8000_0000}; 3'b 101: shaf_rdata_o = {fifo_rdata_i.data[63:24], 24'h 8000_00}; 3'b 110: shaf_rdata_o = {fifo_rdata_i.data[63:16], 16'h 8000}; - 3'b 111: shaf_rdata_o = {fifo_rdata_i.data[63:8], 8'h 80}; - default: shaf_rdata_o = 64'h0; + default: shaf_rdata_o = {fifo_rdata_i.data[63:8], 8'h 80}; // 3'b111 endcase - end else - shaf_rdata_o = '0; + end end Pad00: begin @@ -139,16 +136,14 @@ module prim_sha2_pad import prim_sha2_pkg::*; LenHi: begin shaf_rdata_o = ((digest_mode_flag_q == SHA2_256) || ~MultimodeEn) ? - {32'b0, message_length_i[63:32]}: - ((digest_mode_flag_q == SHA2_384) || (digest_mode_flag_q == SHA2_512)) ? - message_length_i[127:64] : '0; + {32'b0, message_length_i[63:32]} : + message_length_i[127:64]; // SHA384 || SHA512 end LenLo: begin shaf_rdata_o = ((digest_mode_flag_q == SHA2_256) || ~MultimodeEn) ? - {32'b0, message_length_i[31:0]}: - ((digest_mode_flag_q == SHA2_384) || (digest_mode_flag_q == SHA2_512)) ? - message_length_i[63:0]: '0; + {32'b0, message_length_i[31:0]} : + message_length_i[63:0]; // SHA384 || SHA512 end default: begin @@ -250,8 +245,8 @@ module prim_sha2_pad import prim_sha2_pkg::*; shaf_rvalid_o = 1'b1; fifo_rready_o = (digest_mode_flag_q == SHA2_256 || ~MultimodeEn) ? shaf_rready_i && |message_length_i[4:3] : - ((digest_mode_flag_q == SHA2_384) || (digest_mode_flag_q == SHA2_512)) ? - shaf_rready_i && |message_length_i[5:3] : '0; // Only when partial + // SHA384 || SHA512. Only when partial. + shaf_rready_i && |message_length_i[5:3]; // exactly 192 bits left, do not need to pad00's if (shaf_rready_i && txcnt_eq_1a0) begin @@ -310,12 +305,12 @@ module prim_sha2_pad import prim_sha2_pkg::*; sel_data = LenHi; shaf_rvalid_o = 1'b1; + st_d = StLenHi; + inc_txcount = 1'b0; + if (shaf_rready_i) begin st_d = StLenLo; inc_txcount = 1'b1; - end else begin - st_d = StLenHi; - inc_txcount = 1'b0; end end @@ -323,12 +318,12 @@ module prim_sha2_pad import prim_sha2_pkg::*; sel_data = LenLo; shaf_rvalid_o = 1'b1; + st_d = StLenLo; + inc_txcount = 1'b0; + if (shaf_rready_i) begin st_d = StIdle; inc_txcount = 1'b1; - end else begin - st_d = StLenLo; - inc_txcount = 1'b0; end end @@ -337,8 +332,13 @@ module prim_sha2_pad import prim_sha2_pkg::*; end endcase - if (!sha_en_i) st_d = StIdle; - else if (hash_go) st_d = StFifoReceive; + if (!sha_en_i) begin + st_d = StIdle; + // We do not allow the cancellation of an ongoing padding operation, i.e., reverting back to the + // `StFifoReceive` state while being in the states `StPad80`, `StPad00`, `StLenHi` or `StLenLo`. + end else if (hash_go && (st_q inside {StIdle, StFifoReceive})) begin + st_d = StFifoReceive; + end end // tx_count @@ -354,7 +354,7 @@ module prim_sha2_pad import prim_sha2_pkg::*; end else if (inc_txcount) begin if ((digest_mode_flag_q == SHA2_256) || !MultimodeEn) begin tx_count_d[127:5] = tx_count[127:5] + 1'b1; - end else if ((digest_mode_flag_q == SHA2_384) || (digest_mode_flag_q == SHA2_512)) begin + end else begin // SHA384 || SHA512 tx_count_d[127:6] = tx_count[127:6] + 1'b1; end end @@ -377,4 +377,11 @@ module prim_sha2_pad import prim_sha2_pkg::*; // State machine is in Idle only when it meets tx_count == message length assign msg_feed_complete_o = (hash_process_flag_q || hash_stop_flag_q) && (st_q == StIdle); + //////////////// + // Assertions // + //////////////// + + `ASSERT(ValidDigestModeFlag_A, sel_data inside {Pad80, LenHi, LenLo} || inc_txcount |-> + digest_mode_flag_q inside {SHA2_256, SHA2_384, SHA2_512}) + endmodule diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_sha2_pkg.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_sha2_pkg.sv index 1a30d278d1..f63b25c818 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_sha2_pkg.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_sha2_pkg.sv @@ -26,6 +26,12 @@ package prim_sha2_pkg; // set to all-1 for word-aligned input } sha_fifo64_t; + typedef enum logic [1:0] { + FifoIdle, + FifoLoadFromFifo, + FifoWait + } fifoctl_state_e; + // one-hot encoded typedef enum logic [3:0] { SHA2_256 = 4'b0001, @@ -113,15 +119,11 @@ package prim_sha2_pkg; }; function automatic sha_word32_t conv_endian32(input sha_word32_t v, input logic swap); - sha_word32_t conv_data = {<<8{v}}; + sha_word32_t conv_data; + conv_data = {<<8{v}}; conv_endian32 = (swap) ? conv_data : v; endfunction : conv_endian32 - function automatic sha_word64_t conv_endian64(input sha_word64_t v, input logic swap); - sha_word64_t conv_data = {<<8{v}}; - conv_endian64 = (swap) ? conv_data : v; - endfunction : conv_endian64 - function automatic sha_word32_t rotr32(input sha_word32_t v, input integer amt); rotr32 = (v >> amt) | (v << (32-amt)); endfunction : rotr32 diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_sram_arbiter.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_sram_arbiter.sv index d166179d57..b29f93e56b 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_sram_arbiter.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_sram_arbiter.sv @@ -5,7 +5,7 @@ // N:1 SRAM arbiter // // Parameter -// N: Number of requst port +// N: Number of request ports // DW: Data width (SECDED is not included) // Aw: Address width // ArbiterImpl: can be either PPC or BINTREE. @@ -126,9 +126,10 @@ module prim_sram_arbiter #( // Request FIFO prim_fifo_sync #( - .Width (N), - .Pass (1'b0), - .Depth (4) // Assume at most 4 pipelined + .Width (N), + .Pass (1'b0), + .Depth (4), // Assume at most 4 pipelined + .NeverClears (1'b1) ) u_req_fifo ( .clk_i, .rst_ni, diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_subreg.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_subreg.sv index 44f01b9cbc..c13f6f303b 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_subreg.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_subreg.sv @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 // -// Register slice conforming to Comportibility guide. +// Register slice conforming to Comportability guide. module prim_subreg import prim_subreg_pkg::*; @@ -62,7 +62,7 @@ module prim_subreg // feed back out for consolidation assign ds = wr_en ? wr_data : qs; - assign qe = wr_en; + assign qe = we; if (SwAccess == SwAccessRC) begin : gen_rc // In case of a SW RC colliding with a HW write, SW gets the value written by HW diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_subreg_arb.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_subreg_arb.sv index 32269cc8b7..eda9ee6eec 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_subreg_arb.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_subreg_arb.sv @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 // -// Write enable and data arbitration logic for register slice conforming to Comportibility guide. +// Write enable and data arbitration logic for register slice conforming to Comportability guide. module prim_subreg_arb import prim_subreg_pkg::*; @@ -29,7 +29,7 @@ module prim_subreg_arb ); import prim_mubi_pkg::*; - if (SwAccess inside {SwAccessRW, SwAccessWO}) begin : gen_w + if ((SwAccess == SwAccessRW) || (SwAccess == SwAccessWO)) begin : gen_w assign wr_en = we | de; assign wr_data = (we == 1'b1) ? wd : d; // SW higher priority // Unused q - Prevent lint errors. diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_subreg_ext.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_subreg_ext.sv index efb662cc17..8924d70dc0 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_subreg_ext.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_subreg_ext.sv @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 // -// Register slice conforming to Comportibility guide. +// Register slice conforming to Comportability guide. module prim_subreg_ext #( parameter int unsigned DW = 32 diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_subreg_shadow.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_subreg_shadow.sv index 53206d0c64..25e841d88d 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_subreg_shadow.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_subreg_shadow.sv @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 // -// Shadowed register slice conforming to Comportibility guide. +// Shadowed register slice conforming to Comportability guide. `include "prim_assert.sv" @@ -77,7 +77,8 @@ module prim_subreg_shadow prim_subreg_arb #( .DW ( DW ), - .SwAccess ( SwAccess ) + .SwAccess ( SwAccess ), + .Mubi ( Mubi ) ) wr_en_data_arb ( .we ( we ), .wd ( wd ), @@ -115,7 +116,8 @@ module prim_subreg_shadow prim_subreg #( .DW ( DW ), .SwAccess ( StagedSwAccess ), - .RESVAL ( ~RESVAL ) + .RESVAL ( ~RESVAL ), + .Mubi ( Mubi ) ) staged_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -140,7 +142,8 @@ module prim_subreg_shadow prim_subreg #( .DW ( DW ), .SwAccess ( InvertedSwAccess ), - .RESVAL ( ~RESVAL ) + .RESVAL ( ~RESVAL ), + .Mubi ( Mubi ) ) shadow_reg ( .clk_i ( clk_i ), .rst_ni ( rst_shadowed_ni ), @@ -162,7 +165,8 @@ module prim_subreg_shadow prim_subreg #( .DW ( DW ), .SwAccess ( SwAccess ), - .RESVAL ( RESVAL ) + .RESVAL ( RESVAL ), + .Mubi ( Mubi ) ) committed_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -188,9 +192,4 @@ module prim_subreg_shadow assign q = committed_q; assign qs = committed_qs; - // prim_subreg_shadow does not support multi-bit software access yet - `ASSERT_NEVER(MubiIsNotYetSupported_A, Mubi) - logic unused_mubi; - assign unused_mubi = Mubi; - endmodule diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_sum_tree.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_sum_tree.sv index 65cfc88f7c..f8c33423d8 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_sum_tree.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_sum_tree.sv @@ -3,26 +3,34 @@ // SPDX-License-Identifier: Apache-2.0 // // Based on prim_max_tree, this module implements an explicit binary tree to find the -// sum of this inputs. The solution has O(N) area and O(log(N)) delay complexity, and +// sum of its inputs. The solution has O(N) area and O(log(N)) delay complexity, and // thus scales well with many input sources. // -// Note that only input values marked as "valid" are respected in the maximum computation. +// Note that only input values marked as "valid" are respected in the sum computation. // Invalid values are treated as 0. // +// By default, the width of the output is equal to the width of the inputs and the internal adders +// saturate. By setting the `Saturate` parameter to 0, this behavior can be disabled. The +// intermediate results as well as the output are then properly sized such that no overflows +// can happen. `include "prim_assert.sv" module prim_sum_tree #( - parameter int NumSrc = 32, - parameter int Width = 8 + parameter int NumSrc = 32, + parameter bit Saturate = 1'b1, + parameter int InWidth = 8, + + localparam int NumLevels = $clog2(NumSrc), // derived parameter + localparam int OutWidth = Saturate ? InWidth : InWidth + NumLevels// derived parameter ) ( // The module is combinational - the clock and reset are only used for assertions. - input clk_i, - input rst_ni, - input [NumSrc-1:0][Width-1:0] values_i, // Input values - input [NumSrc-1:0] valid_i, // Input valid bits - output logic [Width-1:0] sum_value_o, // Summation result - output logic sum_valid_o // Whether any of the inputs is valid + input clk_i, + input rst_ni, + input [NumSrc-1:0][InWidth-1:0] values_i, // Input values + input [NumSrc-1:0] valid_i, // Input valid bits + output logic [OutWidth-1:0] sum_value_o, // Summation result + output logic sum_valid_o // Whether any of the inputs is valid ); /////////////////////// @@ -34,9 +42,8 @@ module prim_sum_tree #( // Align to powers of 2 for simplicity. // A full binary tree with N levels has 2**N + 2**N-1 nodes. - localparam int NumLevels = $clog2(NumSrc); logic [2**(NumLevels+1)-2:0] vld_tree; - logic [2**(NumLevels+1)-2:0][Width-1:0] sum_tree; + logic [2**(NumLevels+1)-2:0][OutWidth-1:0] sum_tree; for (genvar level = 0; level < NumLevels+1; level++) begin : gen_tree // @@ -62,20 +69,35 @@ module prim_sum_tree #( if (level == NumLevels) begin : gen_leafs if (offset < NumSrc) begin : gen_assign assign vld_tree[Pa] = valid_i[offset]; - assign sum_tree[Pa] = values_i[offset]; + assign sum_tree[Pa] = OutWidth'(values_i[offset]); end else begin : gen_tie_off assign vld_tree[Pa] = '0; assign sum_tree[Pa] = '0; end // This creates the node assignments. end else begin : gen_nodes - logic [Width-1:0] node_sum; // Local helper variable - // In case only one of the parents is valid, forward that one - // In case both parents are valid, forward the one with higher value - assign node_sum = (vld_tree[C0] & vld_tree[C1]) ? sum_tree[C1] + sum_tree[C0] : + logic [OutWidth-1:0] node_sum; + logic [OutWidth-1:0] sum; + if (Saturate) begin : gen_sat + // `sum` is not sized to hold the carry bit. + localparam int LocWidth = OutWidth + 1; + logic [LocWidth-1:0] loc_sum; + assign loc_sum = LocWidth'(sum_tree[C1]) + LocWidth'(sum_tree[C0]); + + // Saturation + assign sum = loc_sum[LocWidth-1] ? {OutWidth{1'b1}} : loc_sum[LocWidth-2:0]; + + end else begin : gen_no_sat + // Simply add the node inputs - `sum` is properly sized to hold also the carry bit. + assign sum = sum_tree[C1] + sum_tree[C0]; + end + + // In case only one of the parents is valid, forward that one. + // In case both parents are valid, forward the sum. + assign node_sum = (vld_tree[C0] & vld_tree[C1]) ? sum : (vld_tree[C0]) ? sum_tree[C0] : (vld_tree[C1]) ? sum_tree[C1] : - {Width'(0)}; + {OutWidth'(0)}; // Forwarding muxes // Note: these ternaries have triggered a synthesis bug in Vivado versions older @@ -100,18 +122,27 @@ module prim_sum_tree #( // pragma coverage off // Helper functions for assertions below. - function automatic logic [Width-1:0] sum_value (input logic [NumSrc-1:0][Width-1:0] values_i, - input logic [NumSrc-1:0] valid_i); - logic [Width-1:0] sum = '0; + function automatic logic [OutWidth-1:0] sum_value ( + input logic [NumSrc-1:0][InWidth-1:0] values_i, + input logic [NumSrc-1:0] valid_i + ); + localparam int LocWidth = Saturate ? OutWidth + 1 : OutWidth; + logic [OutWidth-1:0] sum = '0; + logic [LocWidth-1:0] loc_sum; for (int k = 0; k < NumSrc; k++) begin if (valid_i[k]) begin - sum += values_i[k]; + loc_sum = LocWidth'(sum) + LocWidth'(values_i[k]); + if (Saturate) begin + sum = loc_sum[LocWidth-1] ? {OutWidth{1'b1}} : loc_sum[LocWidth-2:0]; + end else begin + sum = loc_sum; + end end end return sum; endfunction : sum_value - logic [Width-1:0] sum_value_exp; + logic [OutWidth-1:0] sum_value_exp; assign sum_value_exp = sum_value(values_i, valid_i); //VCS coverage on // pragma coverage on diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack.sv index 4dc029d4e8..6fafcb8402 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack.sv @@ -23,7 +23,7 @@ // That one has lower throughput, but it is safe to reset either domain in isolation, since the // two FSMs cannot get out of sync due to persistent EVEN/ODD states. The handshake latencies // are the same as for the NRZ protocol, but the throughput is half that of the NRZ protocol -// since the signals neet to return to zero first, causing two round-trips through the +// since the signals need to return to zero first, causing two round-trips through the // synchronizers instead of just one. // // For further information, see Section 8.2.4 in H. Kaeslin, "Top-Down Digital VLSI Design: From diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_trivium.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_trivium.sv index c648a31e5a..10deb239ba 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_trivium.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_trivium.sv @@ -30,7 +30,7 @@ // PartialSeedWidth-wide part of the state has been overwritten once. // To enable updating the primitive and using the key stream during the reseed operation, the // number of output bits produced per update (OutputWidth) should be greater than the width of -// the smallest NFSR in the primitve (MinNfsrWidth = 84). Thanks to the strong diffusion +// the smallest NFSR in the primitive (MinNfsrWidth = 84). Thanks to the strong diffusion // properties of the primitives, the majority of state and key stream bits change after // reseeding the first state part and performing the first couple of updates if OutputWidth is // chosen sufficiently large. For Bivium, a quick evaluation hints that for OutputWidth equal @@ -64,7 +64,7 @@ module prim_trivium import prim_trivium_pkg::*; // restore to the default seed, or 0: allow // to keep the all zero state if requested by // allow_lockup_i. - parameter seed_type_e SeedType = SeedTypeStateFull, // Reseeding inteface selection, see + parameter seed_type_e SeedType = SeedTypeStateFull, // Reseeding interface selection, see // prim_trivium_pkg.sv for possible values. parameter int unsigned PartialSeedWidth = PartialSeedWidthDefault, @@ -308,7 +308,7 @@ module prim_trivium import prim_trivium_pkg::*; // While performing a partial reseed of the state, the primitive can be updated. However, this // should only be done if the number of produced bits per update / shift amount per update is - // greater than the width of the smallest NFSR (= 84) inside the primitve. Otherwise, there is a + // greater than the width of the smallest NFSR (= 84) inside the primitive. Otherwise, there is a // risk of overwriting the previously provided partial seed which reduces the amount of fresh // entropy injected per full reseed operation. `ASSERT(PrimTriviumPartialStateSeedWhileUpdate_A, 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 81600a8de8..ccb3e80b7e 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_util_memload.svh +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_util_memload.svh @@ -55,11 +55,13 @@ `endif initial begin +`ifndef SYNTHESIS logic show_mem_paths; // Print the hierarchical path to the memory to help make formal connectivity checks easy. void'($value$plusargs("show_mem_paths=%0b", show_mem_paths)); if (show_mem_paths) $display("%m"); +`endif if (MemInitFile != "") begin : gen_meminit $display("Initializing memory %m from file '%s'.", MemInitFile); diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_util_pkg.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_util_pkg.sv index cb30121cef..b1302cc23d 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_util_pkg.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_util_pkg.sv @@ -7,37 +7,6 @@ * Utility functions */ package prim_util_pkg; - /** - * Math function: $clog2 as specified in Verilog-2005 - * - * Do not use this function if $clog2() is available. - * - * clog2 = 0 for value == 0 - * ceil(log2(value)) for value >= 1 - * - * This implementation is a synthesizable variant of the $clog2 function as - * specified in the Verilog-2005 standard (IEEE 1364-2005). - * - * To quote the standard: - * The system function $clog2 shall return the ceiling of the log - * base 2 of the argument (the log rounded up to an integer - * value). The argument can be an integer or an arbitrary sized - * vector value. The argument shall be treated as an unsigned - * value, and an argument value of 0 shall produce a result of 0. - */ - function automatic integer _clog2(integer value); - integer result; - // Use an intermediate value to avoid assigning to an input port, which produces a warning in - // Synopsys DC. - integer v = value; - v = v - 1; - for (result = 0; v > 0; result++) begin - v = v >> 1; - end - return result; - endfunction - - /** * Math function: Number of bits needed to address |value| items. * @@ -72,18 +41,26 @@ package prim_util_pkg; * logic [vbits(64 + 1)-1:0] store_number_64; // width is [6:0] */ function automatic integer vbits(integer value); -`ifdef XCELIUM - // The use of system functions was not allowed here in Verilog-2001, but is - // valid since (System)Verilog-2005, which is also when $clog2() first - // appeared. - // Xcelium < 19.10 does not yet support the use of $clog2() here, fall back - // to an implementation without a system function. Remove this workaround - // if we require a newer Xcelium version. - // See #2579 and #2597. - return (value == 1) ? 1 : _clog2(value); -`else return (value == 1) ? 1 : $clog2(value); -`endif + endfunction + + /** + * Computes the ceiling division of two integer values. + * + * This function performs integer division and rounds the result up to the nearest integer. + * It effectively computes the smallest integer greater than or equal to dividend / divisor. + * + * @param dividend The integer dividend. + * @param divisor The integer divisor. + * @return The ceiling division result (dividend / divisor, rounded up). + * + * Example: + * ceil_div(10, 3) returns 4 + * ceil_div(12, 4) returns 3 + * ceil_div(15, 6) returns 3 + */ + function automatic integer ceil_div(input integer dividend, input integer divisor); + ceil_div = ((dividend % divisor) != 0) ? (dividend / divisor) + 1 : (dividend / divisor); endfunction `ifdef INC_ASSERT diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_xoshiro256pp.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_xoshiro256pp.sv index ed7cc1b5a8..7b90bef787 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_xoshiro256pp.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_xoshiro256pp.sv @@ -7,7 +7,7 @@ // Additional Entropy input to XOR fresh entropy into the state. // Lockup protection that reseeds the generator if it falls into the all-zero state. // -// Refs: [1] D. Blackman and S. Vigna, Scrambled Linear Pseudorndom Number Generators +// Refs: [1] D. Blackman and S. Vigna, Scrambled Linear Pseudorandom Number Generators // https://arxiv.org/pdf/1805.01407.pdf // [2] https://prng.di.unimi.it/ // [3] https://en.wikipedia.org/wiki/Xorshift#xoshiro_and_xoroshiro diff --git a/vendor/lowrisc_ip/ip/prim/util/primgen.py b/vendor/lowrisc_ip/ip/prim/util/primgen.py deleted file mode 100755 index 3e3ba4123d..0000000000 --- a/vendor/lowrisc_ip/ip/prim/util/primgen.py +++ /dev/null @@ -1,497 +0,0 @@ -#!/usr/bin/env python3 -# Copyright lowRISC contributors (OpenTitan project). -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 - -import os -import re -import shutil -import sys - -import yaml -from mako.template import Template - -# Make vendored packages available in the search path. -sys.path.append(os.path.join(os.path.dirname(__file__), 'vendor')) - -try: - from yaml import CSafeDumper as YamlDumper - from yaml import CSafeLoader as YamlLoader -except ImportError: - from yaml import SafeDumper as YamlDumper - from yaml import SafeLoader as YamlLoader - - -def _split_vlnv(core_vlnv): - (vendor, library, name, version) = core_vlnv.split(':', 4) - return { - 'vendor': vendor, - 'library': library, - 'name': name, - 'version': version - } - - -def _prim_cores(cores, prim_name=None): - """ Get all cores of primitives found by fusesoc - - If prim_name is given, only primitives with the given name are returned. - Otherwise, all primitives are returned, independent of their name. - """ - - def _filter_primitives(core): - """ Filter a list of cores to find the primitives we're interested in - - Matching cores follow the pattern - "lowrisc:prim_:", where "" and - "" are placeholders. - """ - - vlnv = _split_vlnv(core[0]) - if (vlnv['vendor'] == 'lowrisc' and - vlnv['library'].startswith('prim_') and - (prim_name is None or vlnv['name'] == prim_name)): - - return core - return None - - return dict(filter(_filter_primitives, cores.items())) - - -def _techlibs(prim_cores): - techlibs = set() - for name, info in prim_cores.items(): - vlnv = _split_vlnv(name) - techlibs.add(_library_to_techlib_name(vlnv['library'])) - return techlibs - - -def _library_to_techlib_name(library): - return library[len("prim_"):] - - -def _core_info_for_techlib(prim_cores, techlib): - for name, info in prim_cores.items(): - vlnv = _split_vlnv(name) - if _library_to_techlib_name(vlnv['library']) == techlib: - return (name, info) - - -def _enum_name_for_techlib(techlib_name, qualified=True): - name = "Impl" + techlib_name.capitalize() - if qualified: - name = "prim_pkg::" + name - return name - - -def _top_module_file(core_files, module_name): - module_filename = module_name + '.sv' - for file in core_files: - if os.path.basename(file) == module_filename: - return file - - -def _parse_module_header_verible(generic_impl_filepath, module_name): - """ Parse a SystemVerilog file to extract the 'module' header using Verible - - Implementation of _parse_module_header() which uses verible-verilog-syntax - to do the parsing. This is the primary implementation and is used when - supported Verible version is available. - - See _parse_module_header() for API details. - """ - - from google_verible_verilog_syntax_py.verible_verilog_syntax import ( - PreOrderTreeIterator, VeribleVerilogSyntax) - - parser = VeribleVerilogSyntax() - - data = parser.parse_file(generic_impl_filepath, - options={"skip_null": True}) - if data.errors: - for err in data.errors: - print( - f'Verible: {err.phase} error in line {err.line} column {err.column}' + - (': {err.message}' if err.message else '.')) - # Intentionally not raising an exception here. - # There are chances that Verible recovered from errors. - if not data.tree: - raise ValueError(f"Unable to parse {generic_impl_filepath!r}.") - - module = data.tree.find({"tag": "kModuleDeclaration"}) - header = module.find({"tag": "kModuleHeader"}) - if not header: - raise ValueError("Unable to extract module header from %s." % - (generic_impl_filepath, )) - - name = header.find({"tag": ["SymbolIdentifier", "EscapedIdentifier"]}, - iter_=PreOrderTreeIterator) - if not name: - raise ValueError("Unable to extract module name from %s." % - (generic_impl_filepath, )) - - imports = header.find_all({"tag": "kPackageImportDeclaration"}) - - parameters_list = header.find({"tag": "kFormalParameterList"}) - parameters = set() - if parameters_list: - for parameter in sorted( - parameters_list.iter_find_all({"tag": "kParamDeclaration"})): - if parameter.find({"tag": "parameter"}): - parameter_id = parameter.find( - {"tag": ["SymbolIdentifier", "EscapedIdentifier"]}) - parameters.add(parameter_id.text) - - ports = header.find({"tag": "kPortDeclarationList"}) - - return { - 'module_header': header.text, - 'package_import_declaration': '\n'.join([i.text for i in imports]), - 'parameter_port_list': parameters_list.text if parameters_list else '', - 'ports': ports.text if ports else '', - 'parameters': parameters, - 'parser': 'Verible' - } - - -def _parse_module_header_fallback(generic_impl_filepath, module_name): - """ Parse a SystemVerilog file to extract the 'module' header using RegExp - - Legacy implementation of _parse_module_header() using regular expressions. - It is not as robust as Verible-backed implementation, but doesn't need - Verible to work. - - See _parse_module_header() for API details. - """ - - # Grammar fragments from the SV2017 spec: - # - # module_nonansi_header ::= - # { attribute_instance } module_keyword [ lifetime ] module_identifier - # { package_import_declaration } [ parameter_port_list ] list_of_ports ; - # module_ansi_header ::= - # { attribute_instance } module_keyword [ lifetime ] module_identifier - # { package_import_declaration }1 [ parameter_port_list ] [ list_of_port_declarations ] - # package_import_declaration ::= - # import package_import_item { , package_import_item } ; - # package_import_item ::= - # package_identifier :: identifier - # | package_identifier :: * - - RE_MODULE_HEADER = ( - r'(?:\s|^)' - r'(?P' # start: capture the whole module header - r'module\s+' # module_keyword - r'(?:(?:static|automatic)\s+)?' + # lifetime (optional) - module_name + # module_identifier - # package_import_declaration (optional, skipped) - r'\s*(?P(?:import\s+[^;]+;)+)?' - r'\s*(?:#\s*\((?P[^;]+)\))?' # parameter_port_list (optional) - r'\s*\(\s*(?P[^;]+)\s*\)' # list_of_port_declarations or list_of_ports - r'\s*;' # trailing semicolon - r')' # end: capture the whole module header - ) - - data = "" - with open(generic_impl_filepath, encoding="utf-8") as file: - data = file.read() - re_module_header = re.compile(RE_MODULE_HEADER, re.DOTALL) - matches = re_module_header.search(data) - if not matches: - raise ValueError("Unable to extract module header from %s." % - (generic_impl_filepath, )) - - parameter_port_list = matches.group('parameter_port_list') or '' - return { - 'module_header': - matches.group('module_header').strip(), - 'package_import_declaration': - matches.group('package_import_declaration') or '', - 'parameter_port_list': - parameter_port_list, - 'ports': - matches.group('ports').strip() or '', - 'parameters': - _parse_parameter_port_list(parameter_port_list), - 'parser': - 'Fallback (regex)' - } - - -def test_parse_parameter_port_list(): - assert _parse_parameter_port_list("parameter enum_t P") == {'P'} - assert _parse_parameter_port_list("parameter integer P") == {'P'} - assert _parse_parameter_port_list("parameter logic [W-1:0] P") == {'P'} - assert _parse_parameter_port_list("parameter logic [W-1:0] P = '0") == { - 'P' - } - assert _parse_parameter_port_list("parameter logic [W-1:0] P = 'b0") == { - 'P' - } - assert _parse_parameter_port_list("parameter logic [W-1:0] P = 2'd0") == { - 'P' - } - - -def _parse_parameter_port_list(parameter_port_list): - """ Parse a list of ports in a module header into individual parameters """ - - # Grammar (SV2017): - # - # parameter_port_list ::= - # # ( list_of_param_assignments { , parameter_port_declaration } ) - # | # ( parameter_port_declaration { , parameter_port_declaration } ) - # | #( ) - # parameter_port_declaration ::= - # parameter_declaration - # | local_parameter_declaration - # | data_type list_of_param_assignments - # | type list_of_type_assignments - - # XXX: Not covering the complete grammar, e.g. `parameter x, y` - RE_PARAMS = ( - r'parameter\s+' - r'(?:[a-zA-Z0-9_\]\[:\s\$-]+\s+)?' # type - r'(?P\w+)' # name - r'(?:\s*=\s*[^,;]+)?' # initial value - ) - re_params = re.compile(RE_PARAMS) - parameters = set() - for m in re_params.finditer(parameter_port_list): - parameters.add(m.group('name')) - return list(sorted(parameters)) - - -def _parse_module_header(generic_impl_filepath, module_name): - """ Parse a SystemVerilog file to extract the 'module' header - - Return a dict with the following entries: - - module_header: the whole module header (including the 'module' keyword) - - package_import_declaration: import declarations - - parameter_port_list: parameter/localparam declarations in the header - - ports: the list of ports. The portlist can be ANSI or non-ANSI style (with - or without signal declarations; see the SV spec for details). - - parser: parser used to extract the data. - """ - - try: - return _parse_module_header_verible(generic_impl_filepath, module_name) - except Exception as e: - print(e) - print("Verible parser failed, using regex fallback instead.") - return _parse_module_header_fallback(generic_impl_filepath, - module_name) - - -def _check_gapi(gapi): - if 'cores' not in gapi: - print("Key 'cores' not found in GAPI structure. " - "Install a compatible version with " - "'pip3 install --user -r python-requirements.txt'.") - return False - return True - - -def _generate_prim_pkg(gapi): - all_prim_cores = _prim_cores(gapi['cores']) - techlibs = _techlibs(all_prim_cores) - - techlib_enums = [] - - # Insert the required generic library first to ensure it gets enum value 0 - techlib_enums.append(_enum_name_for_techlib('generic', qualified=False)) - - for techlib in techlibs: - if techlib == 'generic': - # The generic implementation is required and handled separately. - continue - techlib_enums.append(_enum_name_for_techlib(techlib, qualified=False)) - - # Render prim_pkg.sv file - print("Creating prim_pkg.sv") - prim_pkg_sv_tpl_filepath = os.path.join(os.path.dirname(__file__), - 'primgen', 'prim_pkg.sv.tpl') - prim_pkg_sv_tpl = Template(filename=prim_pkg_sv_tpl_filepath) - - prim_pkg_sv = prim_pkg_sv_tpl.render(encoding="utf-8", - techlib_enums=techlib_enums) - with open('prim_pkg.sv', 'w') as f: - f.write(prim_pkg_sv) - - # Copy prim_pkg.core (no changes needed) - prim_pkg_core_src = os.path.join(os.path.dirname(__file__), 'primgen', - 'prim_pkg.core.tpl') - prim_pkg_core_dest = 'prim_pkg.core' - shutil.copyfile(prim_pkg_core_src, prim_pkg_core_dest) - print("Core file written to %s." % (prim_pkg_core_dest, )) - - -def _instance_sv(prim_name, techlib, parameters): - if not parameters: - s = " prim_{techlib}_{prim_name} u_impl_{techlib} (\n" - else: - s = " prim_{techlib}_{prim_name} #(\n" - s += ",\n".join(" .{p}({p})".format(p=p) for p in parameters) - s += "\n ) u_impl_{techlib} (\n" - s += " .*\n" \ - " );\n" - return s.format(prim_name=prim_name, techlib=techlib) - - -def _create_instances(prim_name, techlibs, parameters): - """ Build SystemVerilog code instantiating primitives from the techlib """ - - # Sort list of technology libraries to produce a stable ordering in the - # generated wrapper. - techlibs_wo_generic = sorted( - [techlib for techlib in techlibs if techlib != 'generic']) - techlibs_generic_last = techlibs_wo_generic + ['generic'] - - if not techlibs_wo_generic: - # Don't output the if/else blocks if there no alternatives exist. - # We still want the generate block to keep hierarchical path names - # stable, even if more than one techlib is found. - s = " if (1) begin : gen_generic\n" - s += _instance_sv(prim_name, "generic", parameters) + "\n" - s += " end" - return s - - nr_techlibs = len(techlibs_generic_last) - out = "" - for pos, techlib in enumerate(techlibs_generic_last): - is_first = pos == 0 - is_last = pos == nr_techlibs - 1 - - s = "" - if not is_first: - s += "else " - if not is_last: - s += "if (Impl == {techlib_enum}) " - - # TODO: wildcard port lists are against our style guide, but it's safer - # to let the synthesis tool figure out the connectivity than us trying - # to parse the port list into individual signals. - s += "begin : gen_{techlib}\n" + _instance_sv(prim_name, techlib, - parameters) + "end" - - if not is_last: - s += " " - - out += s.format(prim_name=prim_name, - techlib=techlib, - techlib_enum=_enum_name_for_techlib(techlib)) - return out - - -def _generate_abstract_impl(gapi): - prim_name = gapi['parameters']['prim_name'] - prim_cores = _prim_cores(gapi['cores'], prim_name) - - techlibs = _techlibs(prim_cores) - - if 'generic' not in techlibs: - raise ValueError("Techlib generic is required, but not found for " - "primitive %s." % prim_name) - print("Implementations for primitive %s: %s" % - (prim_name, ', '.join(techlibs))) - - # Extract port list out of generic implementation - generic_core = _core_info_for_techlib(prim_cores, 'generic')[1] - generic_module_name = 'prim_generic_' + prim_name - top_module_filename = _top_module_file(generic_core['files'], - generic_module_name) - top_module_file = os.path.join(generic_core['core_root'], - top_module_filename) - - print("Inspecting generic module %s" % (top_module_file, )) - generic_hdr = _parse_module_header(top_module_file, generic_module_name) - - # Render abstract primitive HDL from template - print("Creating SystemVerilog module for abstract primitive") - abstract_prim_sv_tpl_filepath = os.path.join(os.path.dirname(__file__), - 'primgen', - 'abstract_prim.sv.tpl') - abstract_prim_sv_tpl = Template(filename=abstract_prim_sv_tpl_filepath) - - abstract_prim_sv = abstract_prim_sv_tpl.render( - encoding="utf-8", - prim_name=prim_name, - 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, - generic_hdr['parameters']), - parser_info=generic_hdr['parser']) - abstract_prim_sv_filepath = 'prim_%s.sv' % (prim_name) - with open(abstract_prim_sv_filepath, 'w') as f: - f.write(abstract_prim_sv) - print("Abstract primitive written to %s" % - (os.path.abspath(abstract_prim_sv_filepath), )) - - # Create core file depending on all primitive implementations we have in the - # techlibs. - print("Creating core file for primitive %s." % (prim_name, )) - abstract_prim_core_filepath = os.path.abspath('prim_%s.core' % (prim_name)) - dependencies = [] - dependencies.append('lowrisc:prim:prim_pkg') - dependencies += [ - _core_info_for_techlib(prim_cores, t)[0] for t in techlibs - ] - abstract_prim_core = { - 'name': "lowrisc:prim_abstract:%s" % (prim_name, ), - 'filesets': { - 'files_rtl': { - 'depend': dependencies, - 'files': [ - abstract_prim_sv_filepath, - ], - 'file_type': 'systemVerilogSource' - }, - }, - 'targets': { - 'default': { - 'filesets': [ - 'files_rtl', - ], - }, - }, - } - with open(abstract_prim_core_filepath, 'w') as f: - # FuseSoC requires this line to appear first in the YAML file. - # Inserting this line through the YAML serializer requires ordered dicts - # to be used everywhere, which is annoying syntax-wise on Python <3.7, - # where native dicts are not sorted. - f.write('CAPI=2:\n') - yaml.dump(abstract_prim_core, f, encoding="utf-8", Dumper=YamlDumper) - print("Core file written to %s" % (abstract_prim_core_filepath, )) - - -def _get_action_from_gapi(gapi, default_action): - if 'parameters' in gapi and 'action' in gapi['parameters']: - return gapi['parameters']['action'] - return default_action - - -def main(): - gapi_filepath = sys.argv[1] - with open(gapi_filepath) as f: - gapi = yaml.load(f, Loader=YamlLoader) - - if not _check_gapi(gapi): - sys.exit(1) - - action = _get_action_from_gapi(gapi, 'generate_abstract_impl') - - if action == 'generate_abstract_impl': - return _generate_abstract_impl(gapi) - elif action == 'generate_prim_pkg': - return _generate_prim_pkg(gapi) - else: - raise ValueError("Invalid action: %s" % (action, )) - - -if __name__ == '__main__': - main() 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 deleted file mode 100644 index 9b3432a3fe..0000000000 --- a/vendor/lowrisc_ip/ip/prim/util/primgen/abstract_prim.sv.tpl +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright lowRISC contributors (OpenTitan project). -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -// This file is auto-generated. -// Used parser: ${parser_info} - -% 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 HIER_BRANCH_NOT_READ -module prim_${prim_name} -${module_header_imports} -#( -${module_header_params} -) ( - ${module_header_ports} -); -% if num_techlibs > 1: - localparam prim_pkg::impl_e Impl = `PRIM_DEFAULT_IMPL; -% endif - -${instances} - -endmodule -//ri lint_check_on OUTPUT_NOT_DRIVEN INPUT_NOT_READ HIER_BRANCH_NOT_READ diff --git a/vendor/lowrisc_ip/ip/prim/util/primgen/prim_pkg.sv.tpl b/vendor/lowrisc_ip/ip/prim/util/primgen/prim_pkg.sv.tpl deleted file mode 100644 index def5d49625..0000000000 --- a/vendor/lowrisc_ip/ip/prim/util/primgen/prim_pkg.sv.tpl +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright lowRISC contributors (OpenTitan project). -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 -// -// Constants for use in primitives - -// This file is auto-generated. - -package prim_pkg; - - // Implementation target specialization - typedef enum integer { - ${',\n '.join(techlib_enums)} - } impl_e; -endpackage : prim_pkg diff --git a/vendor/lowrisc_ip/ip/prim_generic/BUILD b/vendor/lowrisc_ip/ip/prim_generic/BUILD index f42854cd1b..307b2eb253 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/BUILD +++ b/vendor/lowrisc_ip/ip/prim_generic/BUILD @@ -5,7 +5,14 @@ package(default_visibility = ["//visibility:public"]) filegroup( - name = "all_files", - srcs = glob(["**"]) + [ + name = "rtl_files", + srcs = glob( + ["**"], + exclude = [ + "dv/**", + "doc/**", + "README.md", + ], + ) + [ ], ) diff --git a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_buf.vlt b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_buf.vlt index c61d4c6ea4..3952982334 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_buf.vlt +++ b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_buf.vlt @@ -5,4 +5,4 @@ `verilator_config -lint_off -rule UNUSED -file "*/rtl/prim_generic_clock_buf.sv" -match "Parameter is not used: 'NoFpgaBuf'" +lint_off -rule UNUSED -file "*/rtl/prim_clock_buf.sv" -match "Parameter is not used: 'NoFpgaBuf'" diff --git a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_buf.waiver b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_buf.waiver index 89ab9b8ffb..4fedf95345 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_buf.waiver +++ b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_buf.waiver @@ -2,6 +2,6 @@ # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 # -# primitives: prim_generic_clock_buf -waive -rules PARAM_NOT_USED -location {prim_generic_clock_buf.sv} -regexp {Parameter '(NoFpgaBuf|RegionSel)' not used} \ +# primitives: prim_clock_buf +waive -rules PARAM_NOT_USED -location {prim_clock_buf.sv} -regexp {Parameter '(NoFpgaBuf|RegionSel)' not used} \ -comment "parameter unused but required to maintain uniform interface" diff --git a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_div.waiver b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_div.waiver index d748ccb33d..39c024c2c1 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_div.waiver +++ b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_div.waiver @@ -2,19 +2,43 @@ # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 # -# waiver file for prim_generic_clock_div +# waiver file for prim_clock_div -waive -rules CLOCK_EDGE -location {prim_generic_clock_div.sv} -msg {Falling edge of clock 'clk_i' used here, should use rising edge} \ +waive -rules CLOCK_EDGE -location {prim_clock_div.sv} -msg {Falling edge of clock 'clk_i' used here, should use rising edge} \ -comment "The clock switch signal is synchronized on negative edge to ensure it is away from any transition" -waive -rules DUAL_EDGE_CLOCK -location {prim_generic_clock_div.sv} -regexp {.*} \ +waive -rules DUAL_EDGE_CLOCK -location {prim_clock_div.sv} -regexp {.*} \ -comment "The clock switch signal is synchronized on negative edge to ensure it is away from any transition" -waive -rules CLOCK_MUX -location {prim_generic_clock_div.sv} -regexp {.*reaches a multiplexer here, used as a clock.*} \ +waive -rules CLOCK_MUX -location {prim_clock_div.sv} -regexp {.*reaches a multiplexer here, used as a clock.*} \ -comment "A mux is used during scan bypass, and for switching between div by 2 and div by 1 clocks" -waive -rules CLOCK_USE -location {prim_generic_clock_div.sv} -regexp {'clk_i' is connected to 'prim_clock_mux2' port 'clk1_i', and used as a clock} \ +waive -rules CLOCK_USE -location {prim_clock_div.sv} -regexp {'clk_i' is connected to 'prim_clock_mux2' port 'clk1_i', and used as a clock} \ -comment "This clock mux usage is OK." -waive -rules SAME_NAME_TYPE -location {prim_generic_clock_div.sv} -regexp {'ResetValue' is used as a parameter here, and as an enumeration value at} \ +waive -rules SAME_NAME_TYPE -location {prim_clock_div.sv} -regexp {'ResetValue' is used as a parameter here, and as an enumeration value at} \ -comment "Reused parameter name." + +waive -rules CLOCK_DRIVER -location {prim_clock_div.sv} -regexp {'gen_div2.q_p' is driven by instance 'gen_div2\^u_div2' of module 'prim_flop', and used as a clock 'clk_i'} \ + -comment "A 'prim_flop' is used together with a 'prim_clock_inv' to implement a division by 2" + +waive -rules CLOCK_USE -location {prim_clock_div.sv} -regexp {'gen_div2.q_n' is connected to 'prim_flop' port 'd_i\[0\]', and used as a clock 'clk_i'} \ + -comment "A 'prim_flop' is used together with a 'prim_clock_inv' to implement a division by 2" + +waive -rules INV_CLOCK -location {prim_clock_div.sv} -regexp {'gen_div2.q_p' is inverted, used as clock 'clk_i'} \ + -comment "A 'prim_flop' is used together with a 'prim_clock_inv' to implement a division by 2" + +waive -rules CLOCK_DRIVER -location {prim_clock_div.sv} -regexp {'clk_int' is driven here, and used as a clock} \ + -comment "The division by more than 2 is implemented using a behavioral toggle counter" + +waive -rules CLOCK_MUX -location {prim_clock_div.sv} -regexp {Clock 'clk_int' is driven by a multiplexer here, used as a clock 'clk_i'} \ + -comment "This clock mux usage is OK." + +waive -rules CLOCK_MUX -location {prim_clock_div.sv} -regexp {Clock 'clk_muxed' is driven by a multiplexer here, used as a clock} \ + -comment "This clock mux usage is OK." + +waive -rules CLOCK_USE -location {prim_clock_div.sv} -regexp {'clk_muxed' is used for some other purpose, and as clock} \ + -comment "The division by more than 2 is implemented using a behavioral toggle counter driven by 'clk_muxed'" + +waive -rules INV_CLOCK -location {prim_clock_div.sv} -regexp {'clk_muxed' is inverted, used as clock} \ + -comment "The division by more than 2 is implemented using a behavioral toggle counter driven by 'clk_muxed'" diff --git a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_gating.vlt b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_gating.vlt index 2c6c5af87c..8663692959 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_gating.vlt +++ b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_gating.vlt @@ -5,5 +5,5 @@ `verilator_config -lint_off -rule UNUSED -file "*/rtl/prim_generic_clock_gating.sv" -match "Parameter is not used: 'NoFpgaGate'" -lint_off -rule UNUSED -file "*/rtl/prim_generic_clock_gating.sv" -match "Parameter is not used: 'FpgaBufGlobal'" +lint_off -rule UNUSED -file "*/rtl/prim_clock_gating.sv" -match "Parameter is not used: 'NoFpgaGate'" +lint_off -rule UNUSED -file "*/rtl/prim_clock_gating.sv" -match "Parameter is not used: 'FpgaBufGlobal'" diff --git a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_gating.waiver b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_gating.waiver index 1eb8561142..e68c145996 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_gating.waiver +++ b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_gating.waiver @@ -3,11 +3,11 @@ # SPDX-License-Identifier: Apache-2.0 # # primitives: prim_clock_gating -waive -rules LATCH -location {prim_generic_clock_gating.sv} -regexp {'en_latch' is a latch} \ +waive -rules LATCH -location {prim_clock_gating.sv} -regexp {'en_latch' is a latch} \ -comment "clock gating cell creates a latch" -waive -rules COMBO_NBA -location {prim_generic_clock_gating.sv} -regexp {Non-blocking assignment to 'en_latch'} \ +waive -rules COMBO_NBA -location {prim_clock_gating.sv} -regexp {Non-blocking assignment to 'en_latch'} \ -comment "clock gating cell creates a latch" -waive -rules PARAM_NOT_USED -location {prim_generic_clock_gating.sv} -regexp {Parameter 'NoFpgaGate' not used} \ +waive -rules PARAM_NOT_USED -location {prim_clock_gating.sv} -regexp {Parameter 'NoFpgaGate' not used} \ -comment "parameter unused but required to maintain uniform interface" -waive -rules PARAM_NOT_USED -location {prim_generic_clock_gating.sv} -regexp {Parameter 'FpgaBufGlobal' not used} \ +waive -rules PARAM_NOT_USED -location {prim_clock_gating.sv} -regexp {Parameter 'FpgaBufGlobal' not used} \ -comment "parameter unused but required to maintain uniform interface" diff --git a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_mux2.vlt b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_mux2.vlt index d62099a9af..23cd4fa4ab 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_mux2.vlt +++ b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_mux2.vlt @@ -5,4 +5,4 @@ `verilator_config -lint_off -rule UNUSED -file "*/rtl/prim_generic_clock_mux2.sv" -match "Parameter is not used: 'NoFpgaBufG'" +lint_off -rule UNUSED -file "*/rtl/prim_clock_mux2.sv" -match "Parameter is not used: 'NoFpgaBufG'" 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 42d76a8dfa..62d6c52363 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 @@ -4,5 +4,5 @@ # # waiver file for prim_clock_mux2 -waive -rules PARAM_NOT_USED -location {prim_generic_clock_mux2.sv} -regexp {.*Parameter 'NoFpgaBufG' not used in.*} \ +waive -rules PARAM_NOT_USED -location {prim_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_flash.waiver b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_flash.waiver index d733a25619..d69580656b 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_flash.waiver +++ b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_flash.waiver @@ -2,8 +2,11 @@ # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 # -# waiver file for prim_generic_flash +# waiver file for prim_flash # The prim generic module does not make use of the IO ports -waive -rules INOUT_AS_IN -location {prim_generic_flash.sv} \ +waive -rules INOUT_AS_IN -location {prim_flash.sv} \ -regexp {Inout port 'flash_.*_io' has no driver} + +waive -rules {RESET_USE} -location {prim_generic_flash_bank.sv} -regexp {rst_ni' is connected to 'prim_ram_1p' port 'rst_ni', and used as an asynchronous reset or set at prim_generic_flash_bank.sv} \ + -comment "rst_ni is the asynchronous reset of prim_ram_1p_adv. It's unused in the generic implementation, but other implementations may use it." diff --git a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_flop_2sync.waiver b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_flop_2sync.waiver new file mode 100644 index 0000000000..9cb13fb9fe --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_flop_2sync.waiver @@ -0,0 +1,8 @@ +# Copyright lowRISC contributors (OpenTitan project). +# 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 {IFDEF_CODE} -location {prim_flop_2sync.sv} -regexp {.*contained within \`else block.*} \ + -comment "Ifdefs are required for prim_flop_2sync since it is turned on only for simulation." diff --git a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_otp.vlt b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_otp.vlt deleted file mode 100644 index 3aa735e988..0000000000 --- a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_otp.vlt +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright lowRISC contributors (OpenTitan project). -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 -// - -`verilator_config - -// The generic OTP module doesn't use vendor-specific parameters -lint_off -rule UNUSED -file "*/rtl/prim_generic_otp.sv" -match "*VendorTestOffset*" -lint_off -rule UNUSED -file "*/rtl/prim_generic_otp.sv" -match "*VendorTestSize*" 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 deleted file mode 100644 index c2313ab038..0000000000 --- a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_otp.waiver +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright lowRISC contributors (OpenTitan project). -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 -# - -waive -rules {CONST_FF} -location {prim_ram_1p_adv.sv} \ - -msg {Flip-flop 'rerror_q' is driven by constant zeros in module 'prim_ram_1p_adv' (Depth=1024,Width=22,EnableInputPipeline=1,EnableOutputPipeline=1)} \ - -comment "The read error bits are unused and hence set to zero." - -waive -rules {INOUT_AS_IN} -location {prim_generic_otp.sv} \ - -msg {Inout port 'ext_voltage_io' has no driver in module 'prim_generic_otp'} \ - -comment "This signal is not driven in the generic model." - -waive -rules {PARAM_NOT_USED} -location {prim_generic_otp.sv} \ - -regexp {Parameter '(VendorTestOffset|VendorTestSize)' not used in module 'prim_generic_otp'} \ - -comment "These two parameters are not used in the generic model." diff --git a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_pad_wrapper.waiver b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_pad_wrapper.waiver index e9e9acd1ab..527b7f8ac2 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_pad_wrapper.waiver +++ b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_pad_wrapper.waiver @@ -2,26 +2,32 @@ # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 # -# waiver file for prim_generic_pad_wrapper +# waiver file for prim_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_generic_pad_wrapper.sv} \ +waive -rules TRI_DRIVER -regexp {'inout_io' is driven by a tristate driver} -location {prim_pad_wrapper.sv} \ -comment "This is a bidirectional pad inout." waive -rules TRI_DRIVER -regexp {'in_raw_o' is driven by a tristate driver} \ -comment "This is a bidirectional pad inout." -waive -rules MULTI_DRIVEN -regexp {.* drivers on 'inout_io' here} -location {prim_generic_pad_wrapper.sv} \ +waive -rules MULTI_DRIVEN -regexp {.* drivers on 'inout_io' here} -location {prim_pad_wrapper.sv} \ -comment "The pad simulation model has multiple drivers to emulate different IO terminations." -waive -rules SELF_ASSIGN -regexp {LHS signal 'inout_io' encountered on the RHS of a continuous assignment statement} -location {prim_generic_pad_wrapper.sv} \ +waive -rules SELF_ASSIGN -regexp {LHS signal 'inout_io' encountered on the RHS of a continuous assignment statement} -location {prim_pad_wrapper.sv} \ -comment "This implements a keeper termination (it's basically an explicit TRIREG)" -waive -rules DRIVE_STRENGTH -regexp {Drive strength .* encountered on assignment to 'inout_io'} -location {prim_generic_pad_wrapper.sv} \ +waive -rules DRIVE_STRENGTH -regexp {Drive strength .* encountered on assignment to 'inout_io'} -location {prim_pad_wrapper.sv} \ -comment "The pad simulation model uses driving strength attributes to emulate different IO terminations." -waive -rules INPUT_NOT_READ -regexp {Input port 'attr\_i*' is not read from} -location {prim_generic_pad_wrapper.sv} \ +waive -rules INPUT_NOT_READ -regexp {Input port 'attr\_i*' is not read from} -location {prim_pad_wrapper.sv} \ -comment "Some IO attributes may not be implemented." -waive -rules Z_USE -regexp {Constant with 'Z literal value '1'bz' encountered} -location {prim_generic_pad_wrapper.sv} \ +waive -rules Z_USE -regexp {Constant with 'Z literal value '1'bz' encountered} -location {prim_pad_wrapper.sv} \ -comment "This z assignment is correct." -waive -rules PARAM_NOT_USED -regexp {Parameter 'Variant' not used in module 'prim_generic_pad_wrapper'} -location {prim_generic_pad_wrapper.sv} \ +waive -rules PARAM_NOT_USED -regexp {Parameter 'Variant' not used in module 'prim_pad_wrapper'} -location {prim_pad_wrapper.sv} \ -comment "This parameter has been provisioned for later and is currently unused." -waive -rules PARAM_NOT_USED -regexp {Parameter 'ScanRole' not used in module 'prim_generic_pad_wrapper'} -location {prim_generic_pad_wrapper.sv} \ +waive -rules PARAM_NOT_USED -regexp {Parameter 'ScanRole' not used in module 'prim_pad_wrapper'} -location {prim_pad_wrapper.sv} \ -comment "This parameter has been provisioned for later and is currently unused." -waive -rules INPUT_NOT_READ -msg {Input port 'clk_scan_i' is not read from in module 'prim_generic_pad_wrapper'} \ +waive -rules INPUT_NOT_READ -msg {Input port 'clk_scan_i' is not read from in module 'prim_pad_wrapper'} \ -comment "This clock is not read in RTL since it will be connected after synthesis during DFT insertion" +waive -rules {CLOCK_DRIVER CLOCK_USE INV_CLOCK} -regexp {'gen_bidir.out' is (driven here|used for some other purpose|inverted), (and used|and|used) as( a)? clock} \ + -comment "The pad simulation model may also be used for simulating clock pads" +waive -rules {CLOCK_DRIVER} -regexp {'inout_io' is driven here, and used as a clock} + -comment "The pad simulation model may also be used for simulating clock pads" +waive -rules {CLOCK_USE} -regexp {'in_raw_o' is used for some other purpose, and as clock} + -comment "The pad simulation model may also be used for simulating clock pads" 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 997c72c77c..a06461a371 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 @@ -2,11 +2,11 @@ # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 # -# waiver file for prim_generic_ram_1p +# waiver file for prim_ram_1p -waive -rules ALWAYS_SPEC -location {prim_generic_ram_1p.sv} -regexp {Edge triggered block may be more accurately modeled as always_ff} \ +waive -rules ALWAYS_SPEC -location {prim_ram_1p.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'} \ +waive -rules HIER_NET_NOT_READ -regexp {Connected net '(addr|wdata)_i' at prim_ram_1p.sv.* is not read from in module 'prim_ram_1p'} \ -comment "Ascentlint blackboxes very deep RAMs to speed up runtime. This blackboxing causes above lint errors." -waive -rules IFDEF_CODE -location {prim_generic_ram_1p.sv} -regexp {Assignment to 'unused_cfg' contained within `ifndef} \ +waive -rules IFDEF_CODE -location {prim_ram_1p.sv} -regexp {Assignment to 'unused_signals' contained within `ifndef} \ -comment "Declaration of signal and assignment to it are in same `ifndef" diff --git a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_ram_1r1w.waiver b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_ram_1r1w.waiver index 0a717f45d0..c71c28720e 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_ram_1r1w.waiver +++ b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_ram_1r1w.waiver @@ -2,11 +2,11 @@ # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 # -# waiver file for prim_generic_ram_1r1w +# waiver file for prim_ram_1r1w -waive -rules ALWAYS_SPEC -location {prim_generic_ram_1r1w.sv} -regexp {Edge triggered block may be more accurately modeled as always_ff} \ +waive -rules ALWAYS_SPEC -location {prim_ram_1r1w.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_1r1w.sv.* is not read from in module 'prim_generic_ram_1r1w'} \ +waive -rules HIER_NET_NOT_READ -regexp {Connected net '(addr|wdata)_i' at prim_ram_1r1w.sv.* is not read from in module 'prim_ram_1r1w'} \ -comment "Ascentlint blackboxes very deep RAMs to speed up runtime. This blackboxing causes above lint errors." -waive -rules IFDEF_CODE -location {prim_generic_ram_1r1w.sv} -regexp {Assignment to 'unused_cfg' contained within `ifndef} \ +waive -rules IFDEF_CODE -location {prim_ram_1r1w.sv} -regexp {Assignment to 'unused_signals' contained within `ifndef} \ -comment "Declaration of signal and assignment to it are in same `ifndef" 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 c2c00c8c1b..5baf84e9a3 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 @@ -6,4 +6,4 @@ `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'*" +lint_off -rule MULTIDRIVEN -file "*/rtl/prim_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 69590e898d..d3f9dcbedf 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 @@ -2,13 +2,13 @@ # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 # -# waiver file for prim_generic_ram_2p +# waiver file for prim_ram_2p -waive -rules MULTI_PROC_ASSIGN -location {prim_generic_ram_2p.sv} -regexp {Assignment to 'mem' from more than one block} \ +waive -rules MULTI_PROC_ASSIGN -location {prim_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_2p.sv} -regexp {Edge triggered block may be more accurately modeled as always_ff} \ +waive -rules ALWAYS_SPEC -location {prim_ram_2p.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_2p.sv.* is not read from in module 'prim_generic_ram_2p'} \ +waive -rules HIER_NET_NOT_READ -regexp {Connected net '(addr|wdata)_i' at prim_ram_2p.sv.* is not read from in module 'prim_ram_2p'} \ -comment "Ascentlint blackboxes very deep RAMs to speed up runtime. This blackboxing causes above lint errors." -waive -rules IFDEF_CODE -location {prim_generic_ram_2p.sv} -regexp {Assignment to 'unused_cfg' contained within `ifndef} \ +waive -rules IFDEF_CODE -location {prim_ram_2p.sv} -regexp {Assignment to 'unused_cfg' contained within `ifndef} \ -comment "Declaration of signal and assignment to it are in same `ifndef" diff --git a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_rom.waiver b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_rom.waiver index 351694ba18..c6a44351c6 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_rom.waiver +++ b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_rom.waiver @@ -2,7 +2,7 @@ # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 # -# waiver file for prim_generic_rom +# waiver file for prim_rom -waive -rules NOT_DRIVEN -location {prim_generic_rom.sv} -regexp {Signal 'mem' has no driver in module 'prim_generic_rom'} \ +waive -rules NOT_DRIVEN -location {prim_rom.sv} -regexp {Signal 'mem' has no driver in module 'prim_rom'} \ -comment "since this is a ROM, the signal mem has no driver, but it is populated using an initialization file" diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_rst_sync.waiver b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_rst_sync.waiver similarity index 100% rename from vendor/lowrisc_ip/ip/prim/lint/prim_rst_sync.waiver rename to vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_rst_sync.waiver diff --git a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_usb_diff_rx.waiver b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_usb_diff_rx.waiver index 3ae5442bbe..af8022ee4e 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_usb_diff_rx.waiver +++ b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_usb_diff_rx.waiver @@ -2,12 +2,12 @@ # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 # -# waiver file for prim_generic_usb_diff_rx +# waiver file for prim_usb_diff_rx # note that this code is NOT synthesizable and meant for sim only -waive -rules TRI_DRIVER -regexp {'(input_pi|input_ni)' is driven by a tristate driver} -location {prim_generic_usb_diff_rx.sv} \ +waive -rules TRI_DRIVER -regexp {'(input_pi|input_ni)' is driven by a tristate driver} -location {prim_usb_diff_rx.sv} \ -comment "This models the pullup behavior, hence the TRI driver." -waive -rules MULTI_DRIVEN -regexp {'(input_pi|input_ni)' has 2 drivers, also driven at} -location {prim_generic_usb_diff_rx.sv} \ +waive -rules MULTI_DRIVEN -regexp {'(input_pi|input_ni)' has 2 drivers, also driven at} -location {prim_usb_diff_rx.sv} \ -comment "The simulation model has multiple drivers to emulate different IO terminations." -waive -rules DRIVE_STRENGTH -regexp {Drive strength '\(weak0,pull1\)' encountered on assignment to '(input_pi|input_ni)'} -location {prim_generic_usb_diff_rx.sv} \ +waive -rules DRIVE_STRENGTH -regexp {Drive strength '\(weak0,pull1\)' encountered on assignment to '(input_pi|input_ni)'} -location {prim_usb_diff_rx.sv} \ -comment "The simulation model uses driving strength attributes to emulate different IO terminations." diff --git a/vendor/lowrisc_ip/ip/prim_generic/prim_generic.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic.core new file mode 100644 index 0000000000..e7f3a43db6 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic.core @@ -0,0 +1,68 @@ +CAPI=2: +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +name: "lowrisc:prim_generic:all:0.1" +description: "Technology-independent prim library" + +filesets: + files_rtl: + depend: + - lowrisc:prim_generic:prim_pkg + - lowrisc:prim_generic:and2 + - lowrisc:prim_generic:buf + - lowrisc:prim_generic:clock_buf + - lowrisc:prim_generic:clock_div + - lowrisc:prim_generic:clock_gating + - lowrisc:prim_generic:clock_inv + - lowrisc:prim_generic:clock_mux2 + - lowrisc:prim_generic:flop + - lowrisc:prim_generic:flop_2sync + - lowrisc:prim_generic:rst_sync + - lowrisc:prim_generic:flop_en + - lowrisc:prim_generic:pad_attr + - lowrisc:prim_generic:pad_wrapper + - lowrisc:prim_generic:ram_1p + - lowrisc:prim_generic:ram_1r1w + - lowrisc:prim_generic:ram_2p + - lowrisc:prim_generic:rom + - lowrisc:prim_generic:usb_diff_rx + - lowrisc:prim_generic:xnor2 + - lowrisc:prim_generic:xor2 + - lowrisc:prim_generic:flop_no_rst +# Note that flash is a macro that depends on IPs, so they are not +# included here. They must be brought in explicitly. +# - lowrisc:prim_generic:flash + +mapping: + "lowrisc:prim:prim_pkg" : "lowrisc:prim_generic:prim_pkg" + "lowrisc:prim:and2" : "lowrisc:prim_generic:and2" + "lowrisc:prim:buf" : "lowrisc:prim_generic:buf" + "lowrisc:prim:clock_buf" : "lowrisc:prim_generic:clock_buf" + "lowrisc:prim:clock_div" : "lowrisc:prim_generic:clock_div" + "lowrisc:prim:clock_gating" : "lowrisc:prim_generic:clock_gating" + "lowrisc:prim:clock_inv" : "lowrisc:prim_generic:clock_inv" + "lowrisc:prim:clock_mux2" : "lowrisc:prim_generic:clock_mux2" + "lowrisc:prim:flop" : "lowrisc:prim_generic:flop" + "lowrisc:prim:flop_2sync" : "lowrisc:prim_generic:flop_2sync" + "lowrisc:prim:rst_sync" : "lowrisc:prim_generic:rst_sync" + "lowrisc:prim:flop_en" : "lowrisc:prim_generic:flop_en" + "lowrisc:prim:pad_attr" : "lowrisc:prim_generic:pad_attr" + "lowrisc:prim:pad_wrapper" : "lowrisc:prim_generic:pad_wrapper" + "lowrisc:prim:ram_1p" : "lowrisc:prim_generic:ram_1p" + "lowrisc:prim:ram_1r1w" : "lowrisc:prim_generic:ram_1r1w" + "lowrisc:prim:ram_2p" : "lowrisc:prim_generic:ram_2p" + "lowrisc:prim:rom" : "lowrisc:prim_generic:rom" + "lowrisc:prim:usb_diff_rx" : "lowrisc:prim_generic:usb_diff_rx" + "lowrisc:prim:xnor2" : "lowrisc:prim_generic:xnor2" + "lowrisc:prim:xor2" : "lowrisc:prim_generic:xor2" + "lowrisc:prim:flop_no_rst" : "lowrisc:prim_generic:flop_no_rst" + # Flash is a good canditate to be removed from the prims and become a macro like OTP. + # TODO(#27042): When this is done, it should be removed from this mapping. + "lowrisc:prim:flash": "lowrisc:prim_generic:flash" + +targets: + default: + filesets: + - files_rtl diff --git a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_and2.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_and2.core index 35bf0a05b8..e18e8b48a2 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_and2.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_and2.core @@ -5,10 +5,13 @@ CAPI=2: name: "lowrisc:prim_generic:and2" description: "Generic 2-input and" +virtual: + - lowrisc:prim:and2 + filesets: files_rtl: files: - - rtl/prim_generic_and2.sv + - rtl/prim_and2.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_buf.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_buf.core index 1e9380006d..9db9568d25 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_buf.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_buf.core @@ -5,10 +5,13 @@ CAPI=2: name: "lowrisc:prim_generic:buf" description: "buffer" +virtual: + - lowrisc:prim:buf + filesets: files_rtl: files: - - rtl/prim_generic_buf.sv + - rtl/prim_buf.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_clock_buf.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_clock_buf.core index a0527957ea..d11883d9ea 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_clock_buf.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_clock_buf.core @@ -5,10 +5,13 @@ CAPI=2: name: "lowrisc:prim_generic:clock_buf" description: "clock buffer" +virtual: + - lowrisc:prim:clock_buf + filesets: files_rtl: files: - - rtl/prim_generic_clock_buf.sv + - rtl/prim_clock_buf.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_clock_div.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_clock_div.core index 806654072b..0c33b7398f 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_clock_div.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_clock_div.core @@ -5,15 +5,18 @@ CAPI=2: name: "lowrisc:prim_generic:clock_div" description: "Generic clock divide" +virtual: + - lowrisc:prim:clock_div + filesets: files_rtl: depend: - - lowrisc:prim:prim_pkg + - lowrisc:prim:assert - lowrisc:prim:flop - lowrisc:prim:clock_inv - lowrisc:prim:clock_buf files: - - rtl/prim_generic_clock_div.sv + - rtl/prim_clock_div.sv file_type: systemVerilogSource files_ascentlint_waiver: diff --git a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_clock_gating.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_clock_gating.core index c1e878180b..9d79c9d540 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_clock_gating.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_clock_gating.core @@ -5,10 +5,13 @@ CAPI=2: name: "lowrisc:prim_generic:clock_gating" description: "prim" +virtual: + - lowrisc:prim:clock_gating + filesets: files_rtl: files: - - rtl/prim_generic_clock_gating.sv + - rtl/prim_clock_gating.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_clock_inv.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_clock_inv.core index 4f48b07a98..399b220bb6 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_clock_inv.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_clock_inv.core @@ -5,13 +5,16 @@ CAPI=2: name: "lowrisc:prim_generic:clock_inv" description: "Clock inverter with scanmode bypass mux" +virtual: + - lowrisc:prim:clock_inv + filesets: files_rtl: depend: - lowrisc:prim:assert - lowrisc:prim:clock_mux2 files: - - rtl/prim_generic_clock_inv.sv + - rtl/prim_clock_inv.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_clock_mux2.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_clock_mux2.core index f4f343d498..de600aea58 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_clock_mux2.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_clock_mux2.core @@ -5,12 +5,15 @@ CAPI=2: name: "lowrisc:prim_generic:clock_mux2" description: "two-input clock multiplexer primitive" +virtual: + - lowrisc:prim:clock_mux2 + filesets: files_rtl: depend: - lowrisc:prim:assert files: - - rtl/prim_generic_clock_mux2.sv + - rtl/prim_clock_mux2.sv file_type: systemVerilogSource files_verilator_waiver: 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 736caad594..5a8cd51d1b 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flash.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flash.core @@ -5,18 +5,21 @@ CAPI=2: name: "lowrisc:prim_generic:flash" description: "prim" +virtual: + - lowrisc:prim:flash + filesets: files_rtl: depend: - - lowrisc:ip:tlul + - lowrisc:tlul:headers - lowrisc:prim:ram_1p - "fileset_partner ? (partner:systems:ast_pkg)" - "!fileset_partner ? (lowrisc:systems:ast_pkg)" - - lowrisc:ip_interfaces:flash_ctrl_pkg - - lowrisc:ip:flash_ctrl_prim_reg_top + - lowrisc:virtual_ip:flash_ctrl_top_specific_pkg + - lowrisc:virtual_ip:flash_ctrl_prim_reg_top files: - rtl/prim_generic_flash_bank.sv - - rtl/prim_generic_flash.sv + - rtl/prim_flash.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flop.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flop.core index c66701bc1a..e899f79042 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flop.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flop.core @@ -5,10 +5,13 @@ CAPI=2: name: "lowrisc:prim_generic:flop" description: "generic flop" +virtual: + - lowrisc:prim:flop + filesets: files_rtl: files: - - rtl/prim_generic_flop.sv + - rtl/prim_flop.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim/prim_flop_2sync.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flop_2sync.core similarity index 75% rename from vendor/lowrisc_ip/ip/prim/prim_flop_2sync.core rename to vendor/lowrisc_ip/ip/prim_generic/prim_generic_flop_2sync.core index dc1fdb6fb6..a67519a869 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_flop_2sync.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flop_2sync.core @@ -3,15 +3,17 @@ CAPI=2: # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -name: "lowrisc:prim:flop_2sync" -description: "Primitive synchronizer" +name: "lowrisc:prim_generic:flop_2sync" +description: "Generic implementation of a flop-based synchronizer" +virtual: + - lowrisc:prim:flop_2sync + filesets: files_rtl: depend: - - lowrisc:prim:prim_pkg - # Needed because the generic prim_flop_2sync has a - # dependency on prim:flop. + # Needed because the generic impl instantiates prim_flop. - lowrisc:prim:flop + # Needed for DV. - lowrisc:prim:cdc_rand_delay files: - rtl/prim_flop_2sync.sv @@ -21,14 +23,13 @@ filesets: depend: # common waivers - lowrisc:lint:common - file_type: vlt files_ascentlint_waiver: depend: # common waivers - lowrisc:lint:common files: - - lint/prim_flop_2sync.waiver + - lint/prim_generic_flop_2sync.waiver file_type: waiver files_veriblelint_waiver: diff --git a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flop_en.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flop_en.core index 8e39916ee5..e1c70ecfc6 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flop_en.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flop_en.core @@ -5,12 +5,15 @@ CAPI=2: name: "lowrisc:prim_generic:flop_en" description: "generic enable flop" +virtual: + - lowrisc:prim:flop_en + filesets: files_rtl: depend: - lowrisc:prim:sec_anchor files: - - rtl/prim_generic_flop_en.sv + - rtl/prim_flop_en.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim/prim_otp_pkg.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flop_no_rst.core similarity index 66% rename from vendor/lowrisc_ip/ip/prim/prim_otp_pkg.core rename to vendor/lowrisc_ip/ip/prim_generic/prim_generic_flop_no_rst.core index 58c2630975..fc29431a66 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_otp_pkg.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flop_no_rst.core @@ -3,12 +3,15 @@ CAPI=2: # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -name: "lowrisc:prim:otp_pkg:0.1" -description: "Package with common interface definitions for OTP primitives." +name: "lowrisc:prim_generic:flop_no_rst" +description: "generic flop without a reset" +virtual: + - lowrisc:prim:flop_no_rst + filesets: files_rtl: files: - - rtl/prim_otp_pkg.sv + - rtl/prim_flop_no_rst.sv file_type: systemVerilogSource files_verilator_waiver: @@ -27,20 +30,9 @@ filesets: - lowrisc:lint:common targets: - default: &default_target + default: 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: - verilator: - mode: lint-only - verilator_options: - - "-Wall" diff --git a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_otp.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_otp.core deleted file mode 100644 index db270f0743..0000000000 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_otp.core +++ /dev/null @@ -1,44 +0,0 @@ -CAPI=2: -# Copyright lowRISC contributors (OpenTitan project). -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 - -name: "lowrisc:prim_generic:otp" -description: "Technology-independent One-Time Programmable (OTP) memory emulation" -filesets: - files_rtl: - depend: - - lowrisc:prim:all - - lowrisc:prim:util - - lowrisc:prim:ram_1p_adv - - "fileset_partner ? (partner:systems:ast_pkg)" - - "!fileset_partner ? (lowrisc:systems:ast_pkg)" - - lowrisc:prim:otp_pkg - - lowrisc:ip:otp_ctrl_prim_reg_top - files: - - rtl/prim_generic_otp.sv - file_type: systemVerilogSource - - files_verilator_waiver: - depend: - # common waivers - - lowrisc:lint:common - files: - - lint/prim_generic_otp.vlt - file_type: vlt - - files_ascentlint_waiver: - depend: - # common waivers - - lowrisc:lint:common - files: - - lint/prim_generic_otp.waiver - file_type: waiver - - -targets: - default: - filesets: - - tool_verilator ? (files_verilator_waiver) - - tool_ascentlint ? (files_ascentlint_waiver) - - files_rtl diff --git a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_pad_attr.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_pad_attr.core index 0629996c26..c80c59e00d 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_pad_attr.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_pad_attr.core @@ -5,13 +5,16 @@ CAPI=2: name: "lowrisc:prim_generic:pad_attr" description: "Technology-independent pad attribute WARL module (for sim only!)" +virtual: + - lowrisc:prim:pad_attr + filesets: files_rtl: depend: - lowrisc:prim:assert - lowrisc:prim:pad_wrapper_pkg files: - - rtl/prim_generic_pad_attr.sv + - rtl/prim_pad_attr.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_pad_wrapper.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_pad_wrapper.core index ab7f0a1c73..764cd45f89 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_pad_wrapper.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_pad_wrapper.core @@ -5,13 +5,16 @@ CAPI=2: name: "lowrisc:prim_generic:pad_wrapper" description: "Technology-independent pad wrapper implementation (for sim only!)" +virtual: + - lowrisc:prim:pad_wrapper + filesets: files_rtl: depend: - lowrisc:prim:assert - lowrisc:prim:pad_wrapper_pkg files: - - rtl/prim_generic_pad_wrapper.sv + - rtl/prim_pad_wrapper.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim/prim_clock_div.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_pkg.core similarity index 66% rename from vendor/lowrisc_ip/ip/prim/prim_clock_div.core rename to vendor/lowrisc_ip/ip/prim_generic/prim_generic_pkg.core index 954f08d185..4e2c0b454f 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_clock_div.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_pkg.core @@ -3,13 +3,16 @@ CAPI=2: # 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" +name: "lowrisc:prim_generic:prim_pkg" +description: "Generic package" +virtual: + - lowrisc:prim:prim_pkg + filesets: - primgen_dep: - depend: - - lowrisc:prim:prim_pkg - - lowrisc:prim:primgen + files_rtl: + files: + - rtl/prim_pkg.sv + file_type: systemVerilogSource files_verilator_waiver: depend: @@ -20,27 +23,16 @@ filesets: depend: # common waivers - lowrisc:lint:common - files: - - lint/prim_clock_div.waiver - file_type: waiver files_veriblelint_waiver: depend: # common waivers - lowrisc:lint:common -generate: - impl: - generator: primgen - parameters: - prim_name: clock_div - targets: default: filesets: - tool_verilator ? (files_verilator_waiver) - tool_ascentlint ? (files_ascentlint_waiver) - tool_veriblelint ? (files_veriblelint_waiver) - - primgen_dep - generate: - - impl + - files_rtl diff --git a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_ram_1p.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_ram_1p.core index ea3848b121..d02e5303c5 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_ram_1p.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_ram_1p.core @@ -5,14 +5,17 @@ CAPI=2: name: "lowrisc:prim_generic:ram_1p" description: "Single port RAM" +virtual: + - lowrisc:prim:ram_1p + filesets: files_rtl: depend: - lowrisc:prim:assert - - lowrisc:prim:ram_1p_pkg + - lowrisc:prim_generic:ram_1p_pkg - lowrisc:prim:util_memload files: - - rtl/prim_generic_ram_1p.sv + - rtl/prim_ram_1p.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim/prim_ram_1p_pkg.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_ram_1p_pkg.core similarity index 81% rename from vendor/lowrisc_ip/ip/prim/prim_ram_1p_pkg.core rename to vendor/lowrisc_ip/ip/prim_generic/prim_generic_ram_1p_pkg.core index 8f66fbb03f..1e38974cb3 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_ram_1p_pkg.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_ram_1p_pkg.core @@ -3,8 +3,11 @@ CAPI=2: # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -name: "lowrisc:prim:ram_1p_pkg" +name: "lowrisc:prim_generic:ram_1p_pkg" description: "Ram 1p package" +virtual: + - "lowrisc:prim:ram_1p_pkg" + filesets: files_rtl: files: diff --git a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_ram_1r1w.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_ram_1r1w.core index 2cc6529619..e2dd35e8d6 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_ram_1r1w.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_ram_1r1w.core @@ -5,14 +5,17 @@ CAPI=2: name: "lowrisc:prim_generic:ram_1r1w" description: "prim" +virtual: + - lowrisc:prim:ram_1r1w + filesets: files_rtl: depend: - lowrisc:prim:assert - - lowrisc:prim:ram_2p_pkg + - lowrisc:prim_generic:ram_2p_pkg - lowrisc:prim:util_memload files: - - rtl/prim_generic_ram_1r1w.sv + - rtl/prim_ram_1r1w.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_ram_2p.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_ram_2p.core index 13c411459d..64f2b6ea2e 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_ram_2p.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_ram_2p.core @@ -5,14 +5,17 @@ CAPI=2: name: "lowrisc:prim_generic:ram_2p" description: "prim" +virtual: + - lowrisc:prim:ram_2p + filesets: files_rtl: depend: - lowrisc:prim:assert - - lowrisc:prim:ram_2p_pkg + - lowrisc:prim_generic:ram_2p_pkg - lowrisc:prim:util_memload files: - - rtl/prim_generic_ram_2p.sv + - rtl/prim_ram_2p.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim/prim_ram_2p_pkg.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_ram_2p_pkg.core similarity index 81% rename from vendor/lowrisc_ip/ip/prim/prim_ram_2p_pkg.core rename to vendor/lowrisc_ip/ip/prim_generic/prim_generic_ram_2p_pkg.core index 074bc6c382..17f56248d9 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_ram_2p_pkg.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_ram_2p_pkg.core @@ -3,8 +3,11 @@ CAPI=2: # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -name: "lowrisc:prim:ram_2p_pkg" +name: "lowrisc:prim_generic:ram_2p_pkg" description: "Ram 2p package" +virtual: + - "lowrisc:prim:ram_2p_pkg" + filesets: files_rtl: files: diff --git a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_rom.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_rom.core index 5bf3b6ce38..46afbcae0b 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_rom.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_rom.core @@ -5,14 +5,17 @@ CAPI=2: name: "lowrisc:prim_generic:rom" description: "Technology-independent Read-Only Memory (ROM) implementation" +virtual: + - lowrisc:prim:rom + filesets: files_rtl: depend: - lowrisc:prim:assert - - lowrisc:prim:rom_pkg + - lowrisc:prim_generic:rom_pkg - lowrisc:prim:util_memload files: - - rtl/prim_generic_rom.sv + - rtl/prim_rom.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim/prim_rom_pkg.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_rom_pkg.core similarity index 82% rename from vendor/lowrisc_ip/ip/prim/prim_rom_pkg.core rename to vendor/lowrisc_ip/ip/prim_generic/prim_generic_rom_pkg.core index f8a827cecb..35fac0142e 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_rom_pkg.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_rom_pkg.core @@ -3,8 +3,11 @@ CAPI=2: # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -name: "lowrisc:prim:rom_pkg" +name: "lowrisc:prim_generic:rom_pkg" description: "Rom package" +virtual: + - "lowrisc:prim:rom_pkg" + filesets: files_rtl: files: diff --git a/vendor/lowrisc_ip/ip/prim/prim_rst_sync.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_rst_sync.core similarity index 76% rename from vendor/lowrisc_ip/ip/prim/prim_rst_sync.core rename to vendor/lowrisc_ip/ip/prim_generic/prim_generic_rst_sync.core index 9657f87716..9952382b41 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_rst_sync.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_rst_sync.core @@ -3,17 +3,17 @@ CAPI=2: # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -name: "lowrisc:prim:rst_sync" -description: "Primitive Reset synchronizer" +name: "lowrisc:prim_generic:rst_sync" +description: "Generic implementation of a reset synchronizer" +virtual: + - lowrisc:prim:rst_sync + filesets: files_rtl: depend: - - lowrisc:prim:prim_pkg - # Needed because the generic prim_flop_2sync has a - # dependency on prim:flop. + - lowrisc:prim:clock_mux2 - lowrisc:prim:flop_2sync - lowrisc:prim:mubi - - lowrisc:prim:cdc_rand_delay files: - rtl/prim_rst_sync.sv file_type: systemVerilogSource @@ -29,7 +29,7 @@ filesets: # common waivers - lowrisc:lint:common files: - - lint/prim_rst_sync.waiver + - lint/prim_generic_rst_sync.waiver file_type: waiver files_veriblelint_waiver: 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 index d1c34a6a04..f77bdeee10 100644 --- 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 @@ -5,10 +5,13 @@ CAPI=2: name: "lowrisc:prim_generic:usb_diff_rx" description: "Generic differential USB receiver for emulation purposes" +virtual: + - lowrisc:prim:usb_diff_rx + filesets: files_rtl: files: - - rtl/prim_generic_usb_diff_rx.sv + - rtl/prim_usb_diff_rx.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_xnor2.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_xnor2.core index 24e3a125e3..137af01838 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_xnor2.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_xnor2.core @@ -5,10 +5,13 @@ CAPI=2: name: "lowrisc:prim_generic:xnor2" description: "Generic 2-input xnor" +virtual: + - lowrisc:prim:xnor2 + filesets: files_rtl: files: - - rtl/prim_generic_xnor2.sv + - rtl/prim_xnor2.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_xor2.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_xor2.core index e3cf88c20c..b77448326d 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_xor2.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_xor2.core @@ -5,10 +5,13 @@ CAPI=2: name: "lowrisc:prim_generic:xor2" description: "Generic 2-input xor" +virtual: + - lowrisc:prim:xor2 + filesets: files_rtl: files: - - rtl/prim_generic_xor2.sv + - rtl/prim_xor2.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_and2.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_and2.sv similarity index 93% rename from vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_and2.sv rename to vendor/lowrisc_ip/ip/prim_generic/rtl/prim_and2.sv index df1b65fa3b..6a9cca480b 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_and2.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_and2.sv @@ -4,7 +4,7 @@ `include "prim_assert.sv" -module prim_generic_and2 #( +module prim_and2 #( parameter int Width = 1 ) ( input [Width-1:0] in0_i, diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_buf.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_buf.sv similarity index 93% rename from vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_buf.sv rename to vendor/lowrisc_ip/ip/prim_generic/rtl/prim_buf.sv index ede99f1d64..82517a7cf5 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_buf.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_buf.sv @@ -4,7 +4,7 @@ `include "prim_assert.sv" -module prim_generic_buf #( +module prim_buf #( parameter int Width = 1 ) ( input [Width-1:0] in_i, diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_buf.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_clock_buf.sv similarity index 90% rename from vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_buf.sv rename to vendor/lowrisc_ip/ip/prim_generic/rtl/prim_clock_buf.sv index d660aab686..ab39001b55 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_buf.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_clock_buf.sv @@ -4,7 +4,7 @@ `include "prim_assert.sv" -module prim_generic_clock_buf #( +module prim_clock_buf #( // Turning off these verilator lints because keeping these parameters makes it consistent with // the IP in hw/ip/prim_xilinx/rtl/ . /* verilator lint_off UNUSED */ @@ -20,4 +20,4 @@ module prim_generic_clock_buf #( assign inv = ~clk_i; assign clk_o = ~inv; -endmodule // prim_generic_clock_buf +endmodule // prim_clock_buf diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_div.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_clock_div.sv similarity index 98% rename from vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_div.sv rename to vendor/lowrisc_ip/ip/prim_generic/rtl/prim_clock_div.sv index 798aa35ec0..ae9fd2c78f 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_div.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_clock_div.sv @@ -4,7 +4,7 @@ `include "prim_assert.sv" -module prim_generic_clock_div #( +module prim_clock_div #( parameter int unsigned Divisor = 2, parameter logic ResetValue = 0 ) ( diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_gating.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_clock_gating.sv similarity index 95% rename from vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_gating.sv rename to vendor/lowrisc_ip/ip/prim_generic/rtl/prim_clock_gating.sv index 6f80f6e89b..dc092ea56f 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_gating.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_clock_gating.sv @@ -7,7 +7,7 @@ // The logic assumes that en_i is synchronized (so the instantiation site might need to put a // synchronizer before en_i). -module prim_generic_clock_gating #( +module prim_clock_gating #( parameter bit NoFpgaGate = 1'b0, // this parameter has no function in generic parameter bit FpgaBufGlobal = 1'b1 // this parameter has no function in generic ) ( diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_inv.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_clock_inv.sv similarity index 92% rename from vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_inv.sv rename to vendor/lowrisc_ip/ip/prim_generic/rtl/prim_clock_inv.sv index 2f56d3287f..2867dfb881 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_inv.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_clock_inv.sv @@ -5,7 +5,7 @@ // Clock inverter // Varies on the process -module prim_generic_clock_inv #( +module prim_clock_inv #( parameter bit HasScanMode = 1'b1, parameter bit NoFpgaBufG = 1'b0 // only used in FPGA case ) ( @@ -29,4 +29,4 @@ module prim_generic_clock_inv #( assign clk_no = ~clk_i; end -endmodule : prim_generic_clock_inv +endmodule : prim_clock_inv diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_mux2.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_clock_mux2.sv similarity index 58% rename from vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_mux2.sv rename to vendor/lowrisc_ip/ip/prim_generic/rtl/prim_clock_mux2.sv index 85418e0da2..022288f197 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_mux2.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_clock_mux2.sv @@ -4,7 +4,7 @@ `include "prim_assert.sv" -module prim_generic_clock_mux2 #( +module prim_clock_mux2 #( parameter bit NoFpgaBufG = 1'b0 // this parameter serves no function in the generic model ) ( input clk0_i, @@ -16,10 +16,16 @@ module prim_generic_clock_mux2 #( // We model the mux with logic operations for GTECH runs. assign clk_o = (sel_i & clk1_i) | (~sel_i & clk0_i); - // make sure sel is never X (including during reset) - // need to use ##1 as this could break with inverted clocks that - // start with a rising edge at the beginning of the simulation. + // Make sure sel is never X. + // + // So that this can be a clocked assertion, we check it on the posedge of each input clock. + // + // This is disabled for FPV runs (because some formal tools don't have a concept of "X"). The + // assertion comes after a ##1 to allow inverted clocks that start with a rising edge at the + // beginning of the simulation. +`ifndef FPV_ON `ASSERT(selKnown0, ##1 !$isunknown(sel_i), clk0_i, 0) `ASSERT(selKnown1, ##1 !$isunknown(sel_i), clk1_i, 0) +`endif -endmodule : prim_generic_clock_mux2 +endmodule : prim_clock_mux2 diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_flash.sv similarity index 93% rename from vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash.sv rename to vendor/lowrisc_ip/ip/prim_generic/rtl/prim_flash.sv index 2349dd8f2e..ad6dd0e853 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_flash.sv @@ -5,7 +5,7 @@ // Overall flash wrapper // -module prim_generic_flash #( +module prim_flash #( parameter int NumBanks = 2, // number of banks parameter int InfosPerBank = 1, // info pages per bank parameter int InfoTypes = 1, // different info types @@ -52,8 +52,8 @@ module prim_generic_flash #( 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; + assign prog_type_avail_o[flash_ctrl_top_specific_pkg::FlashProgNormal] = 1'b1; + assign prog_type_avail_o[flash_ctrl_top_specific_pkg::FlashProgRepair] = 1'b1; for (genvar bank = 0; bank < NumBanks; bank++) begin : gen_prim_flash_banks @@ -142,5 +142,7 @@ module prim_generic_flash #( assign unused_obs = |obs_ctrl_i; assign fla_obs_o = '0; + `ASSERT_PRIM_REG_WE_ONEHOT_ERROR_TRIGGER_ALERT(PrimRegWeOnehotCheck_A, + u_reg_top, flash_ctrl.alert_tx_o[3]) -endmodule // prim_generic_flash +endmodule // prim_flash diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flop.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_flop.sv similarity index 95% rename from vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flop.sv rename to vendor/lowrisc_ip/ip/prim_generic/rtl/prim_flop.sv index 426b44e042..d2357d2725 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flop.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_flop.sv @@ -4,7 +4,7 @@ `include "prim_assert.sv" -module prim_generic_flop #( +module prim_flop #( parameter int Width = 1, parameter logic [Width-1:0] ResetValue = 0 ) ( diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_flop_2sync.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_flop_2sync.sv similarity index 89% rename from vendor/lowrisc_ip/ip/prim/rtl/prim_flop_2sync.sv rename to vendor/lowrisc_ip/ip/prim_generic/rtl/prim_flop_2sync.sv index 5b46928624..8f7864ee04 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_flop_2sync.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_flop_2sync.sv @@ -2,9 +2,7 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 // -// Generic double-synchronizer flop -// This may need to be moved to prim_generic if libraries have a specific cell -// for synchronization +// Double-flop-based synchronizer module prim_flop_2sync #( parameter int Width = 16, diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flop_en.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_flop_en.sv similarity index 96% rename from vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flop_en.sv rename to vendor/lowrisc_ip/ip/prim_generic/rtl/prim_flop_en.sv index 94ca795fca..aaea0ea7a1 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flop_en.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_flop_en.sv @@ -4,7 +4,7 @@ `include "prim_assert.sv" -module prim_generic_flop_en #( +module prim_flop_en #( parameter int Width = 1, parameter bit EnSecBuf = 0, parameter logic [Width-1:0] ResetValue = 0 diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_flop_no_rst.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_flop_no_rst.sv new file mode 100644 index 0000000000..6c8ed68de3 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_flop_no_rst.sv @@ -0,0 +1,19 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`include "prim_assert.sv" + +module prim_flop_no_rst #( + parameter int Width = 1 +) ( + input clk_i, + input [Width-1:0] d_i, + output logic [Width-1:0] q_o +); + + always_ff @(posedge clk_i) begin + q_o <= d_i; + end + +endmodule 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 index 566a2e8fa2..5ecb7ec2c6 100644 --- 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 @@ -18,28 +18,28 @@ module prim_generic_flash_bank #( 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, + 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 erase_suspend_req_i, - input he_i, - input [AddrW-1:0] addr_i, - input flash_ctrl_pkg::flash_part_e part_i, - input [InfoTypesWidth-1:0] info_sel_i, - input [DataWidth-1:0] prog_data_i, - output logic ack_o, - output logic done_o, - output logic [DataWidth-1:0] rd_data_o, - input init_i, - output logic init_busy_o, - input flash_power_ready_h_i, - input flash_power_down_h_i + input flash_ctrl_top_specific_pkg::flash_prog_e prog_type_i, + input pg_erase_i, + input bk_erase_i, + input erase_suspend_req_i, + input he_i, + input [AddrW-1:0] addr_i, + input flash_ctrl_top_specific_pkg::flash_part_e part_i, + input [InfoTypesWidth-1:0] info_sel_i, + input [DataWidth-1:0] prog_data_i, + output logic ack_o, + output logic done_o, + output logic [DataWidth-1:0] rd_data_o, + input init_i, + output logic init_busy_o, + input flash_power_ready_h_i, + input flash_power_down_h_i ); `ifdef SYNTHESIS @@ -90,33 +90,33 @@ module prim_generic_flash_bank #( 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; - logic mem_bk_erase; - logic [InfoTypesWidth-1:0] mem_info_sel; + 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_top_specific_pkg::flash_part_e mem_part; + logic mem_bk_erase; + logic [InfoTypesWidth-1:0] mem_info_sel; // 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 [InfoTypesWidth-1:0] info_sel; - logic [DataWidth-1:0] prog_data; + logic rd; + logic prog; + logic prog_last; + flash_ctrl_top_specific_pkg::flash_prog_e prog_type; + logic pg_erase; + logic bk_erase; + logic [AddrW-1:0] addr; + flash_ctrl_top_specific_pkg::flash_part_e part; + logic [InfoTypesWidth-1:0] info_sel; + logic [DataWidth-1:0] prog_data; } cmd_payload_t; cmd_payload_t cmd_d, cmd_q; @@ -153,9 +153,10 @@ module prim_generic_flash_bank #( assign ack_o = ack & !init_busy_o; prim_fifo_sync #( - .Width ($bits(cmd_payload_t)), - .Pass (0), - .Depth (2) + .Width ($bits(cmd_payload_t)), + .Pass (0), + .Depth (2), + .NeverClears (1'b1) ) u_cmd_fifo ( .clk_i, .rst_ni, @@ -214,12 +215,12 @@ module prim_generic_flash_bank #( end end - // latch partiton being read since the command fifo is popped early - flash_ctrl_pkg::flash_part_e rd_part_q; + // latch partition being read since the command fifo is popped early + flash_ctrl_top_specific_pkg::flash_part_e rd_part_q; logic [InfoTypesWidth-1:0] info_sel_q; always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin - rd_part_q <= flash_ctrl_pkg::FlashPartData; + rd_part_q <= flash_ctrl_top_specific_pkg::FlashPartData; info_sel_q <= '0; end else if (mem_rd_d) begin rd_part_q <= cmd_q.part; @@ -276,7 +277,7 @@ module prim_generic_flash_bank #( end end - // Emulate flash initilaization with a wait timer + // Emulate flash initialization with a wait timer StInit: begin init_busy_o = 1'h1; if (index_cnt < InitCycles) begin @@ -396,11 +397,11 @@ module prim_generic_flash_bank #( logic [DataWidth-1:0] rd_data_main, rd_data_info; logic [InfoTypes-1:0][DataWidth-1:0] rd_nom_data_info; - // data memory is requested whenver it's a transaction targetted at the data partition + // data memory is requested whenever it's a transaction targetted at the data partition // OR if it's a bank erase logic data_mem_req; assign data_mem_req = mem_req & - (mem_part == flash_ctrl_pkg::FlashPartData | + (mem_part == flash_ctrl_top_specific_pkg::FlashPartData | mem_bk_erase); prim_ram_1p #( @@ -409,13 +410,15 @@ module prim_generic_flash_bank #( .DataBitsPerMask(DataWidth) ) u_mem ( .clk_i, + .rst_ni, .req_i (data_mem_req), .write_i (mem_wr), .addr_i (mem_addr), .wdata_i (mem_wdata), .wmask_i ({DataWidth{1'b1}}), .rdata_o (rd_data_main), - .cfg_i ('0) + .cfg_i ('0), + .cfg_rsp_o() ); for (genvar info_type = 0; info_type < InfoTypes; info_type++) begin : gen_info_types @@ -424,7 +427,7 @@ module prim_generic_flash_bank #( // if NOT bank erase, then only the selected info partition is erased logic info_mem_req; assign info_mem_req = mem_req & - (mem_part == flash_ctrl_pkg::FlashPartInfo) & + (mem_part == flash_ctrl_top_specific_pkg::FlashPartInfo) & ((mem_info_sel == info_type) | mem_bk_erase); prim_ram_1p #( @@ -433,23 +436,27 @@ module prim_generic_flash_bank #( .DataBitsPerMask(DataWidth) ) u_info_mem ( .clk_i, + .rst_ni, .req_i (info_mem_req), .write_i (mem_wr), .addr_i (mem_addr[0 +: InfoAddrW]), .wdata_i (mem_wdata), .wmask_i ({DataWidth{1'b1}}), .rdata_o (rd_nom_data_info[info_type]), - .cfg_i ('0) + .cfg_i ('0), + .cfg_rsp_o() ); end assign rd_data_info = rd_nom_data_info[info_sel_q]; - assign rd_data_d = rd_part_q == flash_ctrl_pkg::FlashPartData ? rd_data_main : rd_data_info; + assign rd_data_d = rd_part_q == flash_ctrl_top_specific_pkg::FlashPartData + ? rd_data_main + : rd_data_info; - flash_ctrl_pkg::flash_prog_e unused_prog_type; + flash_ctrl_top_specific_pkg::flash_prog_e unused_prog_type; assign unused_prog_type = cmd_q.prog_type; logic unused_he; assign unused_he = he_i; -endmodule // prim_generic_flash +endmodule // prim_generic_flash_bank 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 deleted file mode 100644 index 5fe826d660..0000000000 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_otp.sv +++ /dev/null @@ -1,434 +0,0 @@ -// Copyright lowRISC contributors (OpenTitan project). -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -module prim_generic_otp - import prim_otp_pkg::*; -#( - // Native OTP word size. This determines the size_i granule. - parameter int Width = 16, - parameter int Depth = 1024, - // This determines the maximum number of native words that - // can be transferred accross the interface in one cycle. - parameter int SizeWidth = 2, - // Width of the power sequencing signal. - parameter int PwrSeqWidth = 2, - // Width of vendor-specific test control signal - parameter int TestCtrlWidth = 32, - parameter int TestStatusWidth = 32, - parameter int TestVectWidth = 8, - // 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 = "", - // Vendor test partition offset and size (both in bytes) - parameter int VendorTestOffset = 0, - parameter int VendorTestSize = 0 -) ( - input clk_i, - input rst_ni, - // Observability - input ast_pkg::ast_obs_ctrl_t obs_ctrl_i, - output logic [7:0] otp_obs_o, - // Macro-specific power sequencing signals to/from AST - output logic [PwrSeqWidth-1:0] pwr_seq_o, - input [PwrSeqWidth-1:0] pwr_seq_h_i, - // External programming voltage - inout wire ext_voltage_io, - // Test interfaces - input [TestCtrlWidth-1:0] test_ctrl_i, - output logic [TestStatusWidth-1:0] test_status_o, - output logic [TestVectWidth-1:0] test_vect_o, - input tlul_pkg::tl_h2d_t test_tl_i, - output tlul_pkg::tl_d2h_t test_tl_o, - // Other DFT signals - input prim_mubi_pkg::mubi4_t scanmode_i, // Scan Mode input - input scan_en_i, // Scan Shift - input scan_rst_ni, // Scan Reset - // Alert indication (to be connected to alert sender in the instantiating IP) - output logic fatal_alert_o, - output logic recov_alert_o, - // Ready valid handshake for read/write command - output logic ready_o, - input valid_i, - // #(Native words)-1, e.g. size == 0 for 1 native word. - input [SizeWidth-1:0] size_i, - // See prim_otp_pkg for the command encoding. - input cmd_e cmd_i, - 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 err_e err_o -); - - import prim_mubi_pkg::MuBi4False; - - // This is only restricted by the supported ECC poly further - // below, and is straightforward to extend, if needed. - localparam int EccWidth = 6; - `ASSERT_INIT(SecDecWidth_A, Width == 16) - - // 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; - - logic unused_obs; - assign unused_obs = |obs_ctrl_i; - assign otp_obs_o = '0; - - wire unused_ext_voltage; - assign unused_ext_voltage = ext_voltage_io; - logic unused_test_ctrl_i; - assign unused_test_ctrl_i = ^test_ctrl_i; - - logic unused_scan; - assign unused_scan = ^{scanmode_i, scan_en_i, scan_rst_ni}; - - logic intg_err, fsm_err; - assign fatal_alert_o = intg_err || fsm_err; - assign recov_alert_o = 1'b0; - - assign test_vect_o = '0; - assign test_status_o = '0; - - //////////////////////////////////// - // TL-UL Test Interface Emulation // - //////////////////////////////////// - - otp_ctrl_reg_pkg::otp_ctrl_prim_reg2hw_t reg2hw; - otp_ctrl_reg_pkg::otp_ctrl_prim_hw2reg_t hw2reg; - otp_ctrl_prim_reg_top u_reg_top ( - .clk_i, - .rst_ni, - .tl_i (test_tl_i ), - .tl_o (test_tl_o ), - .reg2hw (reg2hw ), - .hw2reg (hw2reg ), - .intg_err_o(intg_err ) - ); - - logic unused_reg_sig; - assign unused_reg_sig = ^reg2hw; - assign hw2reg = '0; - - /////////////////// - // Control logic // - /////////////////// - - // Encoding generated with: - // $ ./util/design/sparse-fsm-encode.py -d 5 -m 9 -n 10 \ - // -s 2599950981 --language=sv - // - // Hamming distance histogram: - // - // 0: -- - // 1: -- - // 2: -- - // 3: -- - // 4: -- - // 5: |||||||||||||||||||| (52.78%) - // 6: ||||||||||||||| (41.67%) - // 7: | (2.78%) - // 8: | (2.78%) - // 9: -- - // 10: -- - // - // Minimum Hamming distance: 5 - // Maximum Hamming distance: 8 - // Minimum Hamming weight: 3 - // Maximum Hamming weight: 8 - // - localparam int StateWidth = 10; - typedef enum logic [StateWidth-1:0] { - ResetSt = 10'b1100000110, - InitSt = 10'b1000110011, - IdleSt = 10'b0101110000, - ReadSt = 10'b0010011111, - ReadWaitSt = 10'b1001001101, - WriteCheckSt = 10'b1111101011, - WriteWaitSt = 10'b0011000010, - WriteSt = 10'b0110100101, - ErrorSt = 10'b1110011000 - } state_e; - - state_e state_d, state_q; - err_e err_d, err_q; - logic valid_d, valid_q; - logic integrity_en_d, integrity_en_q; - logic req, wren, rvalid; - logic [1:0] rerror; - 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; - logic read_ecc_on, write_ecc_on; - logic wdata_inconsistent; - - - assign cnt_d = (cnt_clr) ? '0 : - (cnt_en) ? cnt_q + 1'b1 : cnt_q; - - assign valid_o = valid_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 = err_q; - req = 1'b0; - wren = 1'b0; - cnt_clr = 1'b0; - cnt_en = 1'b0; - read_ecc_on = 1'b1; - write_ecc_on = 1'b1; - fsm_err = 1'b0; - integrity_en_d = integrity_en_q; - - unique case (state_q) - // Wait here until we receive an initialization command. - ResetSt: begin - err_d = NoError; - ready_o = 1'b1; - if (valid_i) begin - if (cmd_i == Init) begin - state_d = InitSt; - end - end - end - // Wait for some time until the OTP macro is ready. - InitSt: begin - state_d = IdleSt; - valid_d = 1'b1; - err_d = NoError; - end - // In the idle state, we basically wait for read or write commands. - IdleSt: begin - ready_o = 1'b1; - err_d = NoError; - if (valid_i) begin - cnt_clr = 1'b1; - err_d = NoError; - unique case (cmd_i) - Read: begin - state_d = ReadSt; - integrity_en_d = 1'b1; - end - Write: begin - state_d = WriteCheckSt; - integrity_en_d = 1'b1; - end - ReadRaw: begin - state_d = ReadSt; - integrity_en_d = 1'b0; - end - WriteRaw: begin - state_d = WriteCheckSt; - integrity_en_d = 1'b0; - end - default: ; - endcase // cmd_i - end - end - // Issue a read command to the macro. - ReadSt: begin - state_d = ReadWaitSt; - req = 1'b1; - // Suppress ECC correction if needed. - read_ecc_on = integrity_en_q; - end - // Wait for response from macro. - ReadWaitSt: begin - // Suppress ECC correction if needed. - read_ecc_on = integrity_en_q; - if (rvalid) begin - cnt_en = 1'b1; - // Uncorrectable error, bail out. - if (rerror[1] && integrity_en_q) begin - state_d = IdleSt; - valid_d = 1'b1; - err_d = 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] && integrity_en_q) begin - err_d = MacroEccCorrError; - end - end - end - end - // First, read out to perform the write blank check and - // read-modify-write operation. - WriteCheckSt: begin - state_d = WriteWaitSt; - req = 1'b1; - // Register raw memory contents without correction so that we can - // perform the read-modify-write correctly. - read_ecc_on = 1'b0; - end - // Wait for readout to complete first. - WriteWaitSt: begin - // Register raw memory contents without correction so that we can - // perform the read-modify-write correctly. - read_ecc_on = 1'b0; - if (rvalid) begin - cnt_en = 1'b1; - - if (cnt_q == size_q) begin - cnt_clr = 1'b1; - state_d = WriteSt; - end else begin - state_d = WriteCheckSt; - end - end - end - // If the write data attempts to clear an already programmed bit, - // the MacroWriteBlankError needs to be asserted. - WriteSt: begin - req = 1'b1; - wren = 1'b1; - cnt_en = 1'b1; - // Suppress ECC calculation if needed. - write_ecc_on = integrity_en_q; - - if (wdata_inconsistent) begin - err_d = MacroWriteBlankError; - end - - if (cnt_q == size_q) begin - valid_d = 1'b1; - state_d = IdleSt; - end - end - // If the FSM is glitched into an invalid state. - ErrorSt: begin - fsm_err = 1'b1; - end - default: begin - state_d = ErrorSt; - fsm_err = 1'b1; - end - endcase // state_q - end - - /////////////////////////////////////////// - // Emulate using ECC protected Block RAM // - /////////////////////////////////////////// - - logic [AddrWidth-1:0] addr; - assign addr = addr_q + AddrWidth'(cnt_q); - - logic [Width-1:0] rdata_corr; - logic [Width+EccWidth-1:0] rdata_d, wdata_ecc, rdata_ecc, wdata_rmw; - logic [2**SizeWidth-1:0][Width-1:0] wdata_q, rdata_reshaped; - logic [2**SizeWidth-1:0][Width+EccWidth-1:0] rdata_q; - - // Use a standard Hamming ECC for OTP. - prim_secded_hamming_22_16_enc u_enc ( - .data_i(wdata_q[cnt_q]), - .data_o(wdata_ecc) - ); - - prim_secded_hamming_22_16_dec u_dec ( - .data_i (rdata_ecc), - .data_o (rdata_corr), - .syndrome_o ( ), - .err_o (rerror) - ); - - assign rdata_d = (read_ecc_on) ? {{EccWidth{1'b0}}, rdata_corr} - : rdata_ecc; - - // Read-modify-write (OTP can only set bits to 1, but not clear to 0). - assign wdata_rmw = (write_ecc_on) ? wdata_ecc | rdata_q[cnt_q] - : {{EccWidth{1'b0}}, wdata_q[cnt_q]} | rdata_q[cnt_q]; - - // This indicates if the write data is inconsistent (i.e., if the operation attempts to - // clear an already programmed bit to zero). - assign wdata_inconsistent = (rdata_q[cnt_q] & wdata_ecc) != rdata_q[cnt_q]; - - // Output data without ECC bits. - always_comb begin : p_output_map - for (int k = 0; k < 2**SizeWidth; k++) begin - rdata_reshaped[k] = rdata_q[k][Width-1:0]; - end - rdata_o = rdata_reshaped; - end - - prim_ram_1p_adv #( - .Depth (Depth), - .Width (Width + EccWidth), - .MemInitFile (MemInitFile), - .EnableInputPipeline (1), - .EnableOutputPipeline (1) - ) u_prim_ram_1p_adv ( - .clk_i, - .rst_ni, - .req_i ( req ), - .write_i ( wren ), - .addr_i ( addr ), - .wdata_i ( wdata_rmw ), - .wmask_i ( {Width+EccWidth{1'b1}} ), - .rdata_o ( rdata_ecc ), - .rvalid_o ( rvalid ), - .rerror_o ( ), - .cfg_i ( '0 ), - .alert_o ( ) - ); - - // Currently it is assumed that no wrap arounds can occur. - `ASSERT(NoWrapArounds_A, req |-> (addr >= addr_q)) - - ////////// - // Regs // - ////////// - - `PRIM_FLOP_SPARSE_FSM(u_state_regs, state_d, state_q, state_e, ResetSt) - - always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs - if (!rst_ni) begin - valid_q <= '0; - err_q <= NoError; - addr_q <= '0; - wdata_q <= '0; - rdata_q <= '0; - cnt_q <= '0; - size_q <= '0; - integrity_en_q <= 1'b0; - end else begin - valid_q <= valid_d; - err_q <= err_d; - cnt_q <= cnt_d; - integrity_en_q <= integrity_en_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 - - //////////////// - // Assertions // - //////////////// - - // Check that the otp_ctrl FSMs only issue legal commands to the wrapper. - `ASSERT(CheckCommands0_A, state_q == ResetSt && valid_i && ready_o |-> cmd_i == Init) - `ASSERT(CheckCommands1_A, state_q != ResetSt && valid_i && ready_o - |-> cmd_i inside {Read, ReadRaw, Write, WriteRaw}) - - -endmodule : prim_generic_otp diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_pad_attr.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_pad_attr.sv similarity index 97% rename from vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_pad_attr.sv rename to vendor/lowrisc_ip/ip/prim_generic/rtl/prim_pad_attr.sv index 80e93f82bc..a79b6a0435 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_pad_attr.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_pad_attr.sv @@ -5,7 +5,7 @@ `include "prim_assert.sv" -module prim_generic_pad_attr +module prim_pad_attr import prim_pad_wrapper_pkg::*; #( parameter pad_type_e PadType = BidirStd // currently ignored in the generic model @@ -68,4 +68,4 @@ module prim_generic_pad_attr assert_static_in_generate_config_not_available(); end -endmodule : prim_generic_pad_attr +endmodule : prim_pad_attr diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_pad_wrapper.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_pad_wrapper.sv similarity index 98% rename from vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_pad_wrapper.sv rename to vendor/lowrisc_ip/ip/prim_generic/rtl/prim_pad_wrapper.sv index 7ff382c302..47ef644ce5 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_pad_wrapper.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_pad_wrapper.sv @@ -7,7 +7,7 @@ `include "prim_assert.sv" -module prim_generic_pad_wrapper +module prim_pad_wrapper import prim_pad_wrapper_pkg::*; #( // These parameters are ignored in this model. @@ -120,4 +120,4 @@ module prim_generic_pad_wrapper assert_static_in_generate_config_not_available(); end -endmodule : prim_generic_pad_wrapper +endmodule : prim_pad_wrapper diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_pkg.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_pkg.sv new file mode 100644 index 0000000000..e71512f1ee --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_pkg.sv @@ -0,0 +1,10 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// + +package prim_pkg; + // The name of the technology implementation. + parameter PrimTechName = "Generic"; + +endpackage // prim_pkg diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_ram_1p.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_ram_1p.sv similarity index 92% rename from vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_ram_1p.sv rename to vendor/lowrisc_ip/ip/prim_generic/rtl/prim_ram_1p.sv index d2e835ac33..e224107f40 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_ram_1p.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_ram_1p.sv @@ -6,7 +6,7 @@ `include "prim_assert.sv" -module prim_generic_ram_1p import prim_ram_1p_pkg::*; #( +module prim_ram_1p import prim_ram_1p_pkg::*; #( parameter int Width = 32, // bit parameter int Depth = 128, parameter int DataBitsPerMask = 1, // Number of data bits per bit of write mask @@ -15,6 +15,7 @@ module prim_generic_ram_1p import prim_ram_1p_pkg::*; #( localparam int Aw = $clog2(Depth) // derived parameter ) ( input logic clk_i, + input logic rst_ni, input logic req_i, input logic write_i, @@ -22,7 +23,8 @@ module prim_generic_ram_1p import prim_ram_1p_pkg::*; #( input logic [Width-1:0] wdata_i, input logic [Width-1:0] wmask_i, output logic [Width-1:0] rdata_o, // Read data. Data is returned one cycle after req_i is high. - input ram_1p_cfg_t cfg_i + input ram_1p_cfg_t cfg_i, + output ram_1p_cfg_rsp_t cfg_rsp_o ); // For certain synthesis experiments we compile the design with generic models to get an unmapped @@ -38,8 +40,9 @@ module prim_generic_ram_1p import prim_ram_1p_pkg::*; #( // Width must be fully divisible by DataBitsPerMask `ASSERT_INIT(DataBitsPerMaskCheck_A, (Width % DataBitsPerMask) == 0) - logic unused_cfg; - assign unused_cfg = ^cfg_i; + logic unused_signals; + assign unused_signals = ^{cfg_i, rst_ni}; + assign cfg_rsp_o = '0; // Width of internal write mask. Note wmask_i input into the module is always assumed // to be the full bit mask diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1p_pkg.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_ram_1p_pkg.sv similarity index 85% rename from vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1p_pkg.sv rename to vendor/lowrisc_ip/ip/prim_generic/rtl/prim_ram_1p_pkg.sv index 4aefd25f87..f8d45dd44a 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1p_pkg.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_ram_1p_pkg.sv @@ -6,6 +6,7 @@ package prim_ram_1p_pkg; typedef struct packed { + logic test; logic cfg_en; logic [3:0] cfg; } cfg_t; @@ -15,6 +16,10 @@ package prim_ram_1p_pkg; cfg_t rf_cfg; // configuration for regfile } ram_1p_cfg_t; + typedef struct packed { + logic done; + } ram_1p_cfg_rsp_t; + parameter ram_1p_cfg_t RAM_1P_CFG_DEFAULT = '0; endpackage // prim_ram_1p_pkg diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_ram_1r1w.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_ram_1r1w.sv similarity index 89% rename from vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_ram_1r1w.sv rename to vendor/lowrisc_ip/ip/prim_generic/rtl/prim_ram_1r1w.sv index aafecf8adb..a64876b02a 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_ram_1r1w.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_ram_1r1w.sv @@ -6,7 +6,7 @@ // This module is for simulation and small size SRAM. // Implementing ECC should be done inside wrapper not this model. `include "prim_assert.sv" -module prim_generic_ram_1r1w import prim_ram_2p_pkg::*; #( +module prim_ram_1r1w import prim_ram_2p_pkg::*; #( parameter int Width = 32, // bit parameter int Depth = 128, parameter int DataBitsPerMask = 1, // Number of data bits per bit of write mask @@ -14,8 +14,10 @@ module prim_generic_ram_1r1w import prim_ram_2p_pkg::*; #( localparam int Aw = $clog2(Depth) // derived parameter ) ( - input clk_a_i, - input clk_b_i, + input logic clk_a_i, + input logic clk_b_i, + input logic rst_a_ni, + input logic rst_b_ni, // Port A can only write input a_req_i, @@ -28,7 +30,8 @@ module prim_generic_ram_1r1w import prim_ram_2p_pkg::*; #( input [Aw-1:0] b_addr_i, output logic [Width-1:0] b_rdata_o, - input ram_2p_cfg_t cfg_i + input ram_2p_cfg_t cfg_i, + output ram_2p_cfg_rsp_t cfg_rsp_o ); // For certain synthesis experiments we compile the design with generic models to get an unmapped @@ -41,8 +44,9 @@ module prim_generic_ram_1r1w import prim_ram_2p_pkg::*; #( // these runs with the following macro. `ifndef SYNTHESIS_MEMORY_BLACK_BOXING - logic unused_cfg; - assign unused_cfg = ^cfg_i; + logic unused_signals; + assign unused_signals = ^{cfg_i, rst_a_ni, rst_b_ni}; + assign cfg_rsp_o = '0; // Width of internal write mask. Note *_wmask_i input into the module is always assumed // to be the full bit mask. diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_ram_2p.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_ram_2p.sv similarity index 96% rename from vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_ram_2p.sv rename to vendor/lowrisc_ip/ip/prim_generic/rtl/prim_ram_2p.sv index f44e828bfb..65f94fe051 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_ram_2p.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_ram_2p.sv @@ -6,7 +6,7 @@ // This module is for simulation and small size SRAM. // Implementing ECC should be done inside wrapper not this model. `include "prim_assert.sv" -module prim_generic_ram_2p import prim_ram_2p_pkg::*; #( +module prim_ram_2p import prim_ram_2p_pkg::*; #( parameter int Width = 32, // bit parameter int Depth = 128, parameter int DataBitsPerMask = 1, // Number of data bits per bit of write mask @@ -32,7 +32,8 @@ module prim_generic_ram_2p import prim_ram_2p_pkg::*; #( input logic [Width-1:0] b_wmask_i, output logic [Width-1:0] b_rdata_o, - input ram_2p_cfg_t cfg_i + input ram_2p_cfg_t cfg_i, + output ram_2p_cfg_rsp_t cfg_rsp_o ); // For certain synthesis experiments we compile the design with generic models to get an unmapped @@ -47,6 +48,7 @@ module prim_generic_ram_2p import prim_ram_2p_pkg::*; #( logic unused_cfg; assign unused_cfg = ^cfg_i; + assign cfg_rsp_o = '0; // Width of internal write mask. Note *_wmask_i input into the module is always assumed // to be the full bit mask. diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_2p_pkg.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_ram_2p_pkg.sv similarity index 87% rename from vendor/lowrisc_ip/ip/prim/rtl/prim_ram_2p_pkg.sv rename to vendor/lowrisc_ip/ip/prim_generic/rtl/prim_ram_2p_pkg.sv index 0b002b4ecc..87702eebb8 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_2p_pkg.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_ram_2p_pkg.sv @@ -6,6 +6,7 @@ package prim_ram_2p_pkg; typedef struct packed { + logic test; logic cfg_en; logic [3:0] cfg; } cfg_t; @@ -19,4 +20,8 @@ package prim_ram_2p_pkg; parameter ram_2p_cfg_t RAM_2P_CFG_DEFAULT = '0; + typedef struct packed { + logic done; + } ram_2p_cfg_rsp_t; + endpackage // prim_ram_2p_pkg diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_rom.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_rom.sv similarity index 70% rename from vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_rom.sv rename to vendor/lowrisc_ip/ip/prim_generic/rtl/prim_rom.sv index acf5f379ca..9dfa41bd7d 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_rom.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_rom.sv @@ -4,7 +4,7 @@ `include "prim_assert.sv" -module prim_generic_rom import prim_rom_pkg::*; #( +module prim_rom import prim_rom_pkg::*; #( parameter int Width = 32, parameter int Depth = 2048, // 8kB default parameter MemInitFile = "", // VMEM file to initialize the memory with @@ -12,17 +12,28 @@ module prim_generic_rom import prim_rom_pkg::*; #( localparam int Aw = $clog2(Depth) ) ( input logic clk_i, + input logic rst_ni, input logic req_i, input logic [Aw-1:0] addr_i, + output logic rvalid_o, output logic [Width-1:0] rdata_o, input rom_cfg_t cfg_i ); - logic unused_cfg; - assign unused_cfg = ^cfg_i; + logic unused_signals; + assign unused_signals = ^{cfg_i}; logic [Width-1:0] mem [Depth]; + // Data always comes in the next cycle after a request + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + rvalid_o <= 1'b0; + end else begin + rvalid_o <= req_i; + end + end + always_ff @(posedge clk_i) begin if (req_i) begin rdata_o <= mem[addr_i]; diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_rom_pkg.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_rom_pkg.sv similarity index 94% rename from vendor/lowrisc_ip/ip/prim/rtl/prim_rom_pkg.sv rename to vendor/lowrisc_ip/ip/prim_generic/rtl/prim_rom_pkg.sv index c6c4be04df..c4f00fd1a0 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_rom_pkg.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_rom_pkg.sv @@ -6,6 +6,7 @@ package prim_rom_pkg; typedef struct packed { + logic test; logic cfg_en; logic [3:0] cfg; } rom_cfg_t; diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_rst_sync.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_rst_sync.sv similarity index 100% rename from vendor/lowrisc_ip/ip/prim/rtl/prim_rst_sync.sv rename to vendor/lowrisc_ip/ip/prim_generic/rtl/prim_rst_sync.sv 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_usb_diff_rx.sv similarity index 95% rename from vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_usb_diff_rx.sv rename to vendor/lowrisc_ip/ip/prim_generic/rtl/prim_usb_diff_rx.sv index a0b8e19c87..a7c7fe00fd 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_usb_diff_rx.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_usb_diff_rx.sv @@ -7,7 +7,7 @@ `include "prim_assert.sv" -module prim_generic_usb_diff_rx #( +module prim_usb_diff_rx #( parameter int CalibW = 32 ) ( inout input_pi, // differential input @@ -47,4 +47,4 @@ module prim_generic_usb_diff_rx #( .out_o (usb_diff_rx_obs_o) ); -endmodule : prim_generic_usb_diff_rx +endmodule : prim_usb_diff_rx diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_xnor2.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_xnor2.sv similarity index 84% rename from vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_xnor2.sv rename to vendor/lowrisc_ip/ip/prim_generic/rtl/prim_xnor2.sv index 90eb684d2f..9a64c4dd77 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_xnor2.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_xnor2.sv @@ -4,7 +4,7 @@ `include "prim_assert.sv" -module prim_generic_xnor2 #( +module prim_xnor2 #( parameter int Width = 1 ) ( input [Width-1:0] in0_i, @@ -12,6 +12,6 @@ module prim_generic_xnor2 #( output logic [Width-1:0] out_o ); - assign out_o = !(in0_i ^ in1_i); + assign out_o = ~(in0_i ^ in1_i); endmodule diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_xor2.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_xor2.sv similarity index 93% rename from vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_xor2.sv rename to vendor/lowrisc_ip/ip/prim_generic/rtl/prim_xor2.sv index 4f303c7730..059dd60b2e 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_xor2.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_xor2.sv @@ -4,7 +4,7 @@ `include "prim_assert.sv" -module prim_generic_xor2 #( +module prim_xor2 #( parameter int Width = 1 ) ( input [Width-1:0] in0_i, diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/BUILD b/vendor/lowrisc_ip/ip/prim_xilinx/BUILD index f42854cd1b..307b2eb253 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/BUILD +++ b/vendor/lowrisc_ip/ip/prim_xilinx/BUILD @@ -5,7 +5,14 @@ package(default_visibility = ["//visibility:public"]) filegroup( - name = "all_files", - srcs = glob(["**"]) + [ + name = "rtl_files", + srcs = glob( + ["**"], + exclude = [ + "dv/**", + "doc/**", + "README.md", + ], + ) + [ ], ) 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 198eeeace1..05764f141f 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 @@ -5,8 +5,8 @@ # 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} \ + -location {prim_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} \ + -location {prim_pad_wrapper.sv} \ -comment "Some IO attributes may not be implemented." diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/lint/prim_xilinx_rom.waiver b/vendor/lowrisc_ip/ip/prim_xilinx/lint/prim_xilinx_rom.waiver new file mode 100644 index 0000000000..351694ba18 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim_xilinx/lint/prim_xilinx_rom.waiver @@ -0,0 +1,8 @@ +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# waiver file for prim_generic_rom + +waive -rules NOT_DRIVEN -location {prim_generic_rom.sv} -regexp {Signal 'mem' has no driver in module 'prim_generic_rom'} \ + -comment "since this is a ROM, the signal mem has no driver, but it is populated using an initialization file" diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx.core b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx.core new file mode 100644 index 0000000000..c456b761e1 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx.core @@ -0,0 +1,66 @@ +CAPI=2: +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +name: "lowrisc:prim_xilinx:all:0.1" +description: "Xilinx 7-series prim library" + +filesets: + files_rtl: + depend: + - lowrisc:prim_xilinx:prim_pkg + - lowrisc:prim_xilinx:and2 + - lowrisc:prim_xilinx:buf + - lowrisc:prim_xilinx:clock_buf + - lowrisc:prim_generic:clock_div + - lowrisc:prim_xilinx:clock_gating + - lowrisc:prim_generic:clock_inv + - lowrisc:prim_xilinx:clock_mux2 + - lowrisc:prim_xilinx:flop + - lowrisc:prim_generic:flop_2sync + - lowrisc:prim_generic:rst_sync + - lowrisc:prim_xilinx:flop_en + - lowrisc:prim_xilinx:pad_attr + - lowrisc:prim_xilinx:pad_wrapper + - lowrisc:prim_xilinx:ram_1p + - lowrisc:prim_generic:ram_1r1w + - lowrisc:prim_generic:ram_2p + - lowrisc:prim_xilinx:rom + - lowrisc:prim_generic:usb_diff_rx + - lowrisc:prim_xilinx:xnor2 + - lowrisc:prim_xilinx:xor2 +# Note that flash is a macro that depends on IPs, so they are not +# included here. They must be brought in explicitly. +# - lowrisc:prim_generic:flash + +mapping: + "lowrisc:prim:prim_pkg" : lowrisc:prim_xilinx:prim_pkg + "lowrisc:prim:and2" : lowrisc:prim_xilinx:and2 + "lowrisc:prim:buf" : lowrisc:prim_xilinx:buf + "lowrisc:prim:clock_buf" : lowrisc:prim_xilinx:clock_buf + "lowrisc:prim:clock_div" : lowrisc:prim_generic:clock_div + "lowrisc:prim:clock_gating" : lowrisc:prim_xilinx:clock_gating + "lowrisc:prim:clock_inv" : lowrisc:prim_generic:clock_inv + "lowrisc:prim:clock_mux2" : lowrisc:prim_xilinx:clock_mux2 + "lowrisc:prim:flop" : lowrisc:prim_xilinx:flop + "lowrisc:prim:flop_2sync" : lowrisc:prim_generic:flop_2sync + "lowrisc:prim:rst_sync" : lowrisc:prim_generic:rst_sync + "lowrisc:prim:flop_en" : lowrisc:prim_xilinx:flop_en + "lowrisc:prim:pad_attr" : lowrisc:prim_xilinx:pad_attr + "lowrisc:prim:pad_wrapper" : lowrisc:prim_xilinx:pad_wrapper + "lowrisc:prim:ram_1p" : lowrisc:prim_xilinx:ram_1p + "lowrisc:prim:ram_1r1w" : lowrisc:prim_generic:ram_1r1w + "lowrisc:prim:ram_2p" : lowrisc:prim_generic:ram_2p + "lowrisc:prim:rom" : lowrisc:prim_xilinx:rom + "lowrisc:prim:usb_diff_rx" : lowrisc:prim_generic:usb_diff_rx + "lowrisc:prim:xnor2" : lowrisc:prim_xilinx:xnor2 + "lowrisc:prim:xor2" : lowrisc:prim_xilinx:xor2 + # Flash is a good canditate to be removed from the prims and become a macro like OTP. + # When this is done, it should be removed from this mapping. + "lowrisc:prim:flash": "lowrisc:prim_generic:flash" + +targets: + default: + filesets: + - files_rtl diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_and2.core b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_and2.core index 9c86c83f4e..a88998653a 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_and2.core +++ b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_and2.core @@ -5,10 +5,13 @@ CAPI=2: name: "lowrisc:prim_xilinx:and2" description: "Xilinx 2-input and" +virtual: + - lowrisc:prim:and2 + filesets: files_rtl: files: - - rtl/prim_xilinx_and2.sv + - rtl/prim_and2.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_buf.core b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_buf.core index bc4e7a2e26..a7402d416e 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_buf.core +++ b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_buf.core @@ -5,10 +5,13 @@ CAPI=2: name: "lowrisc:prim_xilinx:buf" description: "buffer" +virtual: + - lowrisc:prim:buf + filesets: files_rtl: files: - - rtl/prim_xilinx_buf.sv + - rtl/prim_buf.sv file_type: systemVerilogSource files_verilator_waiver: 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 index f1bfbe8f12..c315943b88 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_clock_buf.core +++ b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_clock_buf.core @@ -5,10 +5,13 @@ CAPI=2: name: "lowrisc:prim_xilinx:clock_buf" description: "clock buffer" +virtual: + - lowrisc:prim:clock_buf + filesets: files_rtl: files: - - rtl/prim_xilinx_clock_buf.sv + - rtl/prim_clock_buf.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_clock_gating.core b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_clock_gating.core index 587c7e5a35..5345ab9fab 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_clock_gating.core +++ b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_clock_gating.core @@ -5,10 +5,13 @@ CAPI=2: name: "lowrisc:prim_xilinx:clock_gating" description: "prim" +virtual: + - lowrisc:prim:clock_gating + filesets: files_rtl: files: - - rtl/prim_xilinx_clock_gating.sv + - rtl/prim_clock_gating.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_clock_mux2.core b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_clock_mux2.core index 5d94cd0c71..a1e8463caa 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_clock_mux2.core +++ b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_clock_mux2.core @@ -5,10 +5,13 @@ CAPI=2: name: "lowrisc:prim_xilinx:clock_mux2" description: "two-input clock multiplexer primitive" +virtual: + - lowrisc:prim:clock_mux2 + filesets: files_rtl: files: - - rtl/prim_xilinx_clock_mux2.sv + - rtl/prim_clock_mux2.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_default_pkg.core b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_default_pkg.core new file mode 100644 index 0000000000..efcff71f05 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_default_pkg.core @@ -0,0 +1,19 @@ +CAPI=2: +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +name: "lowrisc:prim_xilinx:prim_xilinx_default_pkg" +description: "Single port RAM" +virtual: + - lowrisc:prim_xilinx:prim_xilinx_pkg +filesets: + files_rtl: + files: + - rtl/prim_xilinx_pkg.sv + file_type: systemVerilogSource + +targets: + default: &default_target + filesets: + - 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 index b94d12c75e..2cd6071177 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_flop.core +++ b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_flop.core @@ -5,10 +5,13 @@ CAPI=2: name: "lowrisc:prim_xilinx:flop" description: "Xilinx flop" +virtual: + - lowrisc:prim:flop + filesets: files_rtl: files: - - rtl/prim_xilinx_flop.sv + - rtl/prim_flop.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_flop_en.core b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_flop_en.core index e40394b832..cc3176d0ee 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_flop_en.core +++ b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_flop_en.core @@ -5,10 +5,13 @@ CAPI=2: name: "lowrisc:prim_xilinx:flop_en" description: "Xilinx enable flop" +virtual: + - lowrisc:prim:flop_en + filesets: files_rtl: files: - - rtl/prim_xilinx_flop_en.sv + - rtl/prim_flop_en.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_pad_attr.core b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_pad_attr.core index 6c1031337b..ef179b09b0 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_pad_attr.core +++ b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_pad_attr.core @@ -5,13 +5,16 @@ CAPI=2: name: "lowrisc:prim_xilinx:pad_attr" description: "Pad attribute WARL module for Xilinx pads" +virtual: + - lowrisc:prim:pad_attr + filesets: files_rtl: depend: - lowrisc:prim:assert - lowrisc:prim:pad_wrapper_pkg files: - - rtl/prim_xilinx_pad_attr.sv + - rtl/prim_pad_attr.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_pad_wrapper.core b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_pad_wrapper.core index 765845a0bc..42e2495071 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_pad_wrapper.core +++ b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_pad_wrapper.core @@ -5,13 +5,16 @@ CAPI=2: name: "lowrisc:prim_xilinx:pad_wrapper" description: "prim" +virtual: + - lowrisc:prim:pad_wrapper + filesets: files_rtl: depend: - lowrisc:prim:assert - lowrisc:prim:pad_wrapper_pkg files: - - rtl/prim_xilinx_pad_wrapper.sv + - rtl/prim_pad_wrapper.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim/prim_clock_mux2.core b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_pkg.core similarity index 65% rename from vendor/lowrisc_ip/ip/prim/prim_clock_mux2.core rename to vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_pkg.core index 5f703aded3..58cfb5ec2d 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_clock_mux2.core +++ b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_pkg.core @@ -3,14 +3,16 @@ CAPI=2: # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -name: "lowrisc:prim:clock_mux2" -description: "2-input clock multiplexer" -filesets: - primgen_dep: - depend: - - lowrisc:prim:prim_pkg - - lowrisc:prim:primgen +name: "lowrisc:prim_xilinx:prim_pkg" +description: "Xilinx technology package" +virtual: + - lowrisc:prim:prim_pkg +filesets: + files_rtl: + files: + - rtl/prim_pkg.sv + file_type: systemVerilogSource files_verilator_waiver: depend: @@ -21,27 +23,16 @@ filesets: depend: # common waivers - lowrisc:lint:common - files: - - lint/prim_clock_mux2.waiver - file_type: waiver files_veriblelint_waiver: depend: # common waivers - lowrisc:lint:common -generate: - impl: - generator: primgen - parameters: - prim_name: clock_mux2 - targets: default: filesets: - tool_verilator ? (files_verilator_waiver) - tool_ascentlint ? (files_ascentlint_waiver) - tool_veriblelint ? (files_veriblelint_waiver) - - primgen_dep - generate: - - impl + - files_rtl diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_ram_1p.core b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_ram_1p.core new file mode 100644 index 0000000000..d171aad84f --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_ram_1p.core @@ -0,0 +1,46 @@ +CAPI=2: +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +name: "lowrisc:prim_xilinx:ram_1p" +description: "Single port RAM" +virtual: + - lowrisc:prim:ram_1p + +filesets: + files_rtl: + depend: + - lowrisc:prim:assert + # Note that prim_xilinx_pkg is a virtual core that the top should provide. + # It maps parameters to instructions for how to split memories into + # logical groups of bits. See prim_xilinx_default_pkg for an example. + - lowrisc:prim_xilinx:prim_xilinx_pkg + - lowrisc:prim_generic:ram_1p_pkg + - lowrisc:prim:util_memload + files: + - rtl/prim_ram_1p.sv + file_type: systemVerilogSource + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + +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/prim_flop.core b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_rom.core similarity index 67% rename from vendor/lowrisc_ip/ip/prim/prim_flop.core rename to vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_rom.core index b707f1c473..f2973dbebf 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_flop.core +++ b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_rom.core @@ -3,27 +3,32 @@ CAPI=2: # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -name: "lowrisc:prim:flop" -description: "Generic flop" +name: "lowrisc:prim_xilinx:rom" +description: "Technology-independent Read-Only Memory (ROM) implementation" +virtual: + - lowrisc:prim:rom + filesets: - primgen_dep: + files_rtl: depend: - - lowrisc:prim:prim_pkg - - lowrisc:prim:primgen - lowrisc:prim:assert + - lowrisc:prim_generic:rom_pkg + - lowrisc:prim:util_memload + files: + - rtl/prim_xilinx_rom.sv + file_type: systemVerilogSource files_verilator_waiver: depend: # common waivers - lowrisc:lint:common - file_type: vlt files_ascentlint_waiver: depend: # common waivers - lowrisc:lint:common files: - - lint/prim_flop.waiver + - lint/prim_xilinx_rom.waiver file_type: waiver files_veriblelint_waiver: @@ -31,18 +36,10 @@ filesets: # common waivers - lowrisc:lint:common -generate: - impl: - generator: primgen - parameters: - prim_name: flop - targets: default: filesets: - tool_verilator ? (files_verilator_waiver) - tool_ascentlint ? (files_ascentlint_waiver) - tool_veriblelint ? (files_veriblelint_waiver) - - primgen_dep - generate: - - impl + - files_rtl diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_xnor2.core b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_xnor2.core new file mode 100644 index 0000000000..852cde0e92 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_xnor2.core @@ -0,0 +1,38 @@ +CAPI=2: +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +name: "lowrisc:prim_xilinx:xnor2" +description: "Xilinx 2-input xnor" +virtual: + - lowrisc:prim:xnor2 + +filesets: + files_rtl: + files: + - rtl/prim_xnor2.sv + file_type: systemVerilogSource + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + +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_xor2.core b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_xor2.core index e7f699cf84..09b321f9d5 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_xor2.core +++ b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_xor2.core @@ -5,10 +5,13 @@ CAPI=2: name: "lowrisc:prim_xilinx:xor2" description: "Xilinx 2-input xor" +virtual: + - lowrisc:prim:xor2 + filesets: files_rtl: files: - - rtl/prim_xilinx_xor2.sv + - rtl/prim_xor2.sv file_type: systemVerilogSource files_verilator_waiver: diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_and2.sv b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_and2.sv similarity index 94% rename from vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_and2.sv rename to vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_and2.sv index 69d8683612..76a0699a01 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_and2.sv +++ b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_and2.sv @@ -6,7 +6,7 @@ // Prevent Vivado from performing optimizations on/across this module. (* DONT_TOUCH = "yes" *) -module prim_xilinx_and2 #( +module prim_and2 #( parameter int Width = 1 ) ( input [Width-1:0] in0_i, diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_buf.sv b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_buf.sv similarity index 93% rename from vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_buf.sv rename to vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_buf.sv index 7bdeea9cb7..dd772bbd12 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_buf.sv +++ b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_buf.sv @@ -4,7 +4,7 @@ // Prevent Vivado from performing optimizations on/across this module. (* DONT_TOUCH = "yes" *) -module prim_xilinx_buf #( +module prim_buf #( parameter int Width = 1 ) ( input [Width-1:0] in_i, diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_clock_buf.sv b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_clock_buf.sv similarity index 97% rename from vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_clock_buf.sv rename to vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_clock_buf.sv index 51945f4402..0169f74048 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_clock_buf.sv +++ b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_clock_buf.sv @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -module prim_xilinx_clock_buf #( +module prim_clock_buf #( // The following options allow a user to choose the type of buffer // associated with this cell. // NoFpgaBuf -> No fpga clock buffer is selected, this will be constructed diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_clock_gating.sv b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_clock_gating.sv similarity index 97% rename from vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_clock_gating.sv rename to vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_clock_gating.sv index 7eaac02a07..99bc6850a2 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_clock_gating.sv +++ b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_clock_gating.sv @@ -2,7 +2,7 @@ // 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_clock_gating #( parameter bit NoFpgaGate = 1'b0, parameter bit FpgaBufGlobal = 1'b1 ) ( diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_clock_mux2.sv b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_clock_mux2.sv similarity index 93% rename from vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_clock_mux2.sv rename to vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_clock_mux2.sv index ee7390d9c2..81066ad40b 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_clock_mux2.sv +++ b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_clock_mux2.sv @@ -4,7 +4,7 @@ `include "prim_assert.sv" -module prim_xilinx_clock_mux2 #( +module prim_clock_mux2 #( parameter bit NoFpgaBufG = 1'b0 ) ( input clk0_i, @@ -33,4 +33,4 @@ module prim_xilinx_clock_mux2 #( `ASSERT(selKnown0, ##1 !$isunknown(sel_i), clk0_i, 0) `ASSERT(selKnown1, ##1 !$isunknown(sel_i), clk1_i, 0) -endmodule : prim_xilinx_clock_mux2 +endmodule : prim_clock_mux2 diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_flop.sv b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_flop.sv similarity index 95% rename from vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_flop.sv rename to vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_flop.sv index 45deeadeec..04c8962e5c 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_flop.sv +++ b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_flop.sv @@ -6,7 +6,7 @@ // Prevent Vivado from performing optimizations on/across this module. (* DONT_TOUCH = "yes" *) -module prim_xilinx_flop #( +module prim_flop #( parameter int Width = 1, parameter logic [Width-1:0] ResetValue = 0 ) ( diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_flop_en.sv b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_flop_en.sv similarity index 90% rename from vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_flop_en.sv rename to vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_flop_en.sv index c4de058a91..321ca4a055 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_flop_en.sv +++ b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_flop_en.sv @@ -6,9 +6,9 @@ // Prevent Vivado from performing optimizations on/across this module. (* DONT_TOUCH = "yes" *) -module prim_xilinx_flop_en #( +module prim_flop_en #( parameter int Width = 1, - // This parmaeter does nothing for prim_xilinx + // This parameter does nothing for prim_xilinx parameter bit EnSecBuf = 0, parameter logic [Width-1:0] ResetValue = 0 ) ( diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_pad_attr.sv b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_pad_attr.sv similarity index 96% rename from vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_pad_attr.sv rename to vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_pad_attr.sv index 7267465e8c..5955d72b18 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_pad_attr.sv +++ b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_pad_attr.sv @@ -5,7 +5,7 @@ `include "prim_assert.sv" -module prim_xilinx_pad_attr +module prim_pad_attr import prim_pad_wrapper_pkg::*; #( // This parameter is ignored in this Xilinx variant. @@ -56,4 +56,4 @@ module prim_xilinx_pad_attr end -endmodule : prim_xilinx_pad_attr +endmodule : prim_pad_attr diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_pad_wrapper.sv b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_pad_wrapper.sv similarity index 98% rename from vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_pad_wrapper.sv rename to vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_pad_wrapper.sv index afb9c1794e..4c2a539de9 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_pad_wrapper.sv +++ b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_pad_wrapper.sv @@ -7,7 +7,7 @@ `include "prim_assert.sv" -module prim_xilinx_pad_wrapper +module prim_pad_wrapper import prim_pad_wrapper_pkg::*; #( // These parameters are ignored in this Xilinx variant. @@ -123,4 +123,4 @@ module prim_xilinx_pad_wrapper assert_static_in_generate_config_not_available(); end -endmodule : prim_xilinx_pad_wrapper +endmodule : prim_pad_wrapper diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_pkg.sv b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_pkg.sv new file mode 100644 index 0000000000..d68577bc9b --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_pkg.sv @@ -0,0 +1,10 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// + +package prim_pkg; + // The name of the technology implementation. + parameter PrimTechName = "Xilinx"; + +endpackage // prim_pkg diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_ram_1p.sv b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_ram_1p.sv new file mode 100644 index 0000000000..742d56bafe --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_ram_1p.sv @@ -0,0 +1,105 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Synchronous single-port SRAM model + +`include "prim_assert.sv" + +module prim_ram_1p import prim_ram_1p_pkg::*; #( + parameter int Width = 32, // bit + parameter int Depth = 128, + parameter int DataBitsPerMask = 1, // Number of data bits per bit of write mask + parameter MemInitFile = "", // VMEM file to initialize the memory with + + localparam int Aw = $clog2(Depth) // derived parameter +) ( + input logic clk_i, + input logic rst_ni, + + input logic req_i, + input logic write_i, + input logic [Aw-1:0] addr_i, + input logic [Width-1:0] wdata_i, + input logic [Width-1:0] wmask_i, + output logic [Width-1:0] rdata_o, // Read data. Data is returned one cycle after req_i is high. + input ram_1p_cfg_t cfg_i, + output ram_1p_cfg_rsp_t cfg_rsp_o +); + + localparam int PrimMaxWidth = prim_xilinx_pkg::get_ram_max_width(Width, Depth); + + if (PrimMaxWidth <= 0) begin : gen_generic + // Width of internal write mask. Note wmask_i input into the module is always assumed + // to be the full bit mask + localparam int MaskWidth = Width / DataBitsPerMask; + + logic [Width-1:0] mem [Depth]; + logic [MaskWidth-1:0] wmask; + + for (genvar k = 0; k < MaskWidth; k++) begin : gen_wmask + assign wmask[k] = &wmask_i[k*DataBitsPerMask +: DataBitsPerMask]; + + // Ensure that all mask bits within a group have the same value for a write + `ASSERT(MaskCheck_A, req_i && write_i |-> + wmask_i[k*DataBitsPerMask +: DataBitsPerMask] inside {{DataBitsPerMask{1'b1}}, '0}, + clk_i, '0) + end + + // 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_i) begin + if (write_i) begin + for (int i=0; i < MaskWidth; i = i + 1) begin + if (wmask[i]) begin + mem[addr_i][i*DataBitsPerMask +: DataBitsPerMask] <= + wdata_i[i*DataBitsPerMask +: DataBitsPerMask]; + end + end + end else begin + rdata_o <= mem[addr_i]; + end + end + end + + `include "prim_util_memload.svh" + end else begin : gen_xpm + logic wr_en; + assign wr_en = write_i & wmask_i[0]; + + logic unused_signals; + assign unused_signals = ^{rst_ni, cfg_i}; + assign cfg_rsp_o = '0; + + for (genvar k = 0; k < Width; k = k + PrimMaxWidth) begin : gen_split + localparam int PrimWidth = ((Width - k) > PrimMaxWidth) ? PrimMaxWidth : Width - k; + + xpm_memory_spram #( + .ADDR_WIDTH_A(Aw), + .BYTE_WRITE_WIDTH_A(PrimWidth), // Masks are not supported + .MEMORY_INIT_FILE((MemInitFile == "") ? "none" : MemInitFile), + .MEMORY_SIZE(Depth * PrimWidth), + .READ_DATA_WIDTH_A(PrimWidth), + .READ_LATENCY_A(1), + .USE_MEM_INIT_MMI(1), + .WRITE_DATA_WIDTH_A(PrimWidth) + ) u_ram_1p ( + .clka(clk_i), + .addra(addr_i), + .dbiterra(), + .dina(wdata_i[k +: PrimWidth]), + .douta(rdata_o[k +: PrimWidth]), + .ena(req_i), + .injectdbiterra(1'b0), + .injectsbiterra(1'b0), + .regcea(1'b1), + .rsta(1'b0), + .sbiterra(), + .sleep(1'b0), + .wea(wr_en) + ); + end + end + +endmodule diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_pkg.sv b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_pkg.sv new file mode 100644 index 0000000000..cf46bc1951 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_pkg.sv @@ -0,0 +1,16 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +package prim_xilinx_pkg; + + // Returns the maximum width of an individual xpm memory. Note that this API + // may evolve over time, but currently it uses the width and depth + // parameters to identify memories that may need to be broken up into + // separate groups. This can help work around updatemem's maximum width for + // words, which is 64 bits at the time of writing. + function automatic int get_ram_max_width(int width, int depth); + return 0; + endfunction + +endpackage : prim_xilinx_pkg diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_rom.sv b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_rom.sv new file mode 100644 index 0000000000..e7aa5cbe8e --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_rom.sv @@ -0,0 +1,78 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`include "prim_assert.sv" + +module prim_rom import prim_rom_pkg::*; #( + parameter int Width = 32, + parameter int Depth = 2048, // 8kB default + parameter string MemInitFile = "", // VMEM file to initialize the memory with + + localparam int Aw = $clog2(Depth) +) ( + input logic clk_i, + input logic rst_ni, + input logic req_i, + input logic [Aw-1:0] addr_i, + output logic rvalid_o, + output logic [Width-1:0] rdata_o, + input rom_cfg_t cfg_i +); + + logic unused_signals; + assign unused_signals = ^{cfg_i}; + + // Data always comes in the next cycle after a request + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + rvalid_o <= 1'b0; + end else begin + rvalid_o <= req_i; + end + end + + if (MemInitFile != "") begin : gen_generic + + logic [Width-1:0] mem [Depth]; + + always_ff @(posedge clk_i) begin + if (req_i) begin + rdata_o <= mem[addr_i]; + end + end + + `include "prim_util_memload.svh" + end else begin : gen_xpm + xpm_memory_sprom #( + .ADDR_WIDTH_A(Aw), + .AUTO_SLEEP_TIME(0), + .CASCADE_HEIGHT(0), + .MEMORY_OPTIMIZATION("false"), + .MEMORY_SIZE(Width * Depth), + .READ_DATA_WIDTH_A(Width), + .READ_LATENCY_A(1), + .USE_MEM_INIT_MMI(1) + ) xpm_memory_sprom_inst ( + .clka(clk_i), + .rsta(1'b0), + .ena(req_i), + .addra(addr_i), + .douta(rdata_o), + .dbiterra(), + .sbiterra(), + .injectdbiterra(1'b0), + .injectsbiterra(1'b0), + .regcea(1'b1), + .sleep(1'b0) + ); + end + + + //////////////// + // ASSERTIONS // + //////////////// + + // Control Signals should never be X + `ASSERT(noXOnCsI, !$isunknown(req_i), clk_i, '0) +endmodule diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xnor2.sv b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xnor2.sv new file mode 100644 index 0000000000..659369adbf --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xnor2.sv @@ -0,0 +1,19 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`include "prim_assert.sv" + +// Prevent Vivado from performing optimizations on/across this module. +(* DONT_TOUCH = "yes" *) +module prim_xnor2 #( + parameter int Width = 1 +) ( + input [Width-1:0] in0_i, + input [Width-1:0] in1_i, + output logic [Width-1:0] out_o +); + + assign out_o = ~(in0_i ^ in1_i); + +endmodule diff --git a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_xor2.sv b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xor2.sv similarity index 94% rename from vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_xor2.sv rename to vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xor2.sv index 0eb9c14235..d00a027eec 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xilinx_xor2.sv +++ b/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_xor2.sv @@ -6,7 +6,7 @@ // Prevent Vivado from performing optimizations on/across this module. (* DONT_TOUCH = "yes" *) -module prim_xilinx_xor2 #( +module prim_xor2 #( parameter int Width = 1 ) ( input [Width-1:0] in0_i, diff --git a/vendor/lowrisc_ip/lint/README.md b/vendor/lowrisc_ip/lint/README.md index 55c5778400..9926da7fd8 100644 --- a/vendor/lowrisc_ip/lint/README.md +++ b/vendor/lowrisc_ip/lint/README.md @@ -90,7 +90,7 @@ The `purge` option ensures that the scratch directory is fully erased before sta Depending on the number of AscentLint licenses that can be checked out at a time, you may also want to set the number of parallel workers to one using `--max-parallel `. Batch regressions for all three tools are regularly run on the `master` branch at eight-hour intervals, and the results are published on a public dashboard such that everybody can inspect the current lint status of all IPs on the project website. -The dashboard can be found by following the appropriate link on the [hardware IP overview page](https://docs.opentitan.org/hw). +The dashboard can be found by following the appropriate link on the [hardware IP overview page](../). # CDC Linting diff --git a/vendor/lowrisc_ip/lint/common.core b/vendor/lowrisc_ip/lint/common.core index 20338eaf11..aa2ac3c36b 100644 --- a/vendor/lowrisc_ip/lint/common.core +++ b/vendor/lowrisc_ip/lint/common.core @@ -18,6 +18,7 @@ filesets: files_veriblelint: files: - tools/veriblelint/lowrisc-styleguide.rules.verible_lint: {file_type: veribleLintRules} + - tools/veriblelint/common.vbl: {file_type: veribleLintWaiver} files_check_tool_requirements: depend: diff --git a/vendor/lowrisc_ip/lint/sival_testplan_schema.hjson b/vendor/lowrisc_ip/lint/sival_testplan_schema.hjson new file mode 100644 index 0000000000..30ac9392a3 --- /dev/null +++ b/vendor/lowrisc_ip/lint/sival_testplan_schema.hjson @@ -0,0 +1,78 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "properties": { + "name": { + "type": "string" + }, + "additionalProperties": false, + "testpoints": { + "type": "array", + "items": { + "additionalProperties": false, + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "desc": { + "type": "string" + }, + "stage": { + "enum": ["V1", "V2", "V2S", "V3"] + }, + "si_stage": { + "enum": ["SV1", "SV2", "SV3", "SV4", "SV5", "NA", "None"] + }, + "bazel": { + "type": "array" + }, + "boot_stages": { + "type": "array", + "items": { + "enum": ["rom_ext", "silicon_owner"] + } + }, + "lc_states": { + "type": "array", + "items": { + "enum": ["PROD", "TEST_UNLOCKED", "RAW", "SCRAP", "TEST_LOCKED", + "TEST_LOCKED0", "DEV", "RMA", "TEST_UNLOCKED0", "PROD_END"] + } + }, + "features": { + "type": "array" + }, + "tests": { + "type": "array" + }, + "otp_mutate": { + "type": "boolean" + }, + "host_support": { + "type": "boolean" + }, + "tags": { + "type": "array" + } + }, + // If the si_stage is not tagged NA, then require the bazel property be present. + "if": { + "properties": { + "si_stage": { + "not": { + "const": "NA" + } + } + } + }, + "then": { + "required": ["bazel"] + }, + "required": ["name", "desc", "stage", "si_stage", "tests"] + } + } + } +} diff --git a/vendor/lowrisc_ip/lint/tools/dvsim/common_lint_cfg.hjson b/vendor/lowrisc_ip/lint/tools/dvsim/common_lint_cfg.hjson index 9ec23bdf9b..99cb5acae1 100644 --- a/vendor/lowrisc_ip/lint/tools/dvsim/common_lint_cfg.hjson +++ b/vendor/lowrisc_ip/lint/tools/dvsim/common_lint_cfg.hjson @@ -20,12 +20,13 @@ // We rely on fusesoc to run lint for us. build_cmd: "{job_prefix} fusesoc" - build_opts: ["--cores-root {proj_root}", + build_opts: ["--cores-root {proj_root}/hw", "run", - "--flag=fileset_{design_level}", "--target={flow}", "--tool={tool}", - "--build-root={build_dir}", + "--work-root={build_dir}/fusesoc-work", + "--mapping=lowrisc:prim_generic:all:0.1", + "{additional_fusesoc_argument}", "{fusesoc_core}"] // Determines which message severities to print into report summaries. diff --git a/vendor/lowrisc_ip/lint/tools/veriblelint/common.vbl b/vendor/lowrisc_ip/lint/tools/veriblelint/common.vbl new file mode 100644 index 0000000000..372c21e2a6 --- /dev/null +++ b/vendor/lowrisc_ip/lint/tools/veriblelint/common.vbl @@ -0,0 +1,6 @@ +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# + +waive --rule=line-length --location=".*ral_pkg.*" diff --git a/vendor/lowrisc_ip/util/dvsim/BUILD b/vendor/lowrisc_ip/util/dvsim/BUILD index d1f451661b..709aefb7e9 100644 --- a/vendor/lowrisc_ip/util/dvsim/BUILD +++ b/vendor/lowrisc_ip/util/dvsim/BUILD @@ -7,6 +7,14 @@ load("@ot_python_deps//:requirements.bzl", "requirement") package(default_visibility = ["//visibility:public"]) +filegroup( + name = "doc_files", + srcs = glob([ + "**/*.md", + "**/*.png", + ]), +) + py_library( name = "utils", srcs = ["utils.py"], diff --git a/vendor/lowrisc_ip/util/dvsim/Deploy.py b/vendor/lowrisc_ip/util/dvsim/Deploy.py index 8f28add084..126f28cd6b 100644 --- a/vendor/lowrisc_ip/util/dvsim/Deploy.py +++ b/vendor/lowrisc_ip/util/dvsim/Deploy.py @@ -137,7 +137,7 @@ def _set_attrs(self): """ self._extract_attrs(self.sim_cfg.__dict__) - # Enable GUI mode. + # Enable GUI mode, also when GUI debug mode has been invoked. self.gui = self.sim_cfg.gui # Output directory where the artifacts go (used by the launcher). @@ -188,7 +188,7 @@ def _subst_vars(self, ignored_subst_vars=[]): """Recursively search and replace substitution variables. First pass: search within self dict. We ignore errors since some - substitions may be available in the second pass. Second pass: search + substitutions may be available in the second pass. Second pass: search the entire sim_cfg object.""" self.__dict__ = find_and_substitute_wildcards(self.__dict__, @@ -242,7 +242,7 @@ def is_equivalent_job(self, item): the final resolved 'cmd' & the exports. The 'name' field will be unique to 'item' and 'self', so we take that out of the comparison. """ - if type(self) != type(item): + if not isinstance(item, Deploy): return False # Check if the cmd field is identical. @@ -566,7 +566,7 @@ def get_seed(): # first. If --fixed-seed is also passed, the subsequent tests # (once the custom seeds are consumed) will be run with the fixed seed. if not RunTest.seeds: - if RunTest.fixed_seed: + if RunTest.fixed_seed is not None: return RunTest.fixed_seed for i in range(1000): seed = random.getrandbits(256) diff --git a/vendor/lowrisc_ip/util/dvsim/FlowCfg.py b/vendor/lowrisc_ip/util/dvsim/FlowCfg.py index daeae87974..340cfad663 100644 --- a/vendor/lowrisc_ip/util/dvsim/FlowCfg.py +++ b/vendor/lowrisc_ip/util/dvsim/FlowCfg.py @@ -52,6 +52,9 @@ def __init__(self, flow_cfg_file, hjson_data, args, mk_config): self.branch = args.branch self.job_prefix = args.job_prefix self.gui = args.gui + self.gui_debug = args.gui_debug + if self.gui_debug: + self.gui = 1 self.interactive = args.interactive @@ -301,17 +304,17 @@ def _process_overrides(self): "Found this instead:\n%s", str(item)) sys.exit(1) - def _do_override(self, ov_name, ov_value): + def _do_override(self, ov_name: str, ov_value: object) -> None: # Go through self attributes and replace with overrides if hasattr(self, ov_name): orig_value = getattr(self, ov_name) - if type(orig_value) == type(ov_value): + if isinstance(ov_value, type(orig_value)): log.debug("Overriding \"%s\" value \"%s\" with \"%s\"", ov_name, orig_value, ov_value) setattr(self, ov_name, ov_value) else: log.error("The type of override value \"%s\" for \"%s\" " - "mismatches the type of original value \"%s\"", + "doesn't match the type of original value \"%s\"", ov_value, ov_name, orig_value) sys.exit(1) else: @@ -319,7 +322,7 @@ def _do_override(self, ov_name, ov_value): sys.exit(1) def _purge(self): - '''Purge the existing scratch areas in preperation for the new run.''' + '''Purge the existing scratch areas in preparation for the new run.''' return def purge(self): @@ -370,8 +373,8 @@ def create_deploy_objects(self): ''' self.prune_selected_cfgs() - # GUI or Interactive mode is allowed only for one cfg. - if (self.gui or self.interactive) and len(self.cfgs) > 1: + # GUI, GUI debug or Interactive mode is allowed only for one cfg. + if (self.gui or self.gui_debug or self.interactive) and len(self.cfgs) > 1: log.fatal("In GUI mode, only one cfg can be run.") sys.exit(1) diff --git a/vendor/lowrisc_ip/util/dvsim/Launcher.py b/vendor/lowrisc_ip/util/dvsim/Launcher.py index a483e94e67..e185048822 100644 --- a/vendor/lowrisc_ip/util/dvsim/Launcher.py +++ b/vendor/lowrisc_ip/util/dvsim/Launcher.py @@ -9,33 +9,37 @@ import re import sys from pathlib import Path +from typing import Union from utils import VERBOSE, clean_odirs, mk_symlink, rm_path class LauncherError(Exception): + def __init__(self, msg) -> None: + self.msg = msg + +class LauncherBusy(Exception): def __init__(self, msg): self.msg = msg class ErrorMessage( - collections.namedtuple( - 'ErrorMessage', - ['line_number', 'message', 'context'], - )): + collections.namedtuple( + "ErrorMessage", + ["line_number", "message", "context"], + ), +): """Contains error-related information. This support classification of failures into buckets. The message field is used to generate the bucket, and context contains a list of lines in the failing log that can be useful for quick diagnostics. """ - pass class Launcher: - """ - Abstraction for launching and maintaining a job. + """Abstraction for launching and maintaining a job. An abstract class that provides methods to prepare a job's environment, launch the job, poll for its completion and finally do some cleanup @@ -76,11 +80,12 @@ class Launcher: fail_msg = ErrorMessage( line_number=None, message="Job killed most likely because its dependent job failed.", - context=[]) + context=[], + ) @staticmethod - def set_pyvenv(project): - '''Activate a python virtualenv if available. + def set_pyvenv(project) -> None: + """Activate a python virtualenv if available. The env variable _PYTHON_VENV if set, points to the path containing the python virtualenv created specifically for this @@ -88,8 +93,7 @@ def set_pyvenv(project): external compute machines. This is not applicable when running jobs locally on the user's machine. - ''' - + """ if Launcher.pyvenv is not None: return @@ -102,37 +106,35 @@ def set_pyvenv(project): # The code below allows each launcher variant to set its own virtualenv # because the loading / activating mechanism could be different between # them. - Launcher.pyvenv = os.environ.get("{}_PYVENV_{}".format( - project.upper(), Launcher.variant.upper())) + Launcher.pyvenv = os.environ.get( + f"{project.upper()}_PYVENV_{Launcher.variant.upper()}", + ) if not Launcher.pyvenv: - Launcher.pyvenv = os.environ.get("{}_PYVENV".format( - project.upper())) + Launcher.pyvenv = os.environ.get(f"{project.upper()}_PYVENV") @staticmethod - def prepare_workspace(project, repo_top, args): - '''Prepare the workspace based on the chosen launcher's needs. + def prepare_workspace(project, repo_top, args) -> None: + """Prepare the workspace based on the chosen launcher's needs. This is done once for the entire duration for the flow run. 'project' is the name of the project. 'repo_top' is the path to the repository. 'args' are the command line args passed to dvsim. - ''' - pass + """ @staticmethod - def prepare_workspace_for_cfg(cfg): - '''Prepare the workspace for a cfg. + def prepare_workspace_for_cfg(cfg) -> None: + """Prepare the workspace for a cfg. This is invoked once for each cfg. 'cfg' is the flow configuration object. - ''' - pass + """ - def __str__(self): + def __str__(self) -> str: return self.deploy.full_name + ":launcher" - def __init__(self, deploy): + def __init__(self, deploy) -> None: cfg = deploy.sim_cfg # One-time preparation of the workspace. @@ -167,78 +169,72 @@ def __init__(self, deploy): # The actual job runtime computed by dvsim, in seconds. self.job_runtime_secs = 0 - def _make_odir(self): + def _make_odir(self) -> None: """Create the output directory.""" - # If renew_odir flag is True - then move it. if self.renew_odir: clean_odirs(odir=self.deploy.odir, max_odirs=self.max_odirs) os.makedirs(self.deploy.odir, exist_ok=True) - def _link_odir(self, status): + def _link_odir(self, status) -> None: """Soft-links the job's directory based on job's status. The dispatched, passed and failed directories in the scratch area provide a quick way to get to the job that was executed. """ - dest = Path(self.deploy.sim_cfg.links[status], self.deploy.qual_name) mk_symlink(self.deploy.odir, dest) # Delete the symlink from dispatched directory if it exists. if status != "D": - old = Path(self.deploy.sim_cfg.links['D'], self.deploy.qual_name) + old = Path(self.deploy.sim_cfg.links["D"], self.deploy.qual_name) rm_path(old) - def _dump_env_vars(self, exports): + def _dump_env_vars(self, exports) -> None: """Write env vars to a file for ease of debug. Each extended class computes the list of exports and invokes this method right before launching the job. """ - - with open(self.deploy.odir + "/env_vars", - "w", - encoding="UTF-8", - errors="surrogateescape") as f: + with open( + self.deploy.odir + "/env_vars", + "w", + encoding="UTF-8", + errors="surrogateescape", + ) as f: for var in sorted(exports.keys()): - f.write("{}={}\n".format(var, exports[var])) + f.write(f"{var}={exports[var]}\n") - def _pre_launch(self): + def _pre_launch(self) -> None: """Do pre-launch activities. Examples include such as preparing the job's environment, clearing old runs, creating the output directory, dumping all env variables etc. This method is already invoked by launch() as the first step. """ - self.deploy.pre_launch() self._make_odir() self.start_time = datetime.datetime.now() - def _do_launch(self): + def _do_launch(self) -> None: """Launch the job.""" + raise NotImplementedError - raise NotImplementedError() - - def launch(self): + def launch(self) -> None: """Launch the job.""" - self._pre_launch() self._do_launch() - def poll(self): + def poll(self) -> Union[str, None]: """Poll the launched job for completion. Invokes _check_status() and _post_finish() when the job completes. """ + raise NotImplementedError - raise NotImplementedError() - - def kill(self): + def kill(self) -> None: """Terminate the job.""" - - raise NotImplementedError() + raise NotImplementedError def _check_status(self): """Determine the outcome of the job (P/F if it ran to completion). @@ -251,11 +247,11 @@ def _check_status(self): def _find_patterns(patterns, line): """Helper function that returns the pattern if any of the given - patterns is found, else None.""" - + patterns is found, else None. + """ assert patterns for pattern in patterns: - match = re.search(r"{}".format(pattern), line) + match = re.search(rf"{pattern}", line) if match: return pattern return None @@ -272,16 +268,16 @@ def _find_patterns(patterns, line): chk_passed = bool(pass_patterns) and (self.exit_code == 0) try: - with open(self.deploy.get_log_path(), - "r", - encoding="UTF-8", - errors="surrogateescape") as f: + with open( + self.deploy.get_log_path(), + encoding="UTF-8", + errors="surrogateescape", + ) as f: lines = f.readlines() except OSError as e: return "F", ErrorMessage( line_number=None, - message="Error opening file {}:\n{}".format( - self.deploy.get_log_path(), e), + message=f"Error opening file {self.deploy.get_log_path()}:\n{e}", context=[], ) @@ -292,13 +288,15 @@ def _find_patterns(patterns, line): if chk_failed or chk_passed: for cnt, line in enumerate(lines): - if chk_failed: - if _find_patterns(self.deploy.fail_patterns, line): - # If failed, then nothing else to do. Just return. - # Provide some extra lines for context. - return "F", ErrorMessage(line_number=cnt + 1, - message=line.strip(), - context=lines[cnt:cnt + 5]) + if chk_failed and _find_patterns(self.deploy.fail_patterns, line): + # If failed, then nothing else to do. Just return. + # Provide some extra lines for context. + end = cnt + 5 + return "F", ErrorMessage( + line_number=cnt + 1, + message=line.strip(), + context=lines[cnt:end], + ) if chk_passed: pattern = _find_patterns(pass_patterns, line) @@ -310,9 +308,11 @@ def _find_patterns(patterns, line): # exit code for whatever reason, then show the last 10 lines of the log # as the failure message, which might help with the debug. if self.exit_code != 0: - return "F", ErrorMessage(line_number=None, - message="Job returned non-zero exit code", - context=lines[-10:]) + return "F", ErrorMessage( + line_number=None, + message="Job returned non-zero exit code", + context=lines[-10:], + ) if chk_passed: return "F", ErrorMessage( line_number=None, @@ -321,7 +321,7 @@ def _find_patterns(patterns, line): ) return "P", None - def _post_finish(self, status, err_msg): + def _post_finish(self, status, err_msg) -> None: """Do post-completion activities, such as preparing the results. Must be invoked by poll(), after the job outcome is determined. @@ -329,8 +329,7 @@ def _post_finish(self, status, err_msg): status is the status of the job, either 'P', 'F' or 'K'. err_msg is an instance of the named tuple ErrorMessage. """ - - assert status in ['P', 'F', 'K'] + assert status in ["P", "F", "K"] self._link_odir(status) log.debug("Item %s has completed execution: %s", self, status) @@ -343,12 +342,15 @@ def _post_finish(self, status, err_msg): # cleanup task failed, then mark the job as failed. if status == "P": status = "F" - err_msg = ErrorMessage(line_number=None, - message=f"{e}", - context=[f"{e}"]) + err_msg = ErrorMessage( + line_number=None, + message=f"{e}", + context=[f"{e}"], + ) self.status = status if self.status != "P": - assert err_msg and isinstance(err_msg, ErrorMessage) + assert err_msg + assert isinstance(err_msg, ErrorMessage) self.fail_msg = err_msg log.log(VERBOSE, err_msg.message) diff --git a/vendor/lowrisc_ip/util/dvsim/LauncherFactory.py b/vendor/lowrisc_ip/util/dvsim/LauncherFactory.py index cac498d045..cf8da8d58a 100644 --- a/vendor/lowrisc_ip/util/dvsim/LauncherFactory.py +++ b/vendor/lowrisc_ip/util/dvsim/LauncherFactory.py @@ -9,6 +9,8 @@ from LocalLauncher import LocalLauncher from LsfLauncher import LsfLauncher from SgeLauncher import SgeLauncher +from SlurmLauncher import SlurmLauncher +from NcLauncher import NcLauncher try: from edacloudlauncher.EdaCloudLauncher import EdaCloudLauncher @@ -45,6 +47,12 @@ def set_launcher_type(is_local=False): elif launcher == "sge": _LAUNCHER_CLS = SgeLauncher + elif launcher == "nc": + _LAUNCHER_CLS = NcLauncher + + elif launcher == "slurm": + _LAUNCHER_CLS = SlurmLauncher + # These custom launchers are site specific. They may not be committed to # the open source repo. elif launcher == "edacloud" and EDACLOUD_LAUNCHER_EXISTS: diff --git a/vendor/lowrisc_ip/util/dvsim/LintCfg.py b/vendor/lowrisc_ip/util/dvsim/LintCfg.py index ced749083a..f7aea3d661 100644 --- a/vendor/lowrisc_ip/util/dvsim/LintCfg.py +++ b/vendor/lowrisc_ip/util/dvsim/LintCfg.py @@ -34,6 +34,10 @@ def __init__(self, flow_cfg_file, hjson_data, args, mk_config): # Message bucket format configuration # Format: [{category: str, severity: str, label: str}, ...] self.message_buckets = [] + # This key is used as a wildcard to place an additional + # fusesoc argument before the name of the core to invoke. + # Format: str + self.additional_fusesoc_argument = '' super().__init__(flow_cfg_file, hjson_data, args, mk_config) diff --git a/vendor/lowrisc_ip/util/dvsim/LocalLauncher.py b/vendor/lowrisc_ip/util/dvsim/LocalLauncher.py index 670cc5ba55..03802329ac 100644 --- a/vendor/lowrisc_ip/util/dvsim/LocalLauncher.py +++ b/vendor/lowrisc_ip/util/dvsim/LocalLauncher.py @@ -1,92 +1,102 @@ # Copyright lowRISC contributors (OpenTitan project). # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 +"""Launcher implementation to run jobs as subprocesses on the local machine.""" import datetime import os import shlex import subprocess +from pathlib import Path +from typing import Union -from Launcher import ErrorMessage, Launcher, LauncherError +from Launcher import ErrorMessage, Launcher, LauncherBusy, LauncherError class LocalLauncher(Launcher): - """ - Implementation of Launcher to launch jobs in the user's local workstation. - """ - - def __init__(self, deploy): - '''Initialize common class members.''' + """Implementation of Launcher to launch jobs in the user's local workstation.""" + def __init__(self, deploy) -> None: + """Initialize common class members.""" super().__init__(deploy) # Popen object when launching the job. - self.process = None + self._process = None + self._log_file = None - def _do_launch(self): + def _do_launch(self) -> None: # 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() - if self.deploy.exports: - exports.update(self.deploy.exports) + exports.update(self.deploy.exports) # Clear the magic MAKEFLAGS variable from exports if necessary. This # variable is used by recursive Make calls to pass variables from one # level to the next. Here, self.cmd is a call to Make but it's # logically a top-level invocation: we don't want to pollute the flow's # Makefile with Make variables from any wrapper that called dvsim. - if 'MAKEFLAGS' in exports: - del exports['MAKEFLAGS'] + if "MAKEFLAGS" in exports: + del exports["MAKEFLAGS"] self._dump_env_vars(exports) if not self.deploy.sim_cfg.interactive: + log_path = Path(self.deploy.get_log_path()) + timeout_mins = self.deploy.get_timeout_mins() + + self.timeout_secs = timeout_mins * 60 if timeout_mins else None + try: - f = open(self.deploy.get_log_path(), - "w", - encoding="UTF-8", - errors="surrogateescape") - f.write("[Executing]:\n{}\n\n".format(self.deploy.cmd)) - f.flush() - timeout_mins = self.deploy.get_timeout_mins() - if timeout_mins: - self.timeout_secs = timeout_mins * 60 - else: - self.timeout_secs = None - self.process = subprocess.Popen(shlex.split(self.deploy.cmd), - bufsize=4096, - universal_newlines=True, - stdout=f, - stderr=f, - env=exports) + self._log_file = log_path.open( + "w", + encoding="UTF-8", + errors="surrogateescape", + ) + self._log_file.write(f"[Executing]:\n{self.deploy.cmd}\n\n") + self._log_file.flush() + + self._process = subprocess.Popen( + shlex.split(self.deploy.cmd), + bufsize=4096, + universal_newlines=True, + stdout=self._log_file, + stderr=self._log_file, + env=exports, + ) + + except BlockingIOError as e: + raise LauncherBusy(f"Failed to launch job: {e}") from e + except subprocess.SubprocessError as e: - raise LauncherError('IO Error: {}\nSee {}'.format( - e, self.deploy.get_log_path())) + raise LauncherError(f"IO Error: {e}\nSee {log_path}") from e + finally: - self._close_process() + self._close_job_log_file() else: # Interactive: Set RUN_INTERACTIVE to 1 - exports['RUN_INTERACTIVE'] = "1" + exports["RUN_INTERACTIVE"] = "1" # Interactive. stdin / stdout are transparent # no timeout and blocking op as user controls the flow print("Interactive mode is not supported yet.") - print("Cmd : {}".format(self.deploy.cmd)) - self.process = subprocess.Popen(shlex.split(self.deploy.cmd), - stdin=None, - stdout=None, - stderr=subprocess.STDOUT, - # string mode - universal_newlines=True, - env=exports) + print(f"Cmd : {self.deploy.cmd}") + self._process = subprocess.Popen( + shlex.split(self.deploy.cmd), + stdin=None, + stdout=None, + stderr=subprocess.STDOUT, + # string mode + universal_newlines=True, + env=exports, + ) # Wait until the process exit - self.process.wait() + self._process.wait() self._link_odir("D") - def poll(self): - '''Check status of the running process + def poll(self) -> Union[str, None]: + """Check status of the running process. This returns 'D', 'P', 'F', or 'K'. If 'D', the job is still running. If 'P', the job finished successfully. If 'F', the job finished with @@ -94,64 +104,73 @@ def poll(self): This function must only be called after running self.dispatch_cmd() and must not be called again once it has returned 'P' or 'F'. - ''' + """ + if self._process is None: + return "E" - assert self.process is not None elapsed_time = datetime.datetime.now() - self.start_time self.job_runtime_secs = elapsed_time.total_seconds() - if self.process.poll() is None: - if self.timeout_secs and (self.job_runtime_secs > - self.timeout_secs) and not self.deploy.gui: + if self._process.poll() is None: + if ( + self.timeout_secs + and (self.job_runtime_secs > self.timeout_secs) # noqa: W503 + and not (self.deploy.gui) # noqa: W503 + ): self._kill() - timeout_message = 'Job timed out after {} minutes'.format( - self.deploy.get_timeout_mins()) + timeout_mins = self.deploy.get_timeout_mins() + timeout_message = f"Job timed out after {timeout_mins} minutes" self._post_finish( - 'K', - ErrorMessage(line_number=None, - message=timeout_message, - context=[timeout_message])) - return 'K' - - return 'D' - - self.exit_code = self.process.returncode + "K", + ErrorMessage( + line_number=None, + message=timeout_message, + context=[timeout_message], + ), + ) + return "K" + + return "D" + + self.exit_code = self._process.returncode status, err_msg = self._check_status() self._post_finish(status, err_msg) + return self.status - def _kill(self): - '''Kill the running process. + def _kill(self) -> None: + """Kill the running process. Try to kill the running process. Send SIGTERM first, wait a bit, and then send SIGKILL if it didn't work. - ''' - assert self.process is not None - self.process.terminate() + """ + if self._process is None: + # process already dead or didn't start + return + + self._process.terminate() try: - self.process.wait(timeout=2) + self._process.wait(timeout=2) except subprocess.TimeoutExpired: - self.process.kill() + self._process.kill() - def kill(self): - '''Kill the running process. + def kill(self) -> None: + """Kill the running process. This must be called between dispatching and reaping the process (the same window as poll()). - - ''' + """ self._kill() self._post_finish( - 'K', - ErrorMessage(line_number=None, message='Job killed!', context=[])) + "K", + ErrorMessage(line_number=None, message="Job killed!", context=[]), + ) - def _post_finish(self, status, err_msg): - self._close_process() - self.process = None + def _post_finish(self, status: str, err_msg: Union[ErrorMessage, None]) -> None: + self._close_job_log_file() + self._process = None super()._post_finish(status, err_msg) - def _close_process(self): - '''Close the file descriptors associated with the process.''' - - assert self.process - if self.process.stdout: - self.process.stdout.close() + def _close_job_log_file(self) -> None: + """Close the file descriptors associated with the process.""" + if self._log_file: + self._log_file.close() diff --git a/vendor/lowrisc_ip/util/dvsim/LsfLauncher.py b/vendor/lowrisc_ip/util/dvsim/LsfLauncher.py index 2260a01752..18d65bf31e 100644 --- a/vendor/lowrisc_ip/util/dvsim/LsfLauncher.py +++ b/vendor/lowrisc_ip/util/dvsim/LsfLauncher.py @@ -160,8 +160,7 @@ def _do_launch(self): # 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() - if self.deploy.exports: - exports.update(self.deploy.exports) + exports.update(self.deploy.exports) # Clear the magic MAKEFLAGS variable from exports if necessary. This # variable is used by recursive Make calls to pass variables from one @@ -279,7 +278,7 @@ def poll(self): # so that we can report the status accurately. # # At this point, we could run bjobs or bhist to determine the status, - # but it has been found to be too slow, expecially when running 1000s + # but it has been found to be too slow, especially when running 1000s # of jobs. Plus, we have to read the job script output anyway to look # for those error messages. # diff --git a/vendor/lowrisc_ip/util/dvsim/NcLauncher.py b/vendor/lowrisc_ip/util/dvsim/NcLauncher.py new file mode 100755 index 0000000000..f7cefdbb63 --- /dev/null +++ b/vendor/lowrisc_ip/util/dvsim/NcLauncher.py @@ -0,0 +1,257 @@ +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +import datetime +import logging as log +import os +import subprocess +import sys +from Launcher import ErrorMessage +from Launcher import Launcher +from Launcher import LauncherError +from utils import rm_path +from utils import VERBOSE + + +class NcLauncher(Launcher): + """Implementation of Launcher to launch jobs using altair nc.""" + + def __init__(self, deploy): + """Initialize common class members.""" + + super().__init__(deploy) + + # Popen object when launching the job. + self.process = None + + def create_run_sh(self, full_path, cmd): + run_file = os.path.join(full_path, 'run.sh') + rm_path(run_file) + lines = ['#!/bin/sh', + 'function realpath {', + ' python -c "import os; print (os.path.realpath(\'$1\'))"', + '}', + 'MY_FILEPATH=$(realpath "${BASH_SOURCE[0]}")', + 'MY_DIR=$( dirname "${MY_FILEPATH}" )', + 'cd $MY_DIR', + 'export TMPDIR=$PWD/tmp', + 'mkdir -p $TMPDIR', + 'echo Launch start : `date`', + 'SECONDS=0', + cmd, + 'echo Launch end : `date`', + 'echo CPU time : $SECONDS sec'] + with open(run_file, 'w') as f: + f.write('\n'.join(lines)) + os.chmod(run_file, 0o755) + + def get_submit_cmd(self): + exetool = self.deploy.sim_cfg.tool + job_name = self.deploy.full_name + cmd = self.deploy.cmd + odir = self.deploy.odir + + # TODO: These tool-specific names need moving into an hjson config + # file. + if (exetool == 'xcelium'): + license_args = ['-r', 'License:Xcelium_Single_Core/1'] + elif (exetool == 'vcs'): + license_args = ['-r', 'License:VCSRuntime_Net/1'] + else: + license_args = [] + license_args.extend(['-r', 'RAM/8192', '-r', 'CORES/2']) + + self.create_run_sh(odir, cmd) + + return (['nc', 'run', '-D', + '-e', 'SNAPSHOT', + '-nodb', '-nolog', '-wl', + '-set', job_name] + + license_args + + ['--', f'{odir}/run.sh']) + + def _pre_launch(self): + # store the start_time (corresponding to job wait time counter) + super()._pre_launch() + # set the nc_job_state to the initial state - waiting for resource + self.nc_job_state = 'waiting' + + def _do_launch(self): + # Compute the environment for the subprocess by overriding environment + # variables of this process with matching ones from self.deploy.exports + exports = os.environ.copy() + exports.update(self.deploy.exports) + + # Clear the magic MAKEFLAGS variable from exports if necessary. This + # variable is used by recursive Make calls to pass variables from one + # level to the next. Here, self.cmd is a call to Make but it's + # logically a top-level invocation: we don't want to pollute the flow's + # Makefile with Make variables from any wrapper that called dvsim. + if 'MAKEFLAGS' in exports: + del exports['MAKEFLAGS'] + + self._dump_env_vars(exports) + + # For reruns, delete the log file of the past run to avoid any race + # condition between the log file getting updated for the new run + # versus the logic that distinguishes the job wait versus run times. + rm_path(self.deploy.get_log_path()) + # using os.open instead of fopen as this allows + # sharing of file descriptors across processes + fd = os.open(self.deploy.get_log_path(), os.O_WRONLY | os.O_CREAT) + fobj = os.fdopen(fd, 'w', encoding='UTF-8') + os.set_inheritable(fd, True) + message = '[Executing]:\n{}\n\n'.format(self.deploy.cmd) + fobj.write(message) + fobj.flush() + if self.deploy.sim_cfg.interactive: + # Interactive: Set RUN_INTERACTIVE to 1 + exports['RUN_INTERACTIVE'] = '1' + # Line buffering (buf_size = 1) chosen to enable + # near real time updates from the tool + buf_size = 1 + std_out = subprocess.PIPE + std_err = subprocess.STDOUT + else: + # setting buf_size = -1 enables subprocess to choose + # the default buffer size which is more efficient + buf_size = -1 + std_out = fd + std_err = fd + + cmd_arr = self.get_submit_cmd() + log.log(VERBOSE, '[Submitting]:\n{}\n\n'.format(' '.join(cmd_arr))) + + try: + self.process = subprocess.Popen(cmd_arr, + bufsize=buf_size, + universal_newlines=True, + pass_fds = [fd], + stdout=std_out, + stderr=std_err, + env=exports, + cwd=self.deploy.odir) + if self.deploy.sim_cfg.interactive: + for line in self.process.stdout: + fobj.write(line) + sys.stdout.write(line) + # Wait until the process exits in case + # the subprocess closes the stdout but still keeps running + self.process.wait() + except subprocess.SubprocessError as e: + raise LauncherError(f'IO Error: {e}\n' + f'See {self.deploy.get_log_path()}') + finally: + self._close_process() + + self._link_odir('D') + + def minutes_since_start(self): + return (datetime.datetime.now() - self.start_time).total_seconds() / 60 + + def poll(self): + """Check status of the running process. + + This returns 'D', 'P', 'F', or 'K'. If 'D', the job is still running. + If 'P', the job finished successfully. If 'F', the job finished with + an error. If 'K' it was killed. + + This function must only be called after running self.dispatch_cmd() and + must not be called again once it has returned 'P' or 'F'. + """ + + assert self.process is not None + if self.process.poll() is None: + run_timeout_mins = self.deploy.get_timeout_mins() + if run_timeout_mins is not None and not self.deploy.gui: + wait_timeout_mins = 180 # max wait time in job / license queue + # We consider the job to have started once its log file contains + # something. file_size_thresh_bytes is a threshold: once the log + # file is bigger than this many bytes, the job must have started + file_size_thresh_bytes = 5120 # log file size threshold + + # query the log file size + f_size = os.path.getsize(self.deploy.get_log_path()) + + if f_size >= file_size_thresh_bytes: + if (self.nc_job_state == 'waiting'): + # If the job log size is more than the threshold, + # declare the job to have started running + # capture the run start time + self.start_time = datetime.datetime.now() + self.nc_job_state = 'running' + + if self.nc_job_state == 'waiting': + # If we get here, we know the log size is less than the threshold. + # check if wait_timeout_mins has elapsed. + if self.minutes_since_start() > wait_timeout_mins: + self.nc_job_state = 'wait_timeout' + + if self.nc_job_state == 'running': + if self.minutes_since_start() > run_timeout_mins: + self.nc_job_state = 'run_timeout' + + if self.nc_job_state in {'wait_timeout', 'run_timeout'}: + self._kill() + if self.nc_job_state == 'run_timeout': + timeout_message = f'Job timed out after running ' \ + f'{run_timeout_mins} mins' + elif self.nc_job_state == 'wait_timeout': + timeout_message = f'Job timed out after waiting ' \ + f'{wait_timeout_mins} mins' + self._post_finish('K', + ErrorMessage(line_number=None, + message=timeout_message, + context=[timeout_message])) + return 'K' + else: + return 'D' + else: + return 'D' + + self.exit_code = self.process.returncode + status, err_msg = self._check_status() + self._post_finish(status, err_msg) + return self.status + + def _kill(self): + """Kill the running process. + + Try to kill the running process. Send SIGTERM + and SIGKILL. + """ + try: + log.log(VERBOSE, f'[Stopping] : {self.deploy.full_name}') + subprocess.run(['nc', 'stop', '-set', self.deploy.full_name, + '-sig', 'TERM,KILL'], + check=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + except subprocess.CalledProcessError as e: + log.error('Failed to kill job: {}'.format( + e.stderr.decode('utf-8').strip())) + + def kill(self): + """Kill the running process. + + This must be called between dispatching and reaping the process (the + same window as poll()). + + """ + self._kill() + self._post_finish( + 'K', + ErrorMessage(line_number=None, message='Job killed!', context=[])) + + def _post_finish(self, status, err_msg): + self._close_process() + self.process = None + super()._post_finish(status, err_msg) + + def _close_process(self): + """Close the file descriptors associated with the process.""" + + assert self.process + if self.process.stdout: + self.process.stdout.close() diff --git a/vendor/lowrisc_ip/util/dvsim/README.md b/vendor/lowrisc_ip/util/dvsim/README.md index 357d52729b..f248a76abd 100644 --- a/vendor/lowrisc_ip/util/dvsim/README.md +++ b/vendor/lowrisc_ip/util/dvsim/README.md @@ -1,4 +1,4 @@ -## DVSim +# DVSim DVSim is a build and run system written in Python that runs a variety of EDA tool flows. There are multiple steps involved in running EDA tool flows. @@ -16,7 +16,7 @@ The following flows are currently supported: * CDC * RDC -# Installation +## Installation Clone the OpenTitan repository by following the [Getting Started](../../doc/getting_started/README.md) steps. The rest of the documentation will assume `$REPO_TOP` as the root of the local OpenTitan repository. @@ -37,12 +37,12 @@ python3 -m pip install --user -r $REPO_TOP/python-requirements.txt Note that you may have already done this if you followed the getting started steps. -# Other related documents +## Other related documents * [Testplanner tool](./doc/testplanner.md) * [Design document](./doc/design_doc.md) * [Glossary](./doc/glossary.md) -# Bugs +## Bugs Please see [link](https://github.com/lowRISC/opentitan/issues?q=is%3Aopen+is%3Aissue+label%3ATool%3Advsim) for a list of open bugs and feature requests. diff --git a/vendor/lowrisc_ip/util/dvsim/Regression.py b/vendor/lowrisc_ip/util/dvsim/Regression.py index 652f965fff..3882702252 100644 --- a/vendor/lowrisc_ip/util/dvsim/Regression.py +++ b/vendor/lowrisc_ip/util/dvsim/Regression.py @@ -2,7 +2,7 @@ # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -from modes import Mode, find_mode, find_and_merge_modes +from modes import Mode, find_mode, find_mode_list from Test import Test import logging as log @@ -20,7 +20,6 @@ class Regression(Mode): def __init__(self, regdict): self.name = "" - self.type = "" # The `tests` member is typically a list, but it defaults to None. # There are 3 possible cases after all the HJson files are parsed, when @@ -84,11 +83,8 @@ def create_regressions(regdicts, sim_cfg, tests): for regression_obj in regression_objs: # Unpack the sim modes - found_sim_mode_objs = find_and_merge_modes( - regression_obj, regression_obj.en_sim_modes, build_modes, - False) - - for sim_mode_obj in found_sim_mode_objs: + for sim_mode_obj in find_mode_list(regression_obj.en_sim_modes, + build_modes): if sim_mode_obj.is_sim_mode == 0: log.error( "Enabled mode \"%s\" within the regression \"%s\" is not a sim mode", @@ -125,12 +121,11 @@ def create_regressions(regdicts, sim_cfg, tests): # Unpack the run_modes # TODO: If there are other params other than run_opts throw an # error and exit - found_run_mode_objs = find_and_merge_modes( - regression_obj, regression_obj.en_run_modes, run_modes, False) # Only merge the pre_run_cmds, post_run_cmds & run_opts from the # run_modes enabled - for run_mode_obj in found_run_mode_objs: + for run_mode_obj in find_mode_list(regression_obj.en_run_modes, + run_modes): # Check if run_mode_obj is also passed on the command line, in # which case, skip if run_mode_obj.name in sim_cfg.en_run_modes: diff --git a/vendor/lowrisc_ip/util/dvsim/Scheduler.py b/vendor/lowrisc_ip/util/dvsim/Scheduler.py index 2f767ad75c..382eb1f550 100644 --- a/vendor/lowrisc_ip/util/dvsim/Scheduler.py +++ b/vendor/lowrisc_ip/util/dvsim/Scheduler.py @@ -6,21 +6,22 @@ import threading from signal import SIGINT, SIGTERM, signal -from Launcher import LauncherError +from Launcher import LauncherBusy, LauncherError from StatusPrinter import get_status_printer from Timer import Timer from utils import VERBOSE -# Sum of lenghts of all lists in the given dict. +# Sum of lengths of all lists in the given dict. def sum_dict_lists(d): - '''Given a dict whose key values are lists, return sum of lengths of - thoese lists.''' + """Given a dict whose key values are lists, return sum of lengths of + these lists. + """ return sum([len(d[k]) for k in d]) def get_next_item(arr, index): - '''Perpetually get an item from a list. + """Perpetually get an item from a list. Returns the next item on the list by advancing the index by 1. If the index is already the last item on the list, it loops back to the start, thus @@ -31,7 +32,7 @@ def get_next_item(arr, index): Returns (item, index) if successful. Raises IndexError if arr is empty. - ''' + """ index += 1 try: item = arr[index] @@ -46,7 +47,7 @@ def get_next_item(arr, index): class Scheduler: - '''An object that runs one or more Deploy items''' + """An object that runs one or more Deploy items.""" def __init__(self, items, launcher_cls, interactive): self.items = items @@ -63,8 +64,8 @@ def __init__(self, items, launcher_cls, interactive): # Print status periodically using an external status printer. self.status_printer = get_status_printer(interactive) self.status_printer.print_header( - msg="Q: queued, D: dispatched, P: passed, F: failed, K: killed, " - "T: total") + msg="Q: queued, D: dispatched, P: passed, F: failed, K: killed, T: total", + ) # Sets of items, split up by their current state. The sets are # disjoint and their union equals the keys of self.item_to_status. @@ -97,9 +98,11 @@ def __init__(self, items, launcher_cls, interactive): # Stuff for printing the status. width = len(str(self._total[target])) - field_fmt = '{{:0{}d}}'.format(width) - self.msg_fmt = 'Q: {0}, D: {0}, P: {0}, F: {0}, K: {0}, T: {0}'.format( - field_fmt) + field_fmt = f"{{:0{width}d}}" + self.msg_fmt = ( + f"Q: {field_fmt}, D: {field_fmt}, P: {field_fmt}, " + f"F: {field_fmt}, K: {field_fmt}, T: {field_fmt}" + ) msg = self.msg_fmt.format(0, 0, 0, 0, 0, self._total[target]) self.status_printer.init_target(target=target, msg=msg) @@ -118,12 +121,11 @@ def __init__(self, items, launcher_cls, interactive): self.launcher_cls = launcher_cls def run(self): - '''Run all scheduled jobs and return the results. + """Run all scheduled jobs and return the results. Returns the results (status) of all items dispatched for all targets and cfgs. - ''' - + """ timer = Timer() # Catch one SIGINT and tell the runner to quit. On a second, die. @@ -131,12 +133,16 @@ def run(self): old_handler = None def on_signal(signal_received, frame): - log.info("Received signal %s. Exiting gracefully.", - signal_received) + log.info( + "Received signal %s. Exiting gracefully.", + signal_received, + ) if signal_received == SIGINT: - log.info('Send another to force immediate quit (but you may ' - 'need to manually kill child processes)') + log.info( + "Send another to force immediate quit (but you may " + "need to manually kill child processes)", + ) # Restore old handler to catch a second SIGINT assert old_handler is not None @@ -181,11 +187,10 @@ def on_signal(signal_received, frame): return self.item_to_status def add_to_scheduled(self, items): - '''Add items to the list of _scheduled. + """Add items to the list of _scheduled. 'items' is a list of Deploy objects. - ''' - + """ for item in items: target_dict = self._scheduled.setdefault(item.target, {}) cfg_list = target_dict.setdefault(item.sim_cfg, []) @@ -193,11 +198,11 @@ def add_to_scheduled(self, items): cfg_list.append(item) def _remove_from_scheduled(self, item): - '''Removes the item from _scheduled[target][cfg] list. + """Removes the item from _scheduled[target][cfg] list. When all items in _scheduled[target][cfg] are finally removed, the cfg key is deleted. - ''' + """ target_dict = self._scheduled[item.target] cfg_list = target_dict.get(item.sim_cfg) if cfg_list is not None: @@ -209,12 +214,11 @@ def _remove_from_scheduled(self, item): del target_dict[item.sim_cfg] def _get_next_target(self, curr_target): - '''Returns the target that succeeds the current one. + """Returns the target that succeeds the current one. curr_target is the target of the job that just completed (example - build). If it is None, then the first target in _scheduled is returned. - ''' - + """ if curr_target is None: return next(iter(self._scheduled)) @@ -234,25 +238,24 @@ def _get_next_target(self, curr_target): return target def _enqueue_successors(self, item=None): - '''Move an item's successors from _scheduled to _queued. + """Move an item's successors from _scheduled to _queued. 'item' is the recently run job that has completed. If None, then we move all available items in all available cfgs in _scheduled's first target. If 'item' is specified, then we find its successors and move them to _queued. - ''' - + """ for next_item in self._get_successors(item): assert next_item not in self.item_to_status assert next_item not in self._queued[next_item.target] - self.item_to_status[next_item] = 'Q' + self.item_to_status[next_item] = "Q" self._queued[next_item.target].append(next_item) self._remove_from_scheduled(next_item) def _cancel_successors(self, item): - '''Cancel an item's successors recursively by moving them from - _scheduled or _queued to _killed.''' - + """Cancel an item's successors recursively by moving them from + _scheduled or _queued to _killed. + """ items = self._get_successors(item) while items: next_item = items.pop() @@ -260,7 +263,7 @@ def _cancel_successors(self, item): items.extend(self._get_successors(next_item)) def _get_successors(self, item=None): - '''Find immediate successors of an item. + """Find immediate successors of an item. 'item' is a job that has completed. We choose the target that follows the 'item''s current target and find the list of successors whose @@ -270,8 +273,7 @@ def _get_successors(self, item=None): Returns the list of item's successors, or an empty list if there are none. - ''' - + """ if item is None: target = self._get_next_target(None) cfgs = set(self._scheduled[target]) @@ -301,8 +303,7 @@ def _get_successors(self, item=None): return successors def _ok_to_enqueue(self, item): - '''Returns true if ALL dependencies of item are complete.''' - + """Returns true if ALL dependencies of item are complete.""" for dep in item.dependencies: # Ignore dependencies that were not scheduled to run. if dep not in self.items: @@ -319,12 +320,12 @@ def _ok_to_enqueue(self, item): return True def _ok_to_run(self, item): - '''Returns true if the required dependencies have passed. + """Returns true if the required dependencies have passed. The item's needs_all_dependencies_passing setting is used to figure out whether we can run this item or not, based on its dependent jobs' statuses. - ''' + """ # 'item' can run only if its dependencies have passed (their results # should already show up in the item to status map). for dep in item.dependencies: @@ -333,25 +334,25 @@ def _ok_to_run(self, item): continue dep_status = self.item_to_status[dep] - assert dep_status in ['P', 'F', 'K'] + assert dep_status in ["P", "F", "K"] if item.needs_all_dependencies_passing: - if dep_status in ['F', 'K']: + if dep_status in ["F", "K"]: return False - else: - if dep_status in ['P']: - return True + elif dep_status in ["P"]: + return True return item.needs_all_dependencies_passing def _poll(self, hms): - '''Check for running items that have finished + """Check for running items that have finished Returns True if something changed. - ''' - - max_poll = min(self.launcher_cls.max_poll, - sum_dict_lists(self._running)) + """ + max_poll = min( + self.launcher_cls.max_poll, + sum_dict_lists(self._running), + ) # If there are no jobs running, we are likely done (possibly because # of a SIGINT). Since poll() was called anyway, signal that something @@ -362,32 +363,44 @@ def _poll(self, hms): changed = False while max_poll: target, self.last_target_polled_idx = get_next_item( - self._targets, self.last_target_polled_idx) + self._targets, + self.last_target_polled_idx, + ) while self._running[target] and max_poll: max_poll -= 1 item, self.last_item_polled_idx[target] = get_next_item( - self._running[target], self.last_item_polled_idx[target]) + self._running[target], + self.last_item_polled_idx[target], + ) status = item.launcher.poll() level = VERBOSE - assert status in ['D', 'P', 'F', 'K'] - if status == 'D': + assert status in ["D", "P", "F", "E", "K"] + if status == "D": continue - elif status == 'P': + + if status == "P": self._passed[target].add(item) - elif status == 'F': + elif status == "F": self._failed[target].add(item) level = log.ERROR else: + # Killed or Error dispatching self._killed[target].add(item) level = log.ERROR self._running[target].pop(self.last_item_polled_idx[target]) self.last_item_polled_idx[target] -= 1 self.item_to_status[item] = status - log.log(level, "[%s]: [%s]: [status] [%s: %s]", hms, target, - item.full_name, status) + log.log( + level, + "[%s]: [%s]: [status] [%s: %s]", + hms, + target, + item.full_name, + status, + ) # Enqueue item's successors regardless of its status. # @@ -402,8 +415,7 @@ def _poll(self, hms): return changed def _dispatch(self, hms): - '''Dispatch some queued items if possible.''' - + """Dispatch some queued items if possible.""" slots = self.launcher_cls.max_parallel - sum_dict_lists(self._running) if slots <= 0: return @@ -412,8 +424,7 @@ def _dispatch(self, hms): # weights. sum_weight = 0 slots_filled = 0 - total_weight = sum(self._queued[t][0].weight for t in self._queued - if self._queued[t]) + total_weight = sum(self._queued[t][0].weight for t in self._queued if self._queued[t]) for target in self._scheduled: if not self._queued[target]: @@ -439,8 +450,7 @@ def _dispatch(self, hms): # targets that are earlier in the list such that in the end, all # slots are fully consumed. sum_weight += self._queued[target][0].weight - target_slots = round( - (slots * sum_weight) / total_weight) - slots_filled + target_slots = round((slots * sum_weight) / total_weight) - slots_filled if target_slots <= 0: continue slots_filled += target_slots @@ -459,21 +469,41 @@ def _dispatch(self, hms): if not to_dispatch: continue - log.log(VERBOSE, "[%s]: [%s]: [dispatch]:\n%s", hms, target, - ", ".join(item.full_name for item in to_dispatch)) + log.log( + VERBOSE, + "[%s]: [%s]: [dispatch]:\n%s", + hms, + target, + ", ".join(item.full_name for item in to_dispatch), + ) for item in to_dispatch: - self._running[target].append(item) - self.item_to_status[item] = 'D' try: item.launcher.launch() + except LauncherError as err: - log.error('{}'.format(err)) + log.exception(err.msg) self._kill_item(item) - def _kill(self): - '''Kill any running items and cancel any that are waiting''' + except LauncherBusy as err: + log.error("Launcher busy: %s", err) + self._queued[target].append(item) + + log.log( + VERBOSE, + "[%s]: [%s]: [reqeued]: %s", + hms, + target, + item.full_name, + ) + continue + + self._running[target].append(item) + self.item_to_status[item] = "D" + + def _kill(self): + """Kill any running items and cancel any that are waiting""" # Cancel any waiting items. We take a copy of self._queued to avoid # iterating over the set as we modify it. for target in self._queued: @@ -487,50 +517,54 @@ def _kill(self): self._kill_item(item) def _check_if_done(self, hms): - '''Check if we are done executing all jobs. + """Check if we are done executing all jobs. Also, prints the status of currently running jobs. - ''' - + """ done = True for target in self._scheduled: - done_cnt = sum([ - len(self._passed[target]), - len(self._failed[target]), - len(self._killed[target]) - ]) + done_cnt = sum( + [ + len(self._passed[target]), + len(self._failed[target]), + len(self._killed[target]), + ], + ) done = done and (done_cnt == self._total[target]) # Skip if a target has not even begun executing. - if not (self._queued[target] or self._running[target] or - done_cnt > 0): + if not (self._queued[target] or self._running[target] or done_cnt > 0): continue perc = done_cnt / self._total[target] * 100 running = ", ".join( - [f"{item.full_name}" for item in self._running[target]]) - msg = self.msg_fmt.format(len(self._queued[target]), - len(self._running[target]), - len(self._passed[target]), - len(self._failed[target]), - len(self._killed[target]), - self._total[target]) - self.status_printer.update_target(target=target, - msg=msg, - hms=hms, - perc=perc, - running=running) + [f"{item.full_name}" for item in self._running[target]], + ) + msg = self.msg_fmt.format( + len(self._queued[target]), + len(self._running[target]), + len(self._passed[target]), + len(self._failed[target]), + len(self._killed[target]), + self._total[target], + ) + self.status_printer.update_target( + target=target, + msg=msg, + hms=hms, + perc=perc, + running=running, + ) return done def _cancel_item(self, item, cancel_successors=True): - '''Cancel an item and optionally all of its successors. + """Cancel an item and optionally all of its successors. Supplied item may be in _scheduled list or the _queued list. From either, we move it straight to _killed. - ''' - - self.item_to_status[item] = 'K' + """ + self.item_to_status[item] = "K" self._killed[item.target].add(item) if item in self._queued[item.target]: self._queued[item.target].remove(item) @@ -541,10 +575,9 @@ def _cancel_item(self, item, cancel_successors=True): self._cancel_successors(item) def _kill_item(self, item): - '''Kill a running item and cancel all of its successors.''' - + """Kill a running item and cancel all of its successors.""" item.launcher.kill() - self.item_to_status[item] = 'K' + self.item_to_status[item] = "K" self._killed[item.target].add(item) self._running[item.target].remove(item) self._cancel_successors(item) diff --git a/vendor/lowrisc_ip/util/dvsim/SgeLauncher.py b/vendor/lowrisc_ip/util/dvsim/SgeLauncher.py index c998b30a1a..9a340f835d 100755 --- a/vendor/lowrisc_ip/util/dvsim/SgeLauncher.py +++ b/vendor/lowrisc_ip/util/dvsim/SgeLauncher.py @@ -36,8 +36,7 @@ def _do_launch(self): # 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() - if self.deploy.exports: - exports.update(self.deploy.exports) + exports.update(self.deploy.exports) # Clear the magic MAKEFLAGS variable from exports if necessary. This # variable is used by recursive Make calls to pass variables from one diff --git a/vendor/lowrisc_ip/util/dvsim/SimCfg.py b/vendor/lowrisc_ip/util/dvsim/SimCfg.py index 83a2c25e33..5891168a0e 100644 --- a/vendor/lowrisc_ip/util/dvsim/SimCfg.py +++ b/vendor/lowrisc_ip/util/dvsim/SimCfg.py @@ -82,6 +82,8 @@ def __init__(self, flow_cfg_file, hjson_data, args, mk_config): # Set default sim modes for unpacking if args.gui: self.en_build_modes.append("gui") + if args.gui_debug: + self.en_build_modes.append("gui_debug") if args.waves is not None: self.en_build_modes.append("waves") else: @@ -449,10 +451,11 @@ def _create_deploy_objects(self): # existing one. is_unique = True for build in self.builds: - if build.is_equivalent_job(new_build): - # Discard `new_build` since it is equivalent to build. If - # `new_build` is the same as `primary_build_mode`, update - # `primary_build_mode` to match `build`. + if new_build.is_equivalent_job(build): + # Discard `new_build` since build implements the same + # thing. If `new_build` is the same as + # `primary_build_mode`, update `primary_build_mode` to + # match `build`. if new_build.name == self.primary_build_mode: self.primary_build_mode = build.name new_build = build @@ -484,12 +487,18 @@ def _create_deploy_objects(self): self.runs = ([] if self.build_only else self._expand_run_list(build_map)) - # In GUI mode, only allow one test to run. + # In GUI mode or GUI with debug mode, only allow one test to run. if self.gui and len(self.runs) > 1: self.runs = self.runs[:1] log.warning("In GUI mode, only one test is allowed to run. " "Picking {}".format(self.runs[0].full_name)) + # GUI mode is only available for Xcelium for the moment. + if (self.gui_debug) and (self.tool not in ['xcelium']): + log.error("GUI debug mode is only available for Xcelium, please remove " + "--gui_debug / -gd option or switch to Xcelium tool.") + sys.exit(1) + # Add builds to the list of things to run, only if --run-only switch # is not passed. self.deploy = [] diff --git a/vendor/lowrisc_ip/util/dvsim/SlurmLauncher.py b/vendor/lowrisc_ip/util/dvsim/SlurmLauncher.py new file mode 100644 index 0000000000..254fd49628 --- /dev/null +++ b/vendor/lowrisc_ip/util/dvsim/SlurmLauncher.py @@ -0,0 +1,144 @@ +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +import logging as log +import os +import shlex +import shutil +import subprocess + +from Launcher import ErrorMessage, Launcher, LauncherError + + +SLURM_QUEUE = os.environ.get("SLURM_QUEUE", "hw-m") +SLURM_MEM = os.environ.get("SLURM_MEM", "16G") +SLURM_MINCPUS = os.environ.get("SLURM_MINCPUS", "8") +SLURM_TIMEOUT = os.environ.get("SLURM_TIMEOUT", "240") +SLURM_CPUS_PER_TASK = os.environ.get("SLURM_CPUS_PER_TASK", "8") +SLURM_SETUP_CMD = os.environ.get("SLURM_SLURM_SETUP_CMD", "") + + +class SlurmLauncher(Launcher): + # Misc common SlurmLauncher settings. + max_odirs = 5 + + def __init__(self, deploy): + '''Initialize common class members.''' + + super().__init__(deploy) + + # Popen object when launching the job. + self.process = None + self.slurm_log_file = self.deploy.get_log_path() + '.slurm' + + def _do_launch(self): + # replace the values in the shell's env vars if the keys match. + exports = os.environ.copy() + exports.update(self.deploy.exports) + + # Clear the magic MAKEFLAGS variable from exports if necessary. This + # variable is used by recursive Make calls to pass variables from one + # level to the next. Here, self.cmd is a call to Make but it's + # logically a top-level invocation: we don't want to pollute the flow's + # Makefile with Make variables from any wrapper that called dvsim. + if 'MAKEFLAGS' in exports: + del exports['MAKEFLAGS'] + + self._dump_env_vars(exports) + + # Add a command delimiter if necessary + slurm_setup_cmd = SLURM_SETUP_CMD + if slurm_setup_cmd and not slurm_setup_cmd.endswith(';'): + slurm_setup_cmd += ';' + + # Encapsulate the run command with the slurm invocation + slurm_cmd = f'srun -p {SLURM_QUEUE} --mem={SLURM_MEM} --mincpus={SLURM_MINCPUS} ' \ + f'--time={SLURM_TIMEOUT} --cpus-per-task={SLURM_CPUS_PER_TASK} ' \ + f'bash -c "{slurm_setup_cmd} {self.deploy.cmd}"' + + try: + with open(self.slurm_log_file, 'w') as out_file: + out_file.write("[Executing]:\n{}\n\n".format(self.deploy.cmd)) + out_file.flush() + + log.info(f'Executing slurm command: {slurm_cmd}') + self.process = subprocess.Popen(shlex.split(slurm_cmd), + bufsize=4096, + universal_newlines=True, + stdout=out_file, + stderr=out_file, + env=exports) + except IOError as e: + raise LauncherError(f'File Error: {e}\nError while handling {self.slurm_log_file}') + except subprocess.SubprocessError as e: + raise LauncherError(f'IO Error: {e}\nSee {self.deploy.get_log_path()}') + finally: + self._close_process() + + self._link_odir("D") + + def poll(self): + '''Check status of the running process + + This returns 'D', 'P' or 'F'. If 'D', the job is still running. If 'P', + the job finished successfully. If 'F', the job finished with an error. + + This function must only be called after running self.dispatch_cmd() and + must not be called again once it has returned 'P' or 'F'. + ''' + + assert self.process is not None + if self.process.poll() is None: + return 'D' + + # Copy slurm job results to log file + if os.path.exists(self.slurm_log_file): + try: + with open(self.slurm_log_file, 'r') as slurm_file: + try: + with open(self.deploy.get_log_path(), 'a') as out_file: + shutil.copyfileobj(slurm_file, out_file) + except IOError as e: + raise LauncherError(f'File Error: {e} when handling ' + f'{self.deploy.get_log_path()}') + # Remove the temporary file from the slurm process + os.remove(self.slurm_log_file) + except IOError as e: + raise LauncherError(f'File Error: {e} when handling {self.slurm_log_file}') + + self.exit_code = self.process.returncode + status, err_msg = self._check_status() + self._post_finish(status, err_msg) + return status + + def kill(self): + '''Kill the running process. + + This must be called between dispatching and reaping the process (the + same window as poll()). + ''' + assert self.process is not None + + # 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() + self._post_finish( + 'K', + ErrorMessage(line_number=None, message='Job killed!', context=[])) + + def _post_finish(self, status, err_msg): + super()._post_finish(status, err_msg) + self._close_process() + self.process = None + + def _close_process(self): + '''Close the file descriptors associated with the process.''' + + assert self.process + if self.process.stdout: + self.process.stdout.close() diff --git a/vendor/lowrisc_ip/util/dvsim/SynCfg.py b/vendor/lowrisc_ip/util/dvsim/SynCfg.py index a81e32d04d..5ccf7f8c5f 100644 --- a/vendor/lowrisc_ip/util/dvsim/SynCfg.py +++ b/vendor/lowrisc_ip/util/dvsim/SynCfg.py @@ -71,7 +71,7 @@ def _gen_results(self, results): # }, # # "timing": { - # # per timing group (ususally a clock domain) + # # per timing group (usually a clock domain) # # in nano seconds # : { # "tns" : , @@ -92,7 +92,7 @@ def _gen_results(self, results): # "macro" : , # "total" : , # - # # hierchical report of first submodule level + # # hierarchical report of first submodule level # "instances" : { # : { # "comb" : , diff --git a/vendor/lowrisc_ip/util/dvsim/Test.py b/vendor/lowrisc_ip/util/dvsim/Test.py index 3c80524b0b..dc464e8e39 100644 --- a/vendor/lowrisc_ip/util/dvsim/Test.py +++ b/vendor/lowrisc_ip/util/dvsim/Test.py @@ -6,7 +6,7 @@ import logging as log import sys -from modes import RunMode, find_and_merge_modes +from modes import RunMode, find_mode, find_mode_list class Test(RunMode): @@ -39,14 +39,6 @@ def create_tests(tdicts, sim_cfg): Process enabled run modes and the set build mode. Return a list of test objects. ''' - - def get_pruned_en_run_modes(test_en_run_modes, global_en_run_modes): - pruned_en_run_modes = [] - for test_en_run_mode in test_en_run_modes: - if test_en_run_mode not in global_en_run_modes: - pruned_en_run_modes.append(test_en_run_mode) - return pruned_en_run_modes - tests_objs = [] # Pass 1: Create unique set of tests by merging tests with the same name for tdict in tdicts: @@ -72,9 +64,16 @@ def get_pruned_en_run_modes(test_en_run_modes, global_en_run_modes): attrs = Test.defaults for test_obj in tests_objs: # Unpack run_modes first - en_run_modes = get_pruned_en_run_modes(test_obj.en_run_modes, - sim_cfg.en_run_modes) - find_and_merge_modes(test_obj, en_run_modes, run_modes) + + # Get the list of names of run modes that are needed for this test + # but aren't also enabled globally. + local_run_mode_names = [name for name in test_obj.en_run_modes + if name not in sim_cfg.en_run_modes] + + # Look up the modes with these names then merge each of these modes + # into test_obj + for m in find_mode_list(local_run_mode_names, run_modes): + test_obj.merge_mode(m) # Find and set the missing attributes from sim_cfg # If not found in sim_cfg either, then throw a warning @@ -95,12 +94,9 @@ def get_pruned_en_run_modes(test_en_run_modes, global_en_run_modes): # solution! We should probably tidy this up properly. setattr(test_obj, attr, deepcopy(global_val)) - # Unpack the build mode for this test - build_mode_objs = find_and_merge_modes(test_obj, - [test_obj.build_mode], - build_modes, - merge_modes=False) - test_obj.build_mode = build_mode_objs[0] + # Look up the build mode named in the test and write it back to the + # test. + test_obj.build_mode = find_mode(test_obj.build_mode, build_modes) # Error if set build mode is actually a sim mode if test_obj.build_mode.is_sim_mode is True: diff --git a/vendor/lowrisc_ip/util/dvsim/Testplan.py b/vendor/lowrisc_ip/util/dvsim/Testplan.py index 056583e408..0c4c850c5a 100644 --- a/vendor/lowrisc_ip/util/dvsim/Testplan.py +++ b/vendor/lowrisc_ip/util/dvsim/Testplan.py @@ -203,7 +203,7 @@ def map_test_results(self, test_results): """Map test results to tests against this testpoint. Given a list of test results find the ones that match the tests listed - in this testpoint and buiild a structure. If no match is found, or if + in this testpoint and build a structure. If no match is found, or if self.tests is an empty list, indicate 0/1 passing so that it is factored into the final total. """ @@ -719,7 +719,7 @@ def get_test_results_summary(self): """Returns the final total as a summary.""" assert self.test_results_mapped, "Have you invoked map_test_results()?" - # The last item in tespoints is the final sum total. We use that to + # The last item in testpoints is the final sum total. We use that to # return the results summary as a dict. total = self.testpoints[-1] assert total.name == "N.A." diff --git a/vendor/lowrisc_ip/util/dvsim/ascentlint-report-parser.py b/vendor/lowrisc_ip/util/dvsim/ascentlint-report-parser.py index 2edb2bf80c..e032baea0e 100755 --- a/vendor/lowrisc_ip/util/dvsim/ascentlint-report-parser.py +++ b/vendor/lowrisc_ip/util/dvsim/ascentlint-report-parser.py @@ -62,7 +62,7 @@ def main(): # Patterns for ascentlint.log parser_args.update({ - args.repdir.joinpath('lint-ascentlint/ascentlint.log'): [ + args.repdir.joinpath('fusesoc-work/ascentlint.log'): [ ("flow_error", r"^FlexNet Licensing error.*"), ("flow_error", r"^Error: .*"), ("flow_error", r"^ERROR.*"), @@ -77,7 +77,7 @@ def main(): # Patterns for ascentlint.rpt parser_args.update({ - args.repdir.joinpath('lint-ascentlint/ascentlint.rpt'): [ + args.repdir.joinpath('fusesoc-work/ascentlint.rpt'): [ ("lint_error", r"^E .*"), ("lint_warning", r"^W .*"), ("lint_info", r"^I .*") diff --git a/vendor/lowrisc_ip/util/dvsim/doc/design_doc.md b/vendor/lowrisc_ip/util/dvsim/doc/design_doc.md index f45f0d086b..36f86e079c 100644 --- a/vendor/lowrisc_ip/util/dvsim/doc/design_doc.md +++ b/vendor/lowrisc_ip/util/dvsim/doc/design_doc.md @@ -30,7 +30,7 @@ Some of the goals / usecases listed below are specific to an EDA tool flow (such - Batch / GUI / interactive mode - With / without wave dumps - Enable wave dump format choices - - With / without [coverage](https://opentitan.org/book/doc/contributing/dv/methodology/#coverage-collection) instrumentation + - With / without [coverage](../../../doc/contributing/dv/methodology/README.md#coverage-collection) instrumentation - Run the same tests in RTL, gate level and power aware simulations - Varying levels of EDA tool logging (to debug EDA tool issues) - Varying levels of EDA tool flow logging (to debug design / verification code) @@ -51,7 +51,7 @@ Some of the goals / usecases listed below are specific to an EDA tool flow (such - Readability - Describe testplans, tool configurations, build modes, run modes, test specifications, testplans and regressions in a human readable, but machine parsable format. -- Scalablility +- Scalability - Enable launching jobs into each new partner's unique compute infrastructure. - Provide a method to easily add support for more new EDA tool flows. - Support a wide variety of open / commercial EDA tools for each flow (i.e. run the same simulation with Synopsys VCS, Cadence Xcelium or Mentor Graphics Questa etc.). @@ -84,11 +84,11 @@ Some of the goals / usecases listed below are specific to an EDA tool flow (such - Enable specification of common passing and failing patterns. - Enable specification of failing patterns that are specific to the EDA tool itself. - Assess pass / fail by parsing the EDA tool flow's log i.e., none of the failing patterns must be seen AND all passing patterns must be seen. - - Enable common failure signatures to be bucketized for the ease of readablility of the report. + - Enable common failure signatures to be bucketized for the ease of readability of the report. - Provide ability to publish the reports to a web server (as a command line option). - Report the wall-clock time and simulated time (the worst case, if the test is multiply seeded) for each test. - For simulations, enable mapping the results of the regression (i.e., the status of the set of tests run) to the testplan entries to indicate the testpoints that have been successfully completed. - - Enable common failure signatures to be bucketized for the ease of readablility of the report. + - Enable common failure signatures to be bucketized for the ease of readability of the report. - Debuggability - Provide logging at multiple levels (normal, verbose and debug) to help debug / triage tool / infrastructure issues. diff --git a/vendor/lowrisc_ip/util/dvsim/doc/glossary.md b/vendor/lowrisc_ip/util/dvsim/doc/glossary.md index 522a80f5c2..413a95df96 100644 --- a/vendor/lowrisc_ip/util/dvsim/doc/glossary.md +++ b/vendor/lowrisc_ip/util/dvsim/doc/glossary.md @@ -32,7 +32,7 @@ The [IBM LSF](https://www.ibm.com/docs/en/spectrum-lsf/10.1.0?topic=overview-lsf EDA tool flows are run at various levels of the design: - **Primitives**: The most basic building blocks used to create hardware designs - OpenTitan provides a library of reusble [primitives](https://docs.opentitan.org/hw/ip/prim/index.html). + OpenTitan provides a library of reusable [primitives](../../../hw/ip/prim/). - **Modules**: A discrete entity that implements a specific feature of a larger design @@ -98,7 +98,7 @@ Please see [TBD]() for more details. DVSim provides these standard regression targets for all DUTs: - `smoke` (typically run in CI checks) - `nightly` (a full regression with coverage enabled, that is run every night) -- `v1` / `v2` / `v3` (DVSim automatically extracts tests that are tagged V1 / V2 / V3 and creates a regression target. +- `v1` / `v2` / `v3` (DVSim automatically extracts tests that are tagged V1 / V2 / V3 and creates a regression target). - `all` (runs all tests with the preset reseeds, without coverage) - `all_once` (run all tests with only a single randomly chosen seed) @@ -127,7 +127,7 @@ Sometimes, the complete verification environment for a DUT (which includes the S A testplan describes a list of tests and functional coverage planned to be developed and written towards DV closure for a DUT. Please see the [testplanner](./testplanner.md) tool for additional details. -The [DV methodology](https://opentitan.org/book/doc/contributing/dv/methodology/#testplan) also provides some additional context on testplans and testpoints. +The [DV methodology](../../../doc/contributing/dv/methodology/#testplan) also provides some additional context on testplans and testpoints. ## Testpoint @@ -145,7 +145,7 @@ The test specification label(s) that satisfy a testpoint are mapped to the testp ## Top level -A top level entity is the highest design entity (i.e., a design entity which is itself, not instatiated as a sub-module in a different module) that is compiled and elaborated. +A top level entity is the highest design entity (i.e., a design entity which is itself, not instantiated as a sub-module in a different module) that is compiled and elaborated. For simulations, this is typically the testbench, since it instantiates the DUT. In simulations, there are also standalone RTL modules (specifically, SVA bindfiles) that are not directly instantiated in the testbench or the DUT hierarchies. These are also considered "top levels" that are elaborated by the tool. diff --git a/vendor/lowrisc_ip/util/dvsim/doc/testplanner.md b/vendor/lowrisc_ip/util/dvsim/doc/testplanner.md index d9dfc3f26b..186befdf9d 100644 --- a/vendor/lowrisc_ip/util/dvsim/doc/testplanner.md +++ b/vendor/lowrisc_ip/util/dvsim/doc/testplanner.md @@ -4,7 +4,7 @@ * Expanding the testplan inline within the DV document as a table; * Annotating the simulation results with testplan entries for a document driven DV execution; -Please see [DV methodology](../../../doc/contributing/dv/methodology/README.md#documentation) for more details on the rationale and motivation for writing and maintaining testplans in a machine-parseable format (`Hjson`). +Please see [DV methodology](../../../doc/contributing/dv/methodology/README.md#testplan) for more details on the rationale and motivation for writing and maintaining testplans in a machine-parseable format (`Hjson`). This document will focus on the anatomy of an Hjson testplan, the list of features supported and some of the ways of using the tool. ## Hjson testplan @@ -54,59 +54,59 @@ The following attributes are used to define each testpoint, at minimum: At the moment, tags are not strictly defined - users are free to come up with their own set of tags. The following examples of tags illustrate the usage: -```hjson - // Run this testpoint on verilator and fpga as well. - tags: ["verilator", "fpga_cw310"] + ```hjson + // Run this testpoint on verilator and fpga as well. + tags: ["verilator", "fpga_cw310"] - // Run this testpoint in gate level and with poweraware. - tags: ["gls", "pa"] + // Run this testpoint in gate level and with power aware. + tags: ["gls", "pa"] - // Run this testpoint with ROM (will use test ROM by default). - tags: ["rom"] + // Run this testpoint with ROM (will use test ROM by default). + tags: ["rom"] - // Run this testpoint as a post-Si test vector on the tester. - tags: ["vector"] -``` + // Run this testpoint as a post-Si test vector on the tester. + tags: ["vector"] + ``` The testplan from the documentation point of view, can be filtered by a tag (or a set of tags), so that the generated testplan table only includes (or excludes) those testpoints. -If the need arises, more attributes may be added relatively easily. - -Testpoints are added to the testplan using the `testpoints` key. -Here's an example: -```hjson - testpoints: [ - { - name: feature1 - stage: V1 - desc: '''**Goal**: High level goal of this test. - - **Stimulus**: Describe the stimulus procedure. - - **Check**: Describe the checking procedure.''' - tests: ["foo_feature1"] - } - { - name: feature2 - stage: V2 - desc: '''**Goal**: High level goal of this test. - - **Stimulus**: Describe the stimulus procedure. - - **Check**: Describe the checking procedure.''' - - // Below is the list of written (runnable) tests that maps to `feature2`. - // To satisfactorilly test `feature2`, three tests are written. There - // could be various reasons to split the written test, the most common - // being unacceptably long runtime. - tests: ["foo_feature2_test1", - "foo_feature2_test2", - "foo_feature2_test3"] - tags: ["gls"] - } - ... - ] -``` + If the need arises, more attributes may be added relatively easily. + + Testpoints are added to the testplan using the `testpoints` key. + Here's an example: + ```hjson + testpoints: [ + { + name: feature1 + stage: V1 + desc: '''**Goal**: High level goal of this test. + + **Stimulus**: Describe the stimulus procedure. + + **Check**: Describe the checking procedure.''' + tests: ["foo_feature1"] + } + { + name: feature2 + stage: V2 + desc: '''**Goal**: High level goal of this test. + + **Stimulus**: Describe the stimulus procedure. + + **Check**: Describe the checking procedure.''' + + // Below is the list of written (runnable) tests that maps to `feature2`. + // To satisfactorily test `feature2`, three tests are written. There + // could be various reasons to split the written test, the most common + // being unacceptably long runtime. + tests: ["foo_feature2_test1", + "foo_feature2_test2", + "foo_feature2_test3"] + tags: ["gls"] + } + ... + ] + ``` ### Covergroups @@ -249,8 +249,9 @@ Filter the testplan by tags "foo" and "bar": $ ./util/dvsim/testplanner.py \ util/dvsim/examples/testplanner/foo_testplan.hjson:foo:bar \ -s util/dvsim/examples/testplanner/foo_sim_results.hjson +``` -Filter the testplan by excluding the testspoints tagged "foo": +Filter the testplan by excluding the testpoints tagged "foo": ```console $ ./util/dvsim/testplanner.py \ util/dvsim/examples/testplanner/foo_testplan.hjson:-foo \ @@ -279,11 +280,11 @@ This is done by invoking: ./util/site/build-docs.sh serve ``` -The `util/mdbook_testplan.py` preprocessor renders any testplan present the `SUMMARY.md` into the documenation. +The `util/mdbook_testplan.py` preprocessor renders any testplan present the `SUMMARY.md` into the documentation. The complete OpenTitan documentation is rendered locally at `https://0.0.0.0:9000`. ## Future work * Allow DUT and its imported testplans to have the same testpoint name as long as they are in separate files. * The list of written tests are appended from both files. - * The descriptions are merged - its upto the user to ensure that it is still meaningful after the merge. + * The descriptions are merged - it's up to the user to ensure that it is still meaningful after the merge. * Conflicting verification stages are flagged as an error. diff --git a/vendor/lowrisc_ip/util/dvsim/dvsim.py b/vendor/lowrisc_ip/util/dvsim/dvsim.py index 3d591bc4d0..f7069ff732 100755 --- a/vendor/lowrisc_ip/util/dvsim/dvsim.py +++ b/vendor/lowrisc_ip/util/dvsim/dvsim.py @@ -34,6 +34,9 @@ import LauncherFactory import LocalLauncher import SgeLauncher +import SlurmLauncher +import LsfLauncher +import NcLauncher from CfgFactory import make_cfg from Deploy import RunTest from Timer import Timer @@ -276,9 +279,9 @@ def parse_args(): # Disable it pending more verbose and automatic solution and document in # help message usage='%(prog)s {} [-h] [options]'.format(cfg_metavar), - epilog="Either place the positional argument ahead of the optional args:\n" \ - "eg. `dvsim.py {} -i ITEM ITEM` \n" \ - "or end a sequence of optional args with `--`:\n" \ + epilog="Either place the positional argument ahead of the optional args:\n" + "eg. `dvsim.py {} -i ITEM ITEM` \n" + "or end a sequence of optional args with `--`:\n" "eg. `dvsim.py -i ITEM ITEM -- {}`\n".format(cfg_metavar, cfg_metavar)) parser.add_argument("cfg", @@ -440,6 +443,15 @@ def parse_args(): help=('Run the flow in GUI mode instead of the batch ' 'mode.')) + disg.add_argument("--gui-debug", + "-gd", + action='store_true', + help=('Run the flow in GUI mode and enable tool debug ' + 'features such as: breakpoints, live values, ' + 'transactions recording... (works with Xcelium ' + 'only for the moment). ' + '[!] Has a significant performance impact.')) + disg.add_argument("--interactive", action='store_true', help=('Run the job in non-GUI interactive mode ' @@ -534,6 +546,7 @@ def parse_args(): 'in the order they are passed.')) seedg.add_argument("--fixed-seed", + "-fs", type=int, metavar='S', help=('Run all items with the seed S. This implies ' @@ -715,14 +728,17 @@ def main(): RunTest.seeds = args.seeds # If we are fixing a seed value, no point in tests having multiple reseeds. - if args.fixed_seed: + if args.fixed_seed is not None: args.reseed = 1 RunTest.fixed_seed = args.fixed_seed # Register the common deploy settings. Timer.print_interval = args.print_interval LocalLauncher.LocalLauncher.max_parallel = args.max_parallel + SlurmLauncher.SlurmLauncher.max_parallel = args.max_parallel SgeLauncher.SgeLauncher.max_parallel = args.max_parallel + LsfLauncher.LsfLauncher.max_parallel = args.max_parallel + NcLauncher.NcLauncher.max_parallel = args.max_parallel Launcher.Launcher.max_odirs = args.max_odirs LauncherFactory.set_launcher_type(args.local) diff --git a/vendor/lowrisc_ip/util/dvsim/modes.py b/vendor/lowrisc_ip/util/dvsim/modes.py index d1e38e706c..0b42e7b6ca 100644 --- a/vendor/lowrisc_ip/util/dvsim/modes.py +++ b/vendor/lowrisc_ip/util/dvsim/modes.py @@ -22,10 +22,6 @@ def __init__(self, type_name: str, mdict): log.error("Key \"name\" missing in mode %s", mdict) sys.exit(1) - if not hasattr(self, "type"): - log.fatal("Key \"type\" is missing or invalid") - sys.exit(1) - for key in keys: if key not in attrs: log.error(f"Key {key} in {mdict} is invalid. Supported " @@ -33,11 +29,13 @@ def __init__(self, type_name: str, mdict): sys.exit(1) setattr(self, key, mdict[key]) - def get_sub_modes(self): - return getattr(self, "en_" + self.type + "_modes", []) + def get_sub_modes(self) -> List[str]: + # Default behaviour is not to have sub-modes + return [] - def set_sub_modes(self, sub_modes): - setattr(self, "en_" + self.type + "_modes", sub_modes) + def set_sub_modes(self, sub_modes: List[str]) -> None: + # Default behaviour is not to have sub-modes + return None def merge_mode(self, mode: 'Mode') -> None: '''Update this object by merging it with mode.''' @@ -61,52 +59,58 @@ def merge_mode(self, mode: 'Mode') -> None: if is_sub_mode and attr == 'name': continue - # If mode's value is None, then nothing to do here. + # If the incoming value is None, then nothing to do here. if mode_attr_val is None: continue - # If self value is None, then replace with mode's value. + # If the current value is None, then replace with the incoming value. if self_attr_val is None: setattr(self, attr, mode_attr_val) continue - # If they are equal, then nothing to do here. + # If both values are equal, there is nothing to do. if self_attr_val == mode_attr_val: continue - # Extend if they are both lists. + # If we have genuine types (because neither value is None), check + # that the values are compatible. + if not isinstance(mode_attr_val, type(self_attr_val)): + log.error(f"Cannot merge {self.name} with mode {mode.name}: " + f"the incoming values for attribute {attr} are not " + f"of the same type.") + sys.exit(1) + + # If the current value is a list, the incoming one must be as well. + # Append that to the current list. if isinstance(self_attr_val, list): assert isinstance(mode_attr_val, list) self_attr_val.extend(mode_attr_val) continue - # If the current val is default, replace with new. + # The types that we support other than lists are "scalar" types, + # which each have a default value. The idea is that a default value + # gets overridden by anything else. scalar_types = {str: "", int: -1} default_val = scalar_types.get(type(self_attr_val)) - if type(self_attr_val) in scalar_types.keys( - ) and self_attr_val == default_val: - setattr(self, attr, mode_attr_val) + # If the incoming value is the type's default value, it will have + # no effect. + if mode_attr_val == default_val: continue - # Check if their types are compatible. - if type(self_attr_val) != type(mode_attr_val): - log.error( - "Mode %s cannot be merged into %s due to a conflict " - "(type mismatch): %s: {%s(%s), %s(%s)}", mode.name, - self.name, attr, str(self_attr_val), - str(type(self_attr_val)), str(mode_attr_val), - str(type(mode_attr_val))) - sys.exit(1) + # If the existing value is the type's default value, it will be + # overridden by the incoming value. + if self_attr_val == default_val: + setattr(self, attr, mode_attr_val) + continue - # Check if they are different non-default values. - if self_attr_val != default_val and mode_attr_val != default_val: - log.error( - "Mode %s cannot be merged into %s due to a conflict " - "(unable to pick one from different values): " - "%s: {%s, %s}", mode.name, self.name, attr, - str(self_attr_val), str(mode_attr_val)) - sys.exit(1) + # If we get to here then neither value is the default value and + # they are not equal. Raise an error because we don't know how to + # merge them. + log.error(f"Cannot merge mode {mode.name} into {self.name} " + f"because they have conflicting values for attribute " + f"{attr}: {mode_attr_val} and {self_attr_val}.") + sys.exit(1) # Check newly appended sub_modes, remove 'self' and duplicates sub_modes = self.get_sub_modes() @@ -207,22 +211,19 @@ def find_mode(mode_name: str, modes: List[Mode]) -> Optional[Mode]: return None -def find_and_merge_modes(mode: Mode, - mode_names: List[str], - modes: List[Mode], - merge_modes: bool = True): - found_mode_objs = [] +def find_mode_list(mode_names: List[str], modes: List[Mode]) -> List[Mode]: + '''Find modes matching a list of names.''' + found_list = [] for mode_name in mode_names: - sub_mode = find_mode(mode_name, modes) - if sub_mode is not None: - found_mode_objs.append(sub_mode) - if merge_modes is True: - mode.merge_mode(sub_mode) - else: - log.error("Mode \"%s\" enabled within mode \"%s\" not found!", - mode_name, mode.name) + mode = find_mode(mode_name, modes) + if mode is None: + log.error("Cannot find requested mode ({}) in list. Known names: {}" + .format(mode_name, [m.name for m in modes])) sys.exit(1) - return found_mode_objs + + found_list.append(mode) + + return found_list class BuildMode(Mode): @@ -235,7 +236,6 @@ class BuildMode(Mode): def __init__(self, bdict): self.name = "" - self.type = "build" self.is_sim_mode = 0 self.pre_build_cmds = [] self.post_build_cmds = [] @@ -251,6 +251,12 @@ def __init__(self, bdict): super().__init__("build mode", bdict) self.en_build_modes = list(set(self.en_build_modes)) + def get_sub_modes(self) -> List[str]: + return self.en_build_modes + + def set_sub_modes(self, sub_modes: List[str]) -> None: + self.en_build_modes = sub_modes + @staticmethod def get_default_mode(): return BuildMode({"name": "default"}) @@ -264,7 +270,6 @@ class RunMode(Mode): def __init__(self, rdict): self.name = "" - self.type = "run" self.reseed = None self.pre_run_cmds = [] self.post_run_cmds = [] @@ -282,6 +287,12 @@ def __init__(self, rdict): super().__init__("run mode", rdict) self.en_run_modes = list(set(self.en_run_modes)) + def get_sub_modes(self) -> List[str]: + return self.en_run_modes + + def set_sub_modes(self, sub_modes: List[str]) -> None: + self.en_run_modes = sub_modes + @staticmethod def get_default_mode(): return None diff --git a/vendor/lowrisc_ip/util/dvsim/qsubopts.py b/vendor/lowrisc_ip/util/dvsim/qsubopts.py index 409893bc9b..6e44163767 100755 --- a/vendor/lowrisc_ip/util/dvsim/qsubopts.py +++ b/vendor/lowrisc_ip/util/dvsim/qsubopts.py @@ -6,7 +6,7 @@ # ---------------------------------- # qsubOptions Class # ---------------------------------- -"""A helper class designed to handle the managment of options and +"""A helper class designed to handle the management of options and positional arguments to qsub and related Grid Engine executables. Contains functions to write the requested execution string either diff --git a/vendor/lowrisc_ip/util/dvsim/results_server.py b/vendor/lowrisc_ip/util/dvsim/results_server.py index e117beb9e4..377ab86a77 100644 --- a/vendor/lowrisc_ip/util/dvsim/results_server.py +++ b/vendor/lowrisc_ip/util/dvsim/results_server.py @@ -89,7 +89,7 @@ def get_creation_time(self, path: str) -> Optional[datetime.datetime]: def mv(self, from_path: str, to_path: str) -> None: """Use gsutil mv to move a file/directory.""" try: - subprocess.run(['gsutil', 'mv', + subprocess.run(['gsutil', '-m', 'mv', self._path_in_bucket(from_path), self._path_in_bucket(to_path)], check=True) @@ -114,7 +114,7 @@ def upload(self, On failure, prints a message to the log but returns as normal. """ try: - sub_cmd = ['cp'] + sub_cmd = ['-m', 'cp'] if recursive: sub_cmd.append('-r') subprocess.run(['gsutil'] + sub_cmd + diff --git a/vendor/lowrisc_ip/util/dvsim/utils.py b/vendor/lowrisc_ip/util/dvsim/utils.py index 75680b314d..ee8f0d5cde 100644 --- a/vendor/lowrisc_ip/util/dvsim/utils.py +++ b/vendor/lowrisc_ip/util/dvsim/utils.py @@ -303,7 +303,7 @@ def find_and_substitute_wildcards(sub_dict, ''' for key in sub_dict.keys(): if type(sub_dict[key]) in [dict, OrderedDict]: - # Recursively call this funciton in sub-dicts + # Recursively call this function in sub-dicts sub_dict[key] = find_and_substitute_wildcards( sub_dict[key], full_dict, ignored_wildcards, ignore_error) @@ -313,7 +313,7 @@ def find_and_substitute_wildcards(sub_dict, # in case it contains a wildcard for i in range(len(sub_dict_key_values)): if type(sub_dict_key_values[i]) in [dict, OrderedDict]: - # Recursively call this funciton in sub-dicts + # Recursively call this function in sub-dicts sub_dict_key_values[i] = \ find_and_substitute_wildcards(sub_dict_key_values[i], full_dict, ignored_wildcards, ignore_error) @@ -361,7 +361,7 @@ def htmc_color_pc_cells(text): Depending on the identifier, it shades the cell in a specific way. A set of 12 color palettes for setting those shades are encoded in ./style.css. These are 'cna' (grey), 'c0' (red), 'c1' ... 'c10' (green). The shade 'cna' - is used for items that are maked as 'not applicable'. The shades 'c1' to + is used for items that are marked as 'not applicable'. The shades 'c1' to 'c9' form a gradient from red to lime-green to indicate 'levels of completeness'. 'cna' is used for greying out a box for 'not applicable' items, 'c0' is for items that are considered risky (or not yet started) and @@ -391,7 +391,7 @@ def htmc_color_pc_cells(text): indicator is negative. N/A items can have any of the following indicators and need not be - preceeded with a numerical value: + preceded with a numerical value: '--', 'NA', 'N.A.', 'N.A', 'N/A', 'na', 'n.a.', 'n.a', 'n/a' @@ -400,7 +400,7 @@ def htmc_color_pc_cells(text): # Replace with based on the fp # value. "color-classes" are listed in ./style.css as follows: "cna" # for NA value, "c0" to "c10" for fp value falling between 0.00-9.99, - # 10.00-19.99 ... 90.00-99.99, 100.0 respetively. + # 10.00-19.99 ... 90.00-99.99, 100.0 respectively. def color_cell(cell, cclass, indicator="%"): op = cell.replace(" None: - self.buckets = { - 'flow_info': [], - 'flow_warning': [], - 'flow_error': [], - 'sdc_info': [], - 'sdc_review': [], - 'sdc_warning': [], - 'sdc_error': [], - 'setup_info': [], - 'setup_review': [], - 'setup_warning': [], - 'setup_error': [], - 'cdc_info': [], - 'cdc_review': [], - 'cdc_warning': [], - 'cdc_error': [], - # this bucket is temporary and will be removed at the end of the - # parsing pass. - 'fusesoc-error': [] - } - self.severities = { - 'flow_info': 'info', - 'flow_warning': 'warning', - 'flow_error': 'error', - 'sdc_info': 'info', - 'sdc_review': 'warning', - 'sdc_warning': 'warning', - 'sdc_error': 'error', - 'setup_info': 'info', - 'setup_review': 'warning', - 'setup_warning': 'warning', - 'setup_error': 'error', - 'cdc_info': 'info', - 'cdc_review': 'warning', - 'cdc_warning': 'warning', - 'cdc_error': 'error' - } - - -# TODO(#9079): this script will be removed long term once the -# parser has been merged with the Dvsim core code. -def main(): - parser = argparse.ArgumentParser( - description="""This script parses AscentLint log and report files from - a lint run, filters the messages and creates an aggregated result - .hjson file with lint messages and their severities. - - The script returns nonzero status if any warnings or errors are - present. - """) - parser.add_argument('--repdir', - type=lambda p: Path(p).resolve(), - default="./", - help="""The script searches the 'vcdc.log' and - 'vcdc.rpt' files in this directory. - Defaults to './'""") - - parser.add_argument('--outfile', - type=lambda p: Path(p).resolve(), - default="./results.hjson", - help="""Path to the results Hjson file. - Defaults to './results.hjson'""") - - args = parser.parse_args() - - # Define warning/error patterns for each logfile - parser_args = {} - - # Patterns for lint.log - parser_args.update({ - args.repdir.joinpath('build.log'): [ - # If lint warnings have been found, the lint tool will exit - # with a nonzero status code and fusesoc will always spit out - # an error like - # - # ERROR: Failed to build ip:core:name:0.1 : 'make' exited with an error code - # - # If we found any other warnings or errors, there's no point in - # listing this too. BUT we want to make sure we *do* see this - # error if there are no other errors or warnings, since that - # shows something has come unstuck. (Probably the lint tool - # spat out a warning that we don't understand) - ("fusesoc-error", - r"^ERROR: Failed to build .* : 'make' exited with an error code") - ] - }) - - # Patterns for vcdc.log - parser_args.update({ - args.repdir.joinpath('syn-icarus/vcdc.log'): [ - ("flow_error", r"^FlexNet Licensing error.*"), - ("flow_error", r"^Error: .*"), - ("flow_error", r"^ERROR.*"), - ("flow_error", r"^ ERR .*"), - ("flow_warning", r"^Warning: .*"), - # We ignore several messages here: - # #25010: unused signals - # #25011: unused signals - # #25012: unused port - # #25013: unused signals - # #26038: unused or RTL constant - # #39035: parameter becomes local - # #39122: non-positive repeat - # #39491: parameter in package - ("flow_warning", r"^ " - "(?!WARN \[#25010\])" # noqa: W605 - "(?!WARN \[#25011\])" # noqa: W605 - "(?!WARN \[#25012\])" # noqa: W605 - "(?!WARN \[#25013\])" # noqa: W605 - "(?!WARN \[#26038\])" # noqa: W605 - "(?!WARN \[#39035\])" # noqa: W605 - "(?!WARN \[#39122\])" # noqa: W605 - "(?!WARN \[#39491\])" # noqa: W605 - "WARN .*"), - ("flow_info", r"^ INFO .*") - ] - }) - - # The CDC messages are a bit more involved to parse out, since we - # need to know the names and associated severities to do this. - # The tool prints out an overview table in the report, which we are - # going to parse first in order to get this information. - # This is then used to construct the regex patterns to look for - # in a second pass to get the actual CDC messages. - cdc_rule_patterns = extract_rule_patterns( - args.repdir.joinpath('REPORT/vcdc.new.rpt')) - - # Patterns for vcdc.rpt - parser_args.update({ - args.repdir.joinpath('REPORT/vcdc.new.rpt'): cdc_rule_patterns - }) - - # Parse logs - parser = CdcParser() - num_messages = parser.get_results(parser_args) - - # Write out results file - parser.write_results_as_hjson(args.outfile) - - # return nonzero status if any warnings or errors are present - # lint infos do not count as failures - if num_messages['error'] > 0 or num_messages['warning'] > 0: - log.info("Found %d lint errors and %d lint warnings", - num_messages['error'], - num_messages['warning']) - sys.exit(1) - - log.info("Lint logfile parsed succesfully") - sys.exit(0) - - -if __name__ == "__main__": - main() diff --git a/vendor/lowrisc_ip/util/uvmdvgen/BUILD b/vendor/lowrisc_ip/util/uvmdvgen/BUILD new file mode 100644 index 0000000000..15384b09d4 --- /dev/null +++ b/vendor/lowrisc_ip/util/uvmdvgen/BUILD @@ -0,0 +1,10 @@ +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "doc_files", + srcs = glob(["**/*.md"]), +) diff --git a/vendor/lowrisc_ip/util/uvmdvgen/README.md b/vendor/lowrisc_ip/util/uvmdvgen/README.md index 14c965ce9b..62b26009ce 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/README.md +++ b/vendor/lowrisc_ip/util/uvmdvgen/README.md @@ -19,7 +19,7 @@ pieces of common code which can be reused when setting up a new DV environment. Running the tool with `-h` switch provides a brief description of all available switches. ```console -$ util/uvmdvgen/uvmdvgen.py -h +$ util/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/]] [-v VENDOR] @@ -59,7 +59,7 @@ optional arguments: _agent is created at this location. (default set to './') -eo [hw/ip/], --env-outdir [hw/ip/] - Path to place the full tetsbench code. It creates 3 + Path to place the full testbench code. It creates 3 directories - dv, data and doc. The DV document and the testplan Hjson files are placed in the doc and data directories respectively. These are to be merged into @@ -198,7 +198,7 @@ provided by `-hi` and `-ha` respectively. By default, these are set to 'False' * `env/i2c_host_scoreboard` - This is the scoreboard component that already creates the analysis fifos and + This is the scoreboard component that already creates the analysis FIFOs and queues for the agents passed via `-ea` switch. It adds starter tasks for processing each fifo in a forever loop and invokes them in the `run_phase` using `fork-join` statement. If the `-c` switch is passed, it also adds a @@ -299,56 +299,56 @@ by supplying the `--vendor ` switch on the command line. #### Examples ```console -$ util/uvmdvgen/uvmdvgen.py i2c -a +$ util/uvmdvgen.py i2c -a ``` This will create `./i2c/i2c_agent` and place all sources there. ```console -$ util/uvmdvgen/uvmdvgen.py jtag -a -ao hw/dv/sv +$ util/uvmdvgen.py jtag -a -ao hw/dv/sv ``` This will create `hw/dv/sv/jtag_agent` directory and place all the sources there. ```console -$ util/uvmdvgen/uvmdvgen.py i2c -a -s -ao hw/dv/sv +$ util/uvmdvgen.py i2c -a -s -ao hw/dv/sv ``` This will create the I2C agent with separate 'host' mode and 'device' mode drivers. ```console -$ util/uvmdvgen/uvmdvgen.py i2c -e -c -hi -eo hw/ip/i2c/dv +$ util/uvmdvgen.py i2c -e -c -hi -eo hw/ip/i2c/dv ``` This is an illegal command, it is not allowed to specify that an IP testbench extends from CIP lib or has interrupts without specifying that it should support a RAL model using the `-hr` flag. ```console -$ util/uvmdvgen/uvmdvgen.py i2c_host -e -c -hi -hr -ea i2c -eo hw/ip/i2c_host/dv +$ util/uvmdvgen.py i2c_host -e -c -hi -hr -ea i2c -eo hw/ip/i2c_host/dv ``` This will create the complete `i2c_host` DV testbench extended from CIP lib and will instantiate `i2c_agent`. It will also create and hook up the interrupt interface in the testbench. ```console -$ util/uvmdvgen/uvmdvgen.py foo -e -c -hi -ha -hr -ea foo -eo hw/ip/i2c_host/dv +$ util/uvmdvgen.py foo -e -c -hi -ha -hr -ea foo -eo hw/ip/i2c_host/dv ``` This will create the complete foo DV testbench extended from CIP lib and will instantiate `foo_agent`. It will also create and hook up the interrupt interface as well as alerts interface in the testbench. ```console -$ util/uvmdvgen/uvmdvgen.py aes -e -c -hr -ea i2c -eo hw/ip/i2c_host/dv +$ util/uvmdvgen.py aes -e -c -hr -ea i2c -eo hw/ip/i2c_host/dv ``` This will create the complete `i2c_host` DV testbench extended from CIP lib and will instantiate `i2c_agent`. ```console -$ util/uvmdvgen/uvmdvgen.py dma -e -eo hw/ip/dma/dv +$ util/uvmdvgen.py dma -e -eo hw/ip/dma/dv ``` This will create the complete dma DV testbench extended from DV lib. It does not instantiate any downstream agents due to absence of `-ea` switch. ```console -$ util/uvmdvgen/uvmdvgen.py chip -e -ea uart i2c jtag -eo hw/top_earlgrey/dv +$ util/uvmdvgen.py chip -e -ea uart i2c jtag -eo hw/top_earlgrey/dv ``` This will create the complete chip testbench DV lib and will instantiate `uart_agent`, `i2c_agent` and `jtag_agent` in the env. diff --git a/vendor/lowrisc_ip/util/uvmdvgen/__init__.py b/vendor/lowrisc_ip/util/uvmdvgen/__init__.py index e69de29bb2..8b770a74c8 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/__init__.py +++ b/vendor/lowrisc_ip/util/uvmdvgen/__init__.py @@ -0,0 +1,5 @@ +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +VENDOR_DEFAULT = "lowrisc" diff --git a/vendor/lowrisc_ip/util/uvmdvgen/env_cov.sv.tpl b/vendor/lowrisc_ip/util/uvmdvgen/env_cov.sv.tpl index f7f9bbe053..2413c4e60d 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/env_cov.sv.tpl +++ b/vendor/lowrisc_ip/util/uvmdvgen/env_cov.sv.tpl @@ -3,7 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 /** - * Covergoups that are dependent on run-time parameters that may be available + * Covergroups that are dependent on run-time parameters that may be available * only in build_phase can be defined here * Covergroups may also be wrapped inside helper classes if needed. */ diff --git a/vendor/lowrisc_ip/util/uvmdvgen/env_pkg.sv.tpl b/vendor/lowrisc_ip/util/uvmdvgen/env_pkg.sv.tpl index b589c6348e..6ee0a8b56a 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/env_pkg.sv.tpl +++ b/vendor/lowrisc_ip/util/uvmdvgen/env_pkg.sv.tpl @@ -28,8 +28,8 @@ package ${name}_env_pkg; // parameters % if has_alerts: // TODO: add the names of alerts in order - parameter string LIST_OF_ALERTS[] = {}; parameter uint NUM_ALERTS = ; + parameter string LIST_OF_ALERTS[NUM_ALERTS] = {}; % endif // types diff --git a/vendor/lowrisc_ip/util/uvmdvgen/gen_agent.py b/vendor/lowrisc_ip/util/uvmdvgen/gen_agent.py index ee81ae1453..17872e69ed 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/gen_agent.py +++ b/vendor/lowrisc_ip/util/uvmdvgen/gen_agent.py @@ -8,7 +8,7 @@ from mako import exceptions from mako.template import Template -from pkg_resources import resource_filename +import importlib.resources def gen_agent(name, has_separate_host_device_driver, root_dir, vendor): @@ -50,7 +50,7 @@ def gen_agent(name, has_separate_host_device_driver, root_dir, vendor): fname = src_prefix + src + src_suffix # read template - tpl = Template(filename=resource_filename('uvmdvgen', ftpl)) + tpl = Template(filename=str(importlib.resources.files('uvmdvgen') / ftpl)) if not os.path.exists(path_dir): os.system("mkdir -p " + path_dir) with open(path_dir + "/" + fname, 'w') as fout: diff --git a/vendor/lowrisc_ip/util/uvmdvgen/gen_env.py b/vendor/lowrisc_ip/util/uvmdvgen/gen_env.py index 61c08b03fa..f3cbc4b6e6 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/gen_env.py +++ b/vendor/lowrisc_ip/util/uvmdvgen/gen_env.py @@ -1,14 +1,14 @@ # Copyright lowRISC contributors (OpenTitan project). # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -"""Generate SystemVerilog UVM agent extended freom our DV lib +"""Generate SystemVerilog UVM agent extended from our DV lib """ import os import logging as log from mako.template import Template -from pkg_resources import resource_filename +import importlib.resources from uvmdvgen import VENDOR_DEFAULT @@ -69,7 +69,7 @@ def gen_env(name, is_cip, has_ral, has_interrupts, has_alerts, num_edn, continue # read template - tpl = Template(filename=resource_filename('uvmdvgen', ftpl)) + tpl = Template(filename=str(importlib.resources.files('uvmdvgen') / ftpl)) # create rendered file with open(file_path, 'w') as fout: diff --git a/vendor/lowrisc_ip/util/uvmdvgen/scoreboard.sv.tpl b/vendor/lowrisc_ip/util/uvmdvgen/scoreboard.sv.tpl index 5cfbcf330f..61e5f50a51 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/scoreboard.sv.tpl +++ b/vendor/lowrisc_ip/util/uvmdvgen/scoreboard.sv.tpl @@ -91,7 +91,7 @@ class ${name}_scoreboard extends dv_base_scoreboard #( // process the csr req // for write, update local variable and fifo at address phase - // for read, update predication at address phase and compare at data phase + // for read, update prediction at address phase and compare at data phase case (csr.get_name()) // add individual case item for each csr "intr_state": begin diff --git a/vendor/lowrisc_ip/util/uvmdvgen/uvmdvgen.py b/vendor/lowrisc_ip/util/uvmdvgen/uvmdvgen.py deleted file mode 100755 index e804de6f6c..0000000000 --- a/vendor/lowrisc_ip/util/uvmdvgen/uvmdvgen.py +++ /dev/null @@ -1,159 +0,0 @@ -#!/usr/bin/env python3 -# Copyright lowRISC contributors (OpenTitan project). -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 -r"""Command-line tool to generate boilerplate DV testbench. - -The generated objects are extended from dv_lib / cip_lib. -""" -import argparse -import logging as log -import re -import sys - -import gen_agent -import gen_env - -VENDOR_DEFAULT = "lowrisc" - - -def main(): - parser = argparse.ArgumentParser( - description=__doc__, - formatter_class=argparse.RawDescriptionHelpFormatter) - parser.add_argument( - "name", - metavar="[ip/block name]", - help="""Name of the ip/block for which the UVM TB is being generated. - This should just name the block, not the path to it.""") - - parser.add_argument( - "-a", - "--gen-agent", - action='store_true', - help="Generate UVM agent code extended from DV library") - - parser.add_argument( - "-s", - "--has-separate-host-device-driver", - action='store_true', - help= - """IP / block agent creates a separate driver for host and device modes. - (Ignored if -a switch is not passed.)""") - - parser.add_argument("-e", - "--gen-env", - action='store_true', - help="Generate testbench UVM env code") - - parser.add_argument( - "-c", - "--is-cip", - action='store_true', - help= - """Is comportable IP - this will result in code being extended from CIP - library. If switch is not passed, the code will be extended from DV - library instead. (Ignored if -e switch is not passed.)""") - - parser.add_argument( - "-hr", - "--has-ral", - default=False, - action='store_true', - help="""Specify whether the DUT has CSRs and thus needs a UVM RAL model. - This option is required if either --is_cip or --has_interrupts - are enabled.""") - - parser.add_argument( - "-hi", - "--has-interrupts", - default=False, - action='store_true', - help="""CIP has interrupts. Create interrupts interface in tb""") - - parser.add_argument( - "-ha", - "--has-alerts", - default=False, - action='store_true', - help="""CIP has alerts. Create alerts interface in tb""") - - parser.add_argument( - "-ne", - "--num-edn", - default=0, - type=int, - help="""CIP has EDN connection. Create edn pull interface in tb""") - - parser.add_argument( - "-ea", - "--env-agents", - nargs="+", - metavar="agt1 agt2", - help="""Env creates an interface agent specified here. They are - assumed to already exist. Note that the list is space-separated, - and not comma-separated. (ignored if -e switch is not passed)""" - ) - - parser.add_argument( - "-ao", - "--agent-outdir", - metavar="[hw/dv/sv]", - help="""Path to place the agent code. A directory called _agent is - created at this location. (default set to './')""") - - parser.add_argument( - "-eo", - "--env-outdir", - metavar="[hw/ip/]", - help="""Path to place the full testbench code. It creates 3 directories - - dv, data, and doc. The DV doc and the testplan Hjson files are placed - in the doc and data directories respectively. These are to be merged - into the IP's root directory (with the existing data and doc - directories). Under dv, it creates 3 sub-directories - env, tb, and - tests - to place all of the testbench sources. (default set to - './'.)""") - - parser.add_argument( - "-v", - "--vendor", - default=VENDOR_DEFAULT, - help= - """Name of the vendor / entity developing the testbench. This is used - to set the VLNV of the FuseSoC core files.""") - - args = parser.parse_args() - - # The name should be alphanumeric. - if re.search(r"\W", args.name): - log.error("The block name '%s' contains non-alphanumeric characters.", - args.name) - sys.exit(1) - - 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 - # has_ral set if one of these options is set. - if not args.has_ral and (args.is_cip or args.has_interrupts): - args.has_ral = True - print("NOTE: --has_ral switch is enabled since either " - "--is_cip or --has_interrupts is set.") - - if args.gen_agent: - gen_agent.gen_agent(args.name, args.has_separate_host_device_driver, - args.agent_outdir, args.vendor) - - if args.gen_env: - 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.num_edn, - args.env_agents, args.env_outdir, args.vendor) - - -if __name__ == '__main__': - main()