diff --git a/dv/fcov/dv_fcov_macros.svh b/dv/fcov/dv_fcov_macros.svh deleted file mode 100644 index 2f43cb13..00000000 --- a/dv/fcov/dv_fcov_macros.svh +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -// Coverage support is not available in Verilator but it's useful to include extra fcov signals for -// linting purposes. They need to be marked as unused to avoid warnings. - -// Include FCOV RTL by default. Exclude it for synthesis and where explicitly requested (by defining -// EXCLUDE_FCOV). -`ifdef SYNTHESIS - `define EXCLUDE_FCOV -`elsif YOSYS - `define EXCLUDE_FCOV -`endif - -`ifdef VERILATOR - `define FCOV_MARK_UNUSED(__var_type, __var_name) \ - __var_type unused_fcov_``__var_name; \ - assign unused_fcov_``__var_name = fcov_``__var_name; -`else - `define FCOV_MARK_UNUSED(__var_type, __var_name) -`endif - -`ifndef FCOV_SIGNAL -`define FCOV_SIGNAL(__var_type, __var_name, __var_definition) \ - `ifndef EXCLUDE_FCOV \ - __var_type fcov_``__var_name; \ -\ - assign fcov_``__var_name = __var_definition; \ -\ - `FCOV_MARK_UNUSED(__var_type, __var_name) \ - `endif -`endif - -`ifndef FCOV_SIGNAL_GEN_IF -`define FCOV_SIGNAL_GEN_IF(__var_type, __var_name, __var_definition, __generate_test, __default_val = '0) \ - `ifndef EXCLUDE_FCOV \ - __var_type fcov_``__var_name; \ -\ - if (__generate_test) begin : g_fcov_``__var_name \ - assign fcov_``__var_name = __var_definition; \ - end else begin : g_no_fcov_``__var_name \ - assign fcov_``__var_name = __default_val; \ - end \ -\ - `FCOV_MARK_UNUSED(__var_type, __var_name) \ - `endif -`endif diff --git a/dv/uvm/core_ibex/fcov/core_ibex_fcov_if.sv b/dv/uvm/core_ibex/fcov/core_ibex_fcov_if.sv index 7659f77e..99677e0c 100644 --- a/dv/uvm/core_ibex/fcov/core_ibex_fcov_if.sv +++ b/dv/uvm/core_ibex/fcov/core_ibex_fcov_if.sv @@ -10,7 +10,7 @@ interface core_ibex_fcov_if import ibex_pkg::*; ( input priv_lvl_e priv_mode_if, input priv_lvl_e priv_mode_lsu ); - `include "dv_macros.svh" + `include "dv_fcov_macros.svh" import uvm_pkg::*; typedef enum { @@ -96,7 +96,7 @@ interface core_ibex_fcov_if import ibex_pkg::*; ( covergroup uarch_cg @(posedge clk_i); type_option.strobe = 1; - `DV_FCOV_EXPR_SEEN(cp_insn_unstalled, instruction_unstalled.triggered) + `DV_FCOV_EXPR_SEEN(insn_unstalled, instruction_unstalled.triggered) cp_insn_category_id: coverpoint id_instr_category; @@ -116,10 +116,10 @@ interface core_ibex_fcov_if import ibex_pkg::*; ( cp_priv_mode_if: coverpoint priv_mode_if; cp_prov_mode_lsu: coverpoint priv_mode_lsu; - `DV_FCOV_EXPR_SEEN(cp_interrupt_taken, id_stage_i.controller_i.fcov_interrupt_taken) - `DV_FCOV_EXPR_SEEN(cp_debug_entry_if, id_stage_i.controller_i.fcov_debug_entry_if) - `DV_FCOV_EXPR_SEEN(cp_debug_entry_id, id_stage_i.controller_i.fcov_debug_entry_id) - `DV_FCOV_EXPR_SEEN(cp_pipe_flush, id_stage_i.controller_i.fcov_pipe_flush) + `DV_FCOV_EXPR_SEEN(interrupt_taken, id_stage_i.controller_i.fcov_interrupt_taken) + `DV_FCOV_EXPR_SEEN(debug_entry_if, id_stage_i.controller_i.fcov_debug_entry_if) + `DV_FCOV_EXPR_SEEN(debug_entry_id, id_stage_i.controller_i.fcov_debug_entry_id) + `DV_FCOV_EXPR_SEEN(pipe_flush, id_stage_i.controller_i.fcov_pipe_flush) wb_reg_hz_instr_cross: cross cp_insn_category_id, cp_wb_reg_hz; stall_cross: cross cp_insn_category_id, cp_stall_type_id; @@ -137,5 +137,5 @@ interface core_ibex_fcov_if import ibex_pkg::*; ( void'($value$plusargs("enable_uarch_cov=%d", en_uarch_cov)); end - `DV_INSTANTIATE_CG(uarch_cg, en_uarch_cov) + `DV_FCOV_INSTANTIATE_CG(uarch_cg, en_uarch_cov) endinterface diff --git a/dv/uvm/core_ibex/ibex_dv.f b/dv/uvm/core_ibex/ibex_dv.f index b5258ac0..eb234255 100644 --- a/dv/uvm/core_ibex/ibex_dv.f +++ b/dv/uvm/core_ibex/ibex_dv.f @@ -70,7 +70,6 @@ ${PRJ_DIR}/vendor/google_riscv-dv/src/riscv_signature_pkg.sv +incdir+${PRJ_DIR}/dv/uvm/core_ibex/tests +incdir+${PRJ_DIR}/dv/uvm/core_ibex/common/ibex_mem_intf_agent +incdir+${PRJ_DIR}/dv/uvm/core_ibex/common/irq_agent -+incdir+${PRJ_DIR}/dv/fcov +incdir+${PRJ_DIR}/vendor/lowrisc_ip/dv/sv/mem_model +incdir+${PRJ_DIR}/vendor/lowrisc_ip/dv/sv/dv_utils +incdir+${PRJ_DIR}/vendor/lowrisc_ip/dv/sv/str_utils diff --git a/dv/uvm/icache/dv/env/ibex_icache_env_cfg.sv b/dv/uvm/icache/dv/env/ibex_icache_env_cfg.sv index d78beff2..79b2c766 100644 --- a/dv/uvm/icache/dv/env/ibex_icache_env_cfg.sv +++ b/dv/uvm/icache/dv/env/ibex_icache_env_cfg.sv @@ -35,6 +35,9 @@ class ibex_icache_env_cfg extends dv_base_env_cfg; virtual function void initialize(bit [BUS_AW-1:0] csr_base_addr = '1); core_agent_cfg = ibex_icache_core_agent_cfg::type_id::create("core_agent_cfg"); mem_agent_cfg = ibex_icache_mem_agent_cfg::type_id::create ("mem_agent_cfg"); + // Note this is a hack - super.initialize() cannot be called without triggering a lot of + // issues due to missing RAL bits + is_initialized = 1; endfunction // Create tag and data ECC agents for each way. If ECC is disabled, this should still be called, diff --git a/ibex_core.core b/ibex_core.core index f153e12d..4a6333dd 100644 --- a/ibex_core.core +++ b/ibex_core.core @@ -13,7 +13,7 @@ filesets: - lowrisc:prim:lfsr - lowrisc:ibex:ibex_pkg - lowrisc:ibex:ibex_icache - - lowrisc:dv:dv_fcov + - lowrisc:dv:dv_fcov_macros files: - rtl/ibex_alu.sv - rtl/ibex_branch_predict.sv diff --git a/rtl/ibex_controller.sv b/rtl/ibex_controller.sv index 2ab41a2d..07c31362 100644 --- a/rtl/ibex_controller.sv +++ b/rtl/ibex_controller.sv @@ -822,12 +822,13 @@ module ibex_controller #( ////////// // FCOV // ////////// - `FCOV_SIGNAL(logic, interrupt_taken, (ctrl_fsm_cs != IRQ_TAKEN) & (ctrl_fsm_ns == IRQ_TAKEN)); - `FCOV_SIGNAL(logic, debug_entry_if, - (ctrl_fsm_cs != DBG_TAKEN_IF) & (ctrl_fsm_ns == DBG_TAKEN_IF)); - `FCOV_SIGNAL(logic, debug_entry_id, - (ctrl_fsm_cs != DBG_TAKEN_ID) & (ctrl_fsm_ns == DBG_TAKEN_ID)); - `FCOV_SIGNAL(logic, pipe_flush, (ctrl_fsm_cs != FLUSH) & (ctrl_fsm_ns == FLUSH)); + + `DV_FCOV_SIGNAL(logic, interrupt_taken, (ctrl_fsm_cs != IRQ_TAKEN) & (ctrl_fsm_ns == IRQ_TAKEN)) + `DV_FCOV_SIGNAL(logic, debug_entry_if, + (ctrl_fsm_cs != DBG_TAKEN_IF) & (ctrl_fsm_ns == DBG_TAKEN_IF)) + `DV_FCOV_SIGNAL(logic, debug_entry_id, + (ctrl_fsm_cs != DBG_TAKEN_ID) & (ctrl_fsm_ns == DBG_TAKEN_ID)) + `DV_FCOV_SIGNAL(logic, pipe_flush, (ctrl_fsm_cs != FLUSH) & (ctrl_fsm_ns == FLUSH)) //////////////// // Assertions // diff --git a/rtl/ibex_id_stage.sv b/rtl/ibex_id_stage.sv index b08fac01..53db94af 100644 --- a/rtl/ibex_id_stage.sv +++ b/rtl/ibex_id_stage.sv @@ -1039,12 +1039,12 @@ module ibex_id_stage #( // FCOV // ////////// - `FCOV_SIGNAL_GEN_IF(logic, rf_rd_wb_hz, + `DV_FCOV_SIGNAL_GEN_IF(logic, rf_rd_wb_hz, (gen_stall_mem.rf_rd_a_hz | gen_stall_mem.rf_rd_b_hz) & instr_valid_i, WritebackStage) - `FCOV_SIGNAL(logic, branch_taken, - instr_executing & (id_fsm_q == FIRST_CYCLE) & branch_decision_i); - `FCOV_SIGNAL(logic, branch_not_taken, - instr_executing & (id_fsm_q == FIRST_CYCLE) & ~branch_decision_i); + `DV_FCOV_SIGNAL(logic, branch_taken, + instr_executing & (id_fsm_q == FIRST_CYCLE) & branch_decision_i) + `DV_FCOV_SIGNAL(logic, branch_not_taken, + instr_executing & (id_fsm_q == FIRST_CYCLE) & ~branch_decision_i) //////////////// // Assertions // diff --git a/rtl/ibex_load_store_unit.sv b/rtl/ibex_load_store_unit.sv index 8fb09a95..a26a3cbd 100644 --- a/rtl/ibex_load_store_unit.sv +++ b/rtl/ibex_load_store_unit.sv @@ -498,8 +498,9 @@ module ibex_load_store_unit ////////// // FCOV // ////////// - `FCOV_SIGNAL(logic, ls_error_exception, (load_err_o | store_err_o) & ~pmp_err_q); - `FCOV_SIGNAL(logic, ls_pmp_exception, (load_err_o | store_err_o) & pmp_err_q); + + `DV_FCOV_SIGNAL(logic, ls_error_exception, (load_err_o | store_err_o) & ~pmp_err_q) + `DV_FCOV_SIGNAL(logic, ls_pmp_exception, (load_err_o | store_err_o) & pmp_err_q) //////////////// // Assertions // diff --git a/rtl/ibex_wb_stage.sv b/rtl/ibex_wb_stage.sv index 7075c01b..02f1308e 100644 --- a/rtl/ibex_wb_stage.sv +++ b/rtl/ibex_wb_stage.sv @@ -173,7 +173,7 @@ module ibex_wb_stage #( assign rf_wdata_wb_o = rf_wdata_wb_mux_we[0] ? rf_wdata_wb_mux[0] : rf_wdata_wb_mux[1]; assign rf_we_wb_o = |rf_wdata_wb_mux_we; - `FCOV_SIGNAL_GEN_IF(logic, wb_valid, g_writeback_stage.wb_valid_q, WritebackStage) + `DV_FCOV_SIGNAL_GEN_IF(logic, wb_valid, g_writeback_stage.wb_valid_q, WritebackStage) `ASSERT(RFWriteFromOneSourceOnly, $onehot0(rf_wdata_wb_mux_we)) endmodule diff --git a/vendor/lowrisc_ip.lock.hjson b/vendor/lowrisc_ip.lock.hjson index 6ba1c0a1..6a649458 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: 7aa5c2b890fa5d4e3d0b43e0f5e561cb7743a01d + rev: 6cc5c164ba96d339f06cbcede0d17d2c96ce3c05 } } 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 3a27ac00..7700e609 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 @@ -97,8 +97,8 @@ interface clk_rst_if #( end endfunction - // set the clk period in ns - function automatic void set_period_ns(int period_ps); + // set the clk period in ps + function automatic void set_period_ps(int period_ps); clk_period_ps = period_ps; clk_freq_mhz = 1000_000 / clk_period_ps; recompute = 1'b1; diff --git a/vendor/lowrisc_ip/dv/sv/common_ifs/index.md b/vendor/lowrisc_ip/dv/sv/common_ifs/index.md index f28e41bb..41dc3bfd 100644 --- a/vendor/lowrisc_ip/dv/sv/common_ifs/index.md +++ b/vendor/lowrisc_ip/dv/sv/common_ifs/index.md @@ -30,7 +30,7 @@ the frequency and duty cycle of the generated clock, use the following functions: * `set_freq_mhz` / `set_freq_khz`: set the clock frequency in MHz / KHz. This is 50MHz by default. -* `set_period_ns`: set the clock period in nanoseconds. This is 20ns by default +* `set_period_ps`: set the clock period in picoseconds. This is 20_000ps by default (giving a clock period of 50MHz). * `set_duty_cycle`: set the duty cycle (as a percentage: 1 - 99). This is 50 by default. 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 00401808..d3ee3c7b 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 @@ -343,7 +343,7 @@ package csr_utils_pkg; end // poke always updates predict value, if predict == 0, revert back to old mirrored value if (!predict || kind == BkdrRegPathRtlShadow) begin - void'(csr.predict(.value(old_mirrored_val), .kind(UVM_PREDICT_DIRECT))); + void'(csr.predict(.value(old_mirrored_val), .kind(UVM_PREDICT_DIRECT), .path(UVM_BACKDOOR))); end endtask 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 fd1cf9e7..810d0024 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 @@ -14,6 +14,10 @@ class dv_base_reg extends uvm_reg; local bit shadow_wr_staged; // stage the first shadow reg write local bit shadow_update_err; local bit en_shadow_wr = 1; + // In certain shadow reg (e.g. in AES), fatal error can lock write access + local bit shadow_fatal_lock; + local string update_err_alert_name; + local string storage_err_alert_name; // atomic_shadow_wr: semaphore to guarantee atomicity of the two writes for shadowed registers. // In case a parallel thread writing a different value to the same reg causing an update_err @@ -60,6 +64,11 @@ class dv_base_reg extends uvm_reg; locked_regs.push_back(locked_reg); endfunction + function bit is_inside_locked_regs(dv_base_reg csr); + if (csr inside {locked_regs}) return 1; + else return 0; + endfunction + function bit is_enable_reg(); return (locked_regs.size() > 0); endfunction @@ -136,7 +145,7 @@ class dv_base_reg extends uvm_reg; // no need to update shadow value or access type if access is not OK, as access is aborted if (rw.status != UVM_IS_OK) return; - if (is_shadowed) begin + if (is_shadowed && !shadow_fatal_lock) begin // first write if (!shadow_wr_staged) begin shadow_wr_staged = 1; @@ -158,7 +167,8 @@ class dv_base_reg extends uvm_reg; field_access = fields[0].get_access(); case (field_access) // rw.value is a dynamic array - "W1C": if (rw.value[0][0] == 1'b1) set_locked_regs_access("RO"); + // discussed in issue #1922: enable register is standarized to W0C or RO (if HW has write + // access). "W0C": if (rw.value[0][0] == 1'b0) set_locked_regs_access("RO"); "RO": ; // if RO, it's updated by design, need to predict in scb default:`uvm_fatal(`gfn, $sformatf("enable register invalid access %s", field_access)) @@ -198,15 +208,20 @@ class dv_base_reg extends uvm_reg; if (is_shadowed) atomic_shadow_wr.put(1); endtask - // override do_predict function to support shadow_reg: - // skip predict if it is shadow_reg's first write, or second write with an update_err + // Override do_predict function to support shadow_reg. + // Skip predict in one of the following conditions: + // 1). It is shadow_reg's first write. + // 2). It is shadow_reg's second write with an update_err. + // 2). The shadow_reg is locked due to fatal storage error and it is not a backdoor write. + virtual function void do_predict (uvm_reg_item rw, uvm_predict_e kind = UVM_PREDICT_DIRECT, uvm_reg_byte_en_t be = -1); - if (is_shadowed && (shadow_wr_staged || shadow_update_err) && kind != UVM_PREDICT_READ) begin - `uvm_info(`gfn, - $sformatf("skip predict csr %s: due to shadow_reg_first_wr=%0b or update_err=%0b", - get_name(), shadow_wr_staged, shadow_update_err), UVM_HIGH) + if (is_shadowed && kind != UVM_PREDICT_READ && (shadow_wr_staged || shadow_update_err || + (shadow_fatal_lock && rw.path != UVM_BACKDOOR))) begin + `uvm_info(`gfn, $sformatf( + "skip predict %s: due to shadow_reg_first_wr=%0b, update_err=%0b, shadow_fatal_lock=%0b", + get_name(), shadow_wr_staged, shadow_update_err, shadow_fatal_lock), UVM_HIGH) return; end super.do_predict(rw, kind, be); @@ -221,12 +236,15 @@ class dv_base_reg extends uvm_reg; input int lineno = 0); if (kind == "BkdrRegPathRtlShadow") shadowed_val = value; else if (kind == "BkdrRegPathRtlCommitted") committed_val = value; + super.poke(status, value, kind, parent, extension, fname, lineno); endtask - // callback function to update shadowed values according to specific design - // should only be called after post-write + // Callback function to update shadowed values according to specific design. + // Should only be called after post-write. + // If a shadow reg is locked due to fatal error, this function will return without updates virtual function void update_shadowed_val(uvm_reg_data_t val, bit do_predict = 1); + if (shadow_fatal_lock) return; if (shadow_wr_staged) begin // update value after first write staged_shadow_val = val; @@ -248,6 +266,7 @@ class dv_base_reg extends uvm_reg; if (is_shadowed) begin shadow_update_err = 0; shadow_wr_staged = 0; + shadow_fatal_lock = 0; committed_val = get_mirrored_value(); shadowed_val = ~committed_val; // in case reset is issued during shadowed writes @@ -257,4 +276,41 @@ class dv_base_reg extends uvm_reg; atomic_en_shadow_wr.put(1); end endfunction + + function void add_update_err_alert(string name); + if (update_err_alert_name == "") update_err_alert_name = name; + endfunction + + function void add_storage_err_alert(string name); + if (storage_err_alert_name == "") storage_err_alert_name = name; + endfunction + + function string get_update_err_alert_name(); + string parent_name = this.get_parent().get_name(); + + // block level alert name is input alert name from hjson + if (parent_name == "ral") return update_err_alert_name; + + // top-level alert name is ${block_name} + alert name from hjson + return ($sformatf("%0s_%0s", parent_name, update_err_alert_name)); + endfunction + + function void lock_shadow_reg(); + shadow_fatal_lock = 1; + endfunction + + function bit shadow_reg_is_locked(); + return shadow_fatal_lock; + endfunction + + function string get_storage_err_alert_name(); + string parent_name = this.get_parent().get_name(); + + // block level alert name is input alert name from hjson + if (parent_name == "ral") return storage_err_alert_name; + + // top-level alert name is ${block_name} + alert name from hjson + return ($sformatf("%0s_%0s", parent_name, storage_err_alert_name)); + endfunction + 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 b31220eb..34dbf861 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 @@ -34,6 +34,7 @@ class dv_base_reg_block extends uvm_reg_block; function void get_dv_base_regs(ref dv_base_reg dv_regs[$]); uvm_reg ral_regs[$]; + // if the ral has hier, this function will recursively includes the registers in the sub-blocks this.get_registers(ral_regs); foreach (ral_regs[i]) `downcast(dv_regs[i], ral_regs[i]) endfunction @@ -48,17 +49,18 @@ class dv_base_reg_block extends uvm_reg_block; endfunction function void get_enable_regs(ref dv_base_reg enable_regs[$]); - dv_base_reg_block blks[$]; - get_dv_base_reg_blocks(blks); - if (blks.size() == 0) begin - dv_base_reg all_regs[$]; - this.get_dv_base_regs(all_regs); - foreach (all_regs[i]) begin - if (all_regs[i].is_enable_reg()) enable_regs.push_back(all_regs[i]); - end - return; - end else begin - foreach (blks[i]) blks[i].get_enable_regs(enable_regs); + dv_base_reg all_regs[$]; + this.get_dv_base_regs(all_regs); + foreach (all_regs[i]) begin + if (all_regs[i].is_enable_reg()) enable_regs.push_back(all_regs[i]); + end + endfunction + + function void get_shadowed_regs(ref dv_base_reg shadowed_regs[$]); + dv_base_reg all_regs[$]; + this.get_dv_base_regs(all_regs); + foreach (all_regs[i]) begin + if (all_regs[i].get_is_shadowed()) shadowed_regs.push_back(all_regs[i]); end 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 d1c1a3ef..08824670 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 @@ -9,6 +9,29 @@ class dv_base_reg_field extends uvm_reg_field; `uvm_object_utils(dv_base_reg_field) `uvm_object_new + // Issue #5105: UVM forces the value member to be non-randomizable for certain access policies. + // We restore it in this extended class. + virtual function void configure(uvm_reg parent, + int unsigned size, + int unsigned lsb_pos, + string access, + bit volatile, + uvm_reg_data_t reset, + bit has_reset, + bit is_rand, + bit individually_accessible); + super.configure(.parent (parent), + .size (size), + .lsb_pos (lsb_pos), + .access (access), + .volatile (volatile), + .reset (reset), + .has_reset(has_reset), + .is_rand (is_rand), + .individually_accessible(individually_accessible)); + value.rand_mode(is_rand); + endfunction + // when use UVM_PREDICT_WRITE and the CSR access is WO, this function will return the default // val of the register, rather than the written value virtual function uvm_reg_data_t XpredictX(uvm_reg_data_t cur_val, 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 27afc14b..565056ed 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 @@ -8,9 +8,16 @@ class dv_base_env_cfg #(type RAL_T = dv_base_reg_block) extends uvm_object; bit en_scb = 1; // can be changed at run-time bit en_scb_tl_err_chk = 1; bit en_scb_mem_chk = 1; - bit en_cov = 1; + bit en_cov = 0; // Enable via plusarg, only if coverage collection is turned on. bit has_ral = 1; bit under_reset = 0; + bit is_initialized; // Indicates that the initialize() method has been called. + + // The scope and runtime of a existing test can be reduced by setting this variable. This is + // useful to keep the runtime down especially in time-sensitive runs such as CI, which is meant + // to check the code health and not find design bugs. It is set via plusarg and retrieved in + // `dv_base_test`. + bit smoke_test = 0; // bit to configure all uvcs with zero delays to create high bw test rand bit zero_delays; @@ -40,8 +47,12 @@ class dv_base_env_cfg #(type RAL_T = dv_base_reg_block) extends uvm_object; `uvm_object_new + function void pre_randomize(); + `DV_CHECK_FATAL(is_initialized, "Please invoke initialize() before randomizing this object.") + endfunction + virtual function void initialize(bit [bus_params_pkg::BUS_AW-1:0] csr_base_addr = '1); - import bus_params_pkg::*; + is_initialized = 1'b1; // build the ral model if (has_ral) begin @@ -63,7 +74,7 @@ class dv_base_env_cfg #(type RAL_T = dv_base_reg_block) extends uvm_object; // correctly handle the case where a bus address is narrower than a uvm_reg_addr_t). base_addr = (&csr_base_addr ? {`UVM_REG_ADDR_WIDTH{1'b1}} : - {{(`UVM_REG_ADDR_WIDTH - BUS_AW){1'b0}}, csr_base_addr}); + {{(`UVM_REG_ADDR_WIDTH - bus_params_pkg::BUS_AW){1'b0}}, csr_base_addr}); ral.set_base_addr(base_addr); // Get list of valid csr addresses (useful in seq to randomize addr as well as in scb checks) diff --git a/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_scoreboard.sv b/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_scoreboard.sv index f2e57cf9..00a99929 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_scoreboard.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_scoreboard.sv @@ -33,9 +33,12 @@ class dv_base_scoreboard #(type RAL_T = dv_base_reg_block, if (!cfg.clk_rst_vif.rst_n) begin `uvm_info(`gfn, "reset occurred", UVM_HIGH) cfg.reset_asserted(); + csr_utils_pkg::reset_asserted(); @(posedge cfg.clk_rst_vif.rst_n); reset(); cfg.reset_deasserted(); + csr_utils_pkg::clear_outstanding_access(); + csr_utils_pkg::reset_deasserted(); `uvm_info(`gfn, "out of reset", UVM_HIGH) end else begin @@ -47,7 +50,9 @@ class dv_base_scoreboard #(type RAL_T = dv_base_reg_block, virtual function void reset(string kind = "HARD"); // reset the ral model - if (cfg.has_ral) ral.reset(kind); + if (cfg.has_ral) begin + foreach (cfg.ral_models[i]) cfg.ral_models[i].reset(kind); + end endfunction virtual function void pre_abort(); 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 5435b827..25ad402c 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 @@ -14,6 +14,8 @@ class dv_base_test #(type CFG_T = dv_base_env_cfg, uint max_quit_count = 1; uint64 test_timeout_ns = 200_000_000; // 200ms uint drain_time_ns = 2_000; // 2us + bit poll_for_stop = 1'b1; + uint poll_for_stop_interval_ns = 1000; `uvm_component_new @@ -25,17 +27,23 @@ class dv_base_test #(type CFG_T = dv_base_env_cfg, env = ENV_T::type_id::create("env", this); cfg = CFG_T::type_id::create("cfg", this); - // don't add args for initialize. Use default value instead cfg.initialize(); `DV_CHECK_RANDOMIZE_FATAL(cfg) uvm_config_db#(CFG_T)::set(this, "env", "cfg", cfg); - // knob to en/dis scb (enabled by default) + // Enable scoreboard (and sub-scoreboard checks) via plusarg. void'($value$plusargs("en_scb=%0b", cfg.en_scb)); void'($value$plusargs("en_scb_tl_err_chk=%0b", cfg.en_scb_tl_err_chk)); void'($value$plusargs("en_scb_mem_chk=%0b", cfg.en_scb_mem_chk)); - // knob to cfg all agents with zero delays + + // Enable fastest design performance by configuring zero delays in all agents. void'($value$plusargs("zero_delays=%0b", cfg.zero_delays)); + + // Enable coverage collection. + void'($value$plusargs("en_cov=%0b", cfg.en_cov)); + + // Enable reduced runtime test. + void'($value$plusargs("smoke_test=%0b", cfg.smoke_test)); endfunction : build_phase virtual function void end_of_elaboration_phase(uvm_phase phase); @@ -49,17 +57,22 @@ class dv_base_test #(type CFG_T = dv_base_env_cfg, virtual task run_phase(uvm_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)); + void'($value$plusargs("poll_for_stop_interval_ns=%0d", poll_for_stop_interval_ns)); + if (poll_for_stop) dv_utils_pkg::poll_for_stop(.interval_ns(poll_for_stop_interval_ns)); void'($value$plusargs("UVM_TEST_SEQ=%0s", test_seq_s)); if (run_test_seq) begin run_seq(test_seq_s, phase); end - // TODO: add hook for end of test checking + // TODO: add hook for end of test checking. endtask : run_phase virtual task run_seq(string test_seq_s, uvm_phase phase); uvm_sequence test_seq = create_seq_by_name(test_seq_s); - // provide virtual_sequencer earlier, so we may use the p_sequencer in constraint + // 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); `DV_CHECK_RANDOMIZE_FATAL(test_seq) @@ -70,7 +83,7 @@ class dv_base_test #(type CFG_T = dv_base_env_cfg, `uvm_info(`gfn, {"Finished test sequence ", test_seq_s}, UVM_MEDIUM) endtask - // TODO: add default report_phase implementation + // TODO: Add default report_phase implementation. endclass : dv_base_test 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 6e0d4479..ffd4b7fb 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 @@ -25,7 +25,7 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block, // knobs to enable pre_start routines bit do_dut_init = 1'b1; bit do_apply_reset = 1'b1; - bit do_wait_for_reset = 1'b1; + bit do_wait_for_reset = 1'b0; // knobs to enable post_start routines bit do_dut_shutdown = 1'b1; @@ -86,13 +86,7 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block, virtual task apply_reset(string kind = "HARD"); if (kind == "HARD") begin - csr_utils_pkg::reset_asserted(); cfg.clk_rst_vif.apply_reset(); - csr_utils_pkg::clear_outstanding_access(); - csr_utils_pkg::reset_deasserted(); - end - if (cfg.has_ral) begin - foreach (cfg.ral_models[i]) cfg.ral_models[i].reset(kind); end endtask diff --git a/dv/fcov/dv_fcov.core b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_fcov_macros.core similarity index 83% rename from dv/fcov/dv_fcov.core rename to vendor/lowrisc_ip/dv/sv/dv_utils/dv_fcov_macros.core index 32688bcb..02c03356 100644 --- a/dv/fcov/dv_fcov.core +++ b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_fcov_macros.core @@ -2,8 +2,8 @@ CAPI=2: # Copyright lowRISC contributors. # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -name: "lowrisc:dv:dv_fcov" -description: "DV FCOV utilities" +name: "lowrisc:dv:dv_fcov_macros" +description: "DV FCOV macros" filesets: files_fcov: 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 new file mode 100644 index 00000000..8ca12cdc --- /dev/null +++ b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_fcov_macros.svh @@ -0,0 +1,112 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Include FCOV RTL by default. Disable it for synthesis and where explicitly requested (by defining +// DV_FCOV_DISABLE). +`ifdef SYNTHESIS + `define DV_FCOV_DISABLE +`elsif YOSYS + `define DV_FCOV_DISABLE +`endif + +// Disable instantiations of FCOV coverpoints or covergroups. +`ifdef VERILATOR + `define DV_FCOV_DISABLE_CP +`elsif DV_FCOV_DISABLE + `define DV_FCOV_DISABLE_CP +`endif + +// Instantiates a covergroup in an interface or module. +// +// This macro assumes that a covergroup of the same name as the NAME_ arg is defined in the +// interface or module. It just adds some extra signals and logic to control the creation of the +// covergroup instance with ~bit en_~. This defaults to 0. It is ORed with the external +// COND_ signal. The testbench can modify it at t = 0 based on the test being run. +// NOTE: This is not meant to be invoked inside a class. +// +// NAME_ : Name of the covergroup. +// COND_ : External condition / expr that controls the creation of the covergroup. +// ARGS_ : Arguments to covergroup instance, if any. Args MUST BE wrapped in (..). +`ifndef DV_FCOV_INSTANTIATE_CG +`ifdef DV_FCOV_DISABLE_CP + `define DV_FCOV_INSTANTIATE_CG(NAME_, COND_ = 1'b1, ARGS_ = ()) +`else + `define DV_FCOV_INSTANTIATE_CG(NAME_, COND_ = 1'b1, ARGS_ = ()) \ + bit en_``NAME_ = 1'b0; \ + NAME_ NAME_``_inst; \ + initial begin \ + /* The #1 delay below allows any part of the tb to control the conditions first at t = 0. */ \ + #1; \ + if ((en_``NAME_) || (COND_)) begin \ + $display("%0t: (%0s:%0d) [%m] %0s", $time, `__FILE__, `__LINE__, \ + {"Creating covergroup ", `"NAME_`"}); \ + NAME_``_inst = new``ARGS_; \ + end \ + end +`endif +`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). +`ifndef DV_FCOV_EXPR_SEEN +`ifdef DV_FCOV_DISABLE_CP + `define DV_FCOV_EXPR_SEEN(NAME_, EXPR_) +`else + `define DV_FCOV_EXPR_SEEN(NAME_, EXPR_) cp_``NAME_: coverpoint EXPR_ { bins seen = {1}; } +`endif +`endif + +// Creates a SVA cover that can be used in a covergroup. +// +// This macro creates an unnamed SVA cover from the property (or an expression) `PROP_` and an event +// with the name `EV_NAME_`. When the SVA cover is hit, the event is triggered. A coverpoint can +// cover the `triggered` property of the event. +`ifndef DV_FCOV_SVA +`ifdef DV_FCOV_DISABLE + `define DV_FCOV_SVA(EV_NAME_, PROP_, CLK_ = clk_i, RST_ = rst_ni) +`else + `define DV_FCOV_SVA(EV_NAME_, PROP_, CLK_ = clk_i, RST_ = rst_ni) \ + event EV_NAME_; \ + cover property (@(posedge CLK_) disable iff (RST_ == 0) (PROP_)) begin \ + -> EV_NAME_; \ + end +`endif +`endif + +// Coverage support is not always available but it's useful to include extra fcov signals for +// linting purposes. They need to be marked as unused to avoid warnings. +`ifndef DV_FCOV_MARK_UNUSED + `define DV_FCOV_MARK_UNUSED(TYPE_, NAME_) \ + TYPE_ unused_fcov_``NAME_; \ + assign unused_fcov_``NAME_ = fcov_``NAME_; +`endif + +// Define a signal and expression in the design for capture in functional coverage +`ifndef DV_FCOV_SIGNAL +`ifdef DV_FCOV_DISABLE + `define DV_FCOV_SIGNAL(TYPE_, NAME_, EXPR_) +`else + `define DV_FCOV_SIGNAL(TYPE_, NAME_, EXPR_) \ + TYPE_ fcov_``NAME_; \ + assign fcov_``NAME_ = EXPR_; \ + `DV_FCOV_MARK_UNUSED(TYPE_, NAME_) +`endif +`endif + +// Define a signal and expression in the design for capture in functional coverage depending on +// design configuration. The input GEN_COND_ must be a constant or parameter. +`ifndef DV_FCOV_SIGNAL_GEN_IF +`ifdef DV_FCOV_DISABLE + `define DV_FCOV_SIGNAL_GEN_IF(TYPE_, NAME_, EXPR_, GEN_COND_, DEFAULT_ = '0) +`else + `define DV_FCOV_SIGNAL_GEN_IF(TYPE_, NAME_, EXPR_, GEN_COND_, DEFAULT_ = '0) \ + TYPE_ fcov_``NAME_; \ + if (GEN_COND_) begin : g_fcov_``NAME_ \ + assign fcov_``NAME_ = EXPR_; \ + end else begin : g_no_fcov_``NAME_ \ + assign fcov_``NAME_ = DEFAULT_; \ + end \ + `DV_FCOV_MARK_UNUSED(TYPE_, NAME_) +`endif +`endif 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 4386f135..2ecb41aa 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh +++ b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh @@ -2,9 +2,6 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -`ifndef __DV_MACROS_SVH__ -`define __DV_MACROS_SVH__ - `ifdef UVM `include "uvm_macros.svh" `endif @@ -270,7 +267,7 @@ // print static/dynamic 1d array or queue `ifndef DV_PRINT_ARR_CONTENTS -`define DV_PRINT_ARR_CONTENTS(ARR_, V_=UVM_MEDIUM, ID_=`gfn) \ +`define DV_PRINT_ARR_CONTENTS(ARR_, V_=uvm_pkg::UVM_MEDIUM, ID_=`gfn) \ begin \ foreach (ARR_[i]) begin \ `dv_info($sformatf("%s[%0d] = 0x%0d[0x%0h]", `"ARR_`", i, ARR_[i], ARR_[i]), V_, ID_) \ @@ -364,7 +361,7 @@ begin \ EXIT_ \ if (MSG_ != "") begin \ - `dv_info(MSG_, UVM_HIGH, ID_) \ + `dv_info(MSG_, uvm_pkg::UVM_HIGH, ID_) \ end \ end \ join_any \ @@ -438,7 +435,7 @@ `ifdef UVM `ifndef dv_info // verilog_lint: waive macro-name-style - `define dv_info(MSG_, VERBOSITY_ = UVM_LOW, ID_ = $sformatf("%m")) \ + `define dv_info(MSG_, VERBOSITY_ = uvm_pkg::UVM_LOW, ID_ = $sformatf("%m")) \ if (uvm_pkg::uvm_report_enabled(VERBOSITY_, uvm_pkg::UVM_INFO, ID_)) begin \ uvm_pkg::uvm_report_info(ID_, MSG_, VERBOSITY_, `uvm_file, `uvm_line, "", 1); \ end @@ -495,67 +492,3 @@ `endif `endif // UVM - -// Declare array of alert interface, using parameter NUM_ALERTS and LIST_OF_ALERTS, and connect to -// arrays of wires (alert_tx and alert_rx). User need to manually connect these wires to DUT -// Also set each alert_if to uvm_config_db to use in env -`ifndef DV_ALERT_IF_CONNECT -`define DV_ALERT_IF_CONNECT \ - alert_esc_if alert_if[NUM_ALERTS](.clk(clk), .rst_n(rst_n)); \ - prim_alert_pkg::alert_rx_t [NUM_ALERTS-1:0] alert_rx; \ - prim_alert_pkg::alert_tx_t [NUM_ALERTS-1:0] alert_tx; \ - for (genvar k = 0; k < NUM_ALERTS; k++) begin : connect_alerts_pins \ - assign alert_rx[k] = alert_if[k].alert_rx; \ - assign alert_if[k].alert_tx = alert_tx[k]; \ - initial begin \ - uvm_config_db#(virtual alert_esc_if)::set(null, $sformatf("*.env.m_alert_agent_%0s", \ - LIST_OF_ALERTS[k]), "vif", alert_if[k]); \ - end \ - end -`endif - -// Instantiates a covergroup in an interface or module. -// -// This macro assumes that a covergroup of the same name as the __CG_NAME arg is defined in the -// interface or module. It just adds some extra signals and logic to control the creation of the -// covergroup instance with ~bit en_~. This defaults to 0. It is ORed with the external -// __COND signal. The testbench can modify it at t = 0 based on the test being run. -// NOTE: This is not meant to be invoked inside a class. -// -// __CG_NAME : Name of the covergroup. -// __COND : External condition / expr that controls the creation of the covergroup. -// __CG_ARGS : Arguments to covergroup instance, if any. Args MUST BE wrapped in (..). -`ifndef DV_INSTANTIATE_CG -`define DV_INSTANTIATE_CG(__CG_NAME, __COND = 1'b1, __CG_ARGS = ()) \ - bit en_``__CG_NAME = 1'b0; \ - __CG_NAME __CG_NAME``_inst; \ - initial begin \ - /* The #1 delay below allows any part of the tb to control the conditions first at t = 0. */ \ - #1; \ - if ((en_``__CG_NAME) || (__COND)) begin \ - `dv_info({"Creating covergroup ", `"__CG_NAME`"}, UVM_MEDIUM) \ - __CG_NAME``_inst = new``__CG_ARGS; \ - end \ - end -`endif - -// Creates a SVA cover that can be used in a covergroup. -// -// This macro creates an unnamed SVA cover from the expression `__sva` and an event with the name -// `__ev_name`. When the SVA cover is hit, the event is triggered. A coverpoint can cover the -// `triggered` property of the event. -`ifndef DV_FCOV_SVA -`define DV_FCOV_SVA(__ev_name, __sva, __clk = clk_i, __rst = rst_ni) \ - event __ev_name; \ - cover property (@(posedge __clk) disable iff (__rst == 0) (__sva)) begin \ - -> __ev_name; \ - end -`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). -`ifndef DV_FCOV_EXPR_SEEN -`define DV_FCOV_EXPR_SEEN(__cp_name, __expr) __cp_name: coverpoint __expr { bins seen = {1}; } -`endif - -`endif // __DV_MACROS_SVH__ diff --git a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils.core b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils.core index 183b66b3..90df9573 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils.core +++ b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils.core @@ -9,6 +9,7 @@ filesets: files_dv: depend: - lowrisc:dv:dv_macros + - lowrisc:dv:dv_fcov_macros - lowrisc:dv:common_ifs - lowrisc:prim:assert:0.1 - lowrisc:ibex:bus_params_pkg 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 5a36fe22..d411b5ef 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 @@ -92,11 +92,20 @@ package dv_utils_pkg; return val >= 0 ? val : -val; endfunction - // endian swap + // endian swaps a 32-bit data word function automatic logic [31:0] endian_swap(logic [31:0] data); return {<<8{data}}; endfunction + // endian swaps bytes at a word granularity, while preserving overall word ordering. + // + // e.g. if `arr[] = '{'h0, 'h1, 'h2, 'h3, 'h4, 'h5, 'h6, 'h7}`, this function will produce: + // `'{'h3, 'h2, 'h1, 'h0, 'h7, 'h6, 'h5, 'h4}` + function automatic void endian_swap_byte_arr(ref bit [7:0] arr[]); + arr = {<< byte {arr}}; + arr = {<< 32 {arr}}; + endfunction + `ifdef UVM // Simple function to set max errors before quitting sim function automatic void set_max_quit_count(int n); @@ -171,6 +180,20 @@ package dv_utils_pkg; return (hier.substr(0, idx - 1)); endfunction + // Periodically check for the existence of a magic file (dv.stop). Exit if it exists. This + // provides a mechanism to gracefully kill a simulation without direct access to the process. + task automatic poll_for_stop(uint interval_ns = 1000, string filename = "dv.stop"); + fork + while (1) begin + #(interval_ns * 1ns); + if (!$system($sformatf("test -f %0s", filename))) begin + $system($sformatf("rm %0s", filename)); + `dv_fatal($sformatf("Found %0s file. Exiting!", filename), "poll_for_stop") + end + end + join_none + endtask : poll_for_stop + // sources `ifdef UVM `include "dv_report_server.sv" diff --git a/vendor/lowrisc_ip/dv/sv/str_utils/str_utils_pkg.sv b/vendor/lowrisc_ip/dv/sv/str_utils/str_utils_pkg.sv index f0a62f42..19494d3a 100644 --- a/vendor/lowrisc_ip/dv/sv/str_utils/str_utils_pkg.sv +++ b/vendor/lowrisc_ip/dv/sv/str_utils/str_utils_pkg.sv @@ -119,6 +119,15 @@ package str_utils_pkg; end endfunction : str_to_bytes + // Converts an array of bytes to a string. + function automatic string bytes_to_str(byte bytes[]); + string s; + foreach (bytes[i]) begin + s = {s, string'(bytes[i])}; + end + return s; + endfunction + /************************/ /* File path functions. */ /************************/ diff --git a/vendor/lowrisc_ip/dv/tools/common.tcl b/vendor/lowrisc_ip/dv/tools/common.tcl index f9a941d1..7279aefc 100644 --- a/vendor/lowrisc_ip/dv/tools/common.tcl +++ b/vendor/lowrisc_ip/dv/tools/common.tcl @@ -17,8 +17,9 @@ if {[info exists ::env(WAVES)]} { } set tb_top "tb" -if {[info exists ::(TB_TOP)]} { +if {[info exists ::env(TB_TOP)]} { set tb_top "$::env(TB_TOP)" +} else { puts "WARNING: TB_TOP environment variable not set - using \"tb\" as the top level testbench hierarchy." } diff --git a/vendor/lowrisc_ip/dv/tools/dvsim/common_modes.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/common_modes.hjson index 6730dd12..16b9e68e 100644 --- a/vendor/lowrisc_ip/dv/tools/dvsim/common_modes.hjson +++ b/vendor/lowrisc_ip/dv/tools/dvsim/common_modes.hjson @@ -16,6 +16,9 @@ name: cov is_sim_mode: 1 en_build_modes: ["{tool}_cov"] + // This plusarg is retrieved in `hw/dv/sv/dv_lib/dv_base_test.sv`. If not set, the coverage + // collection components are not created. + run_opts: ["+en_cov=1"] } { name: profile 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 6a6c37e7..6e013b62 100644 --- a/vendor/lowrisc_ip/dv/tools/dvsim/common_sim_cfg.hjson +++ b/vendor/lowrisc_ip/dv/tools/dvsim/common_sim_cfg.hjson @@ -62,7 +62,8 @@ "+define+UVM_REGEX_NO_DPI", "+define+UVM_REG_ADDR_WIDTH={tl_aw}", "+define+UVM_REG_DATA_WIDTH={tl_dw}", - "+define+UVM_REG_BYTENABLE_WIDTH={tl_dbw}"] + "+define+UVM_REG_BYTENABLE_WIDTH={tl_dbw}", + "+define+SIMULATION"] run_opts: ["+UVM_NO_RELNOTES", "+UVM_VERBOSITY={expand_uvm_verbosity_{verbosity}}"] @@ -110,6 +111,8 @@ name: smoke tests: [] reseed: 1 + // Knob used to configure an existing test / vseq to have a shorter runtime. + run_opts: ["+smoke_test=1"] } { diff --git a/vendor/lowrisc_ip/dv/tools/dvsim/vcs.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/vcs.hjson index 784839e3..9ff21fd7 100644 --- a/vendor/lowrisc_ip/dv/tools/dvsim/vcs.hjson +++ b/vendor/lowrisc_ip/dv/tools/dvsim/vcs.hjson @@ -192,6 +192,7 @@ // Vars that need to exported to the env. exports: [ + { FLEXLM_DIAGNOSTICS: 4 }, { VCS_ARCH_OVERRIDE: "linux" }, { VCS_LIC_EXPIRE_WARNING: 1 } ] diff --git a/vendor/lowrisc_ip/dv/tools/dvsim/verilator.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/verilator.hjson index 76da9333..5ad0adea 100644 --- a/vendor/lowrisc_ip/dv/tools/dvsim/verilator.hjson +++ b/vendor/lowrisc_ip/dv/tools/dvsim/verilator.hjson @@ -43,6 +43,11 @@ ] // -- END -- + // Remove {proj_root}/hw/foundry from FuseSoC cores search if it exists. + pre_build_cmds: ['''if [ -d {proj_root}/hw/foundry ]; then \ + touch {proj_root}/hw/foundry/FUSESOC_IGNORE; \ + fi'''] + build_cmd: "fusesoc {fusesoc_cores_root_dirs} run" ex_name: "{eval_cmd} echo \"{fusesoc_core}\" | cut -d: -f3" run_cmd: "{build_dir}/sim-verilator/V{ex_name}" diff --git a/vendor/lowrisc_ip/dv/tools/waves.tcl b/vendor/lowrisc_ip/dv/tools/waves.tcl index 23f806a8..af8fd627 100644 --- a/vendor/lowrisc_ip/dv/tools/waves.tcl +++ b/vendor/lowrisc_ip/dv/tools/waves.tcl @@ -19,6 +19,7 @@ global tb_top set wavedump_db "waves.$waves" # TODO: convert this to a proc? +set fid "" switch $waves { "none" { puts "INFO: Dumping waves is not enabled." @@ -39,7 +40,7 @@ switch $waves { "vpd" { checkEq simulator "vcs" - dump -file $wavedump_db -type VPD + set fid [dump -file $wavedump_db -type VPD] } "vcd" { @@ -76,13 +77,14 @@ if {$waves ne "none"} { # simulation. It is useful in that case to only dump the relevant scopes of interest during debug. # # scope : Design / testbench hierarchy to dump waves. Defaults to $tb_top. +# fid : File ID returned by the dump command in the first step above. # depth : Levels in the hierarchy to dump waves. Defaults to 0 (dump all levels). # fsdb_flags : Additional string flags passed to fsdbDumpVars. Defaults to "+all". # probe_flags : Additional string flags passed to probe command (Xcelium). Defaults to "-all". # dump_flags : Additional string flags passed to dump command (VCS). Defaults to "-aggregates". # # Depending on the need, more such technlogy specific flags can be added in future. -proc wavedumpScope {scope {depth 0} {fsdb_flags "+all"} {probe_flags "-all"} +proc wavedumpScope {scope fid {depth 0} {fsdb_flags "+all"} {probe_flags "-all"} {dump_flags "-aggregates"}} { global simulator global waves @@ -114,7 +116,7 @@ proc wavedumpScope {scope {depth 0} {fsdb_flags "+all"} {probe_flags "-all"} "vpd" { # The dump command switch -aggregates enables dumping of structs & # arrays. - dump -add "$scope" -depth $depth $dump_flags + dump -add "$scope" -fid $fid -depth $depth $dump_flags } "vcd" { @@ -154,5 +156,5 @@ setDefault dump_tb_top 1 # By default, add the full test bench scope for wavedump. if {$dump_tb_top == 1} { - wavedumpScope $tb_top + wavedumpScope $tb_top $fid } diff --git a/vendor/lowrisc_ip/dv/verilator/cpp/verilator_memutil.cc b/vendor/lowrisc_ip/dv/verilator/cpp/verilator_memutil.cc index 9f6c3178..7e46497d 100644 --- a/vendor/lowrisc_ip/dv/verilator/cpp/verilator_memutil.cc +++ b/vendor/lowrisc_ip/dv/verilator/cpp/verilator_memutil.cc @@ -98,6 +98,7 @@ bool VerilatorMemUtil::ParseCLIArguments(int argc, char **argv, {"rominit", required_argument, nullptr, 'r'}, {"raminit", required_argument, nullptr, 'm'}, {"flashinit", required_argument, nullptr, 'f'}, + {"otpinit", required_argument, nullptr, 'o'}, {"meminit", required_argument, nullptr, 'l'}, {"verbose-mem-load", no_argument, nullptr, 'V'}, {"load-elf", required_argument, nullptr, 'E'}, @@ -134,6 +135,10 @@ bool VerilatorMemUtil::ParseCLIArguments(int argc, char **argv, load_args.push_back( {.name = "flash", .filepath = optarg, .type = kMemImageUnknown}); break; + case 'o': + load_args.push_back( + {.name = "otp", .filepath = optarg, .type = kMemImageUnknown}); + break; case 'l': if (strcasecmp(optarg, "list") == 0) { mem_util_->PrintMemRegions(); diff --git a/vendor/lowrisc_ip/ip/prim/doc/prim_flash.md b/vendor/lowrisc_ip/ip/prim/doc/prim_flash.md index 52381f67..779397cd 100644 --- a/vendor/lowrisc_ip/ip/prim/doc/prim_flash.md +++ b/vendor/lowrisc_ip/ip/prim/doc/prim_flash.md @@ -29,7 +29,7 @@ TestModeWidth | int | The number of test modes for a bank of flash Name | In/Out | Description ------------------------|--------|--------------------------------- clk_i | input | Clock input -rst_n_i | input | Reset input +rst_ni | input | Reset input flash_req_i | input | Inputs from flash protocol and physical controllers flash_rsp_o | output | Outputs to flash protocol and physical controllers prog_type_avail_o | output | Available program types in this flash wrapper: Currently there are only two types, program normal and program repair @@ -41,14 +41,14 @@ tdo_o | output | jtag tdo bist_enable_i | input | lc_ctrl_pkg :: On for bist_enable input scanmode_i | input | dft scanmode input scan_en_i | input | dft scan shift input -scan_rst_n_i | input | dft scanmode reset +scan_rst_ni | input | dft scanmode reset flash_power_ready_h_i | input | flash power is ready (high voltage connection) flash_power_down_h_i | input | flash wrapper is powering down (high voltage connection) flash_test_mode_a_i | input | flash test mode values (analog connection) flash_test_voltage_h_i | input | flash test mode voltage (high voltage connection) flash_err_o | output | flash level error interrupt indication, cleared on write 1 to status register -flash_alert_po | output | flash positive detector alert -flash_alert_no | output | flash negative detector alert +flash_alert_po | output | flash positive detector alert +flash_alert_no | output | flash negative detector alert flash_alert_ack | input | single pulse ack flash_alert_trig | input | alert force trig by SW tl_i | input | TL_UL interface for rd/wr registers access @@ -148,7 +148,7 @@ A program type not supported by the wrapper, indicated through `prog_type_avail` ## Erase Suspend Since erase operations can take a significant amount of time, sometimes it is necessary for software or other components to suspend the operation. -The suspend operation input request starts with `erase_suspend_req` assertion. Flash wrapper circuit acks when wrapper starts suspend. +The suspend operation input request starts with `erase_suspend_req` assertion. Flash wrapper circuit acks when wrapper starts suspend. When the erase suspend completes, the flash wrapper circuitry also asserts `done` for the ongoing erase transaction to ensure all hardware gracefully completes. The following is an example diagram diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_sim.core b/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_sim.core index c70bd3b6..3eff6f48 100644 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_sim.core +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_sim.core @@ -13,6 +13,7 @@ filesets: files_dv: depend: - lowrisc:dv:dv_utils + - lowrisc:dv:dv_test_status - lowrisc:dv:common_ifs files: - tb/prim_lfsr_tb.sv diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/tb/prim_lfsr_tb.sv b/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/tb/prim_lfsr_tb.sv index 1422af8e..c31e3949 100644 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/tb/prim_lfsr_tb.sv +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/tb/prim_lfsr_tb.sv @@ -166,7 +166,7 @@ module prim_lfsr_tb; lfsr_en = '0; err = '0; - main_clk.set_period_ns(ClkPeriod); + main_clk.set_period_ps(ClkPeriod); main_clk.set_active(); main_clk.apply_reset(); @@ -209,19 +209,18 @@ module prim_lfsr_tb; end end - if (!err) begin - $display("All LFSRs from %0d bit to %0d have maximum length!", - MinLfsrDw, MaxLfsrDw); - // signature for makefile - $display("TEST PASSED CHECKS"); - end else begin - $display("One or more checks have failed!"); - // signature for makefile - $display("TEST FAILED CHECKS"); - end - + if (!err) $display("All LFSRs from %0d bit to %0d have maximum length!", MinLfsrDw, MaxLfsrDw); + dv_test_status_pkg::dv_test_status(.passed(!err)); $finish(); end + // TODO: perhaps wrap this in a macro? + initial begin + bit poll_for_stop = 1'b1; + int unsigned poll_for_stop_interval_ns = 1000; + void'($value$plusargs("poll_for_stop=%0b", poll_for_stop)); + void'($value$plusargs("poll_for_stop_interval_ns=%0d", poll_for_stop_interval_ns)); + if (poll_for_stop) dv_utils_pkg::poll_for_stop(.interval_ns(poll_for_stop_interval_ns)); + end endmodule : prim_lfsr_tb diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_present/data/prim_present_testplan.hjson b/vendor/lowrisc_ip/ip/prim/dv/prim_present/data/prim_present_testplan.hjson deleted file mode 100644 index dc3dfe95..00000000 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_present/data/prim_present_testplan.hjson +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 -{ - name: "prim_present" - import_testplans: [] - entries: [ - { - name: smoke - desc: '''Simple PRESENT test - feed golden and random testvectors into - both the encryption and decryption algorithms and verify that all - outputs match those from the reference model.''' - milestone: V2 - tests: ["prim_present_smoke"] - } - ] -} diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_present/prim_present_sim.core b/vendor/lowrisc_ip/ip/prim/dv/prim_present/prim_present_sim.core index 0356b784..5fcb3d42 100644 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_present/prim_present_sim.core +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_present/prim_present_sim.core @@ -12,6 +12,9 @@ filesets: files_dv: depend: + - lowrisc:dv:dv_utils + - lowrisc:dv:dv_macros + - lowrisc:dv:dv_test_status - lowrisc:dv:crypto_dpi_present:0.1 files: - tb/prim_present_tb.sv diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_present/prim_present_sim_cfg.hjson b/vendor/lowrisc_ip/ip/prim/dv/prim_present/prim_present_sim_cfg.hjson index 2d5c95b6..7704798e 100644 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_present/prim_present_sim_cfg.hjson +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_present/prim_present_sim_cfg.hjson @@ -17,9 +17,6 @@ // Fusesoc core file used for building the file list. fusesoc_core: lowrisc:dv:prim_present_sim:0.1 - // Testplan hjson file. - testplan: "{proj_root}/hw/ip/prim/dv/prim_present/data/prim_present_testplan.hjson" - // Import additional common sim cfg files. import_cfgs: ["{proj_root}/hw/dv/tools/dvsim/common_sim_cfg.hjson"] @@ -36,7 +33,7 @@ // List of test specifications. tests: [ { - name: prim_present_smoke + name: prim_present_test } ] @@ -44,7 +41,7 @@ regressions: [ { name: smoke - tests: ["prim_present_smoke"] + tests: ["prim_present_test"] } ] } diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_present/tb/prim_present_tb.sv b/vendor/lowrisc_ip/ip/prim/dv/prim_present/tb/prim_present_tb.sv index 5fe73835..cf351687 100644 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_present/tb/prim_present_tb.sv +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_present/tb/prim_present_tb.sv @@ -11,6 +11,7 @@ // widths remain untested. module prim_present_tb; + `include "dv_macros.svh" ////////////////////////////////////////////////////// // config @@ -42,6 +43,10 @@ module prim_present_tb; // this parameter is required for the DPI model. localparam bit KeySize80 = (KeyWidth == 80); + // This bit can be set from the command line to indicate that we are running a smoke regression, + // and to run just a single iteration of the test. + // This helps drastically reduce runtimes in the CI flows. + bit smoke_test; ////////////////////////////////////////////////////// // DUTs for both encryption and decryption @@ -94,16 +99,13 @@ module prim_present_tb; crypto_dpi_present_pkg::sv_dpi_present_get_key_schedule(key, KeySize80, key_schedule); - $display("Starting encryption pass with data[0x%0x] and key[0x%0x]!", plaintext, key); check_encryption(plaintext, key, key_schedule, encrypted_text); - $display("Starting decryption pass!"); check_decryption(encrypted_text, key, key_out[Encrypt]); endtask - // Helper task to drive plaintext and key into each encryption instance. // Calls a subroutine to perform checks on the outputs (once they are available). task automatic check_encryption(input bit [DataWidth-1:0] plaintext, @@ -194,7 +196,7 @@ module prim_present_tb; break; end end - if (error) $fatal("TEST FAILED CHECKS"); + if (error) dv_test_status_pkg::dv_test_status(.passed(1'b0)); endtask @@ -203,6 +205,8 @@ module prim_present_tb; ////////////////////////////////////////////////////// initial begin : p_stimuli + int num_trans; + string msg_id = $sformatf("%m"); // The key and plaintext/ciphertext to be fed into PRESENT instances. bit [KeyWidth-1:0] key; @@ -231,22 +235,27 @@ module prim_present_tb; test_present(plaintext, key); // Test random vectors - for (int i = 0; i < 5000; i++) begin - if (!std::randomize(plaintext)) begin - $fatal("Randomization of plaintext failed!"); - end - if (!std::randomize(key)) begin - $fatal("Randomization of key failed!"); - end + void'($value$plusargs("smoke_test=%0b", smoke_test)); + num_trans = smoke_test ? 1 : $urandom_range(5000, 25000); + for (int i = 0; i < num_trans; i++) begin + `DV_CHECK_STD_RANDOMIZE_FATAL(plaintext, "", msg_id) + `DV_CHECK_STD_RANDOMIZE_FATAL(key, "", msg_id) test_present(plaintext, key); end - // Final error checking and print out the test signature (expected by simulation flow). $display("All encryption and decryption passes were successful!"); - $display("TEST PASSED CHECKS"); + dv_test_status_pkg::dv_test_status(.passed(1'b1)); $finish(); end + // TODO: perhaps wrap this in a macro? + initial begin + bit poll_for_stop = 1'b1; + int unsigned poll_for_stop_interval_ns = 1000; + void'($value$plusargs("poll_for_stop=%0b", poll_for_stop)); + void'($value$plusargs("poll_for_stop_interval_ns=%0d", poll_for_stop_interval_ns)); + if (poll_for_stop) dv_utils_pkg::poll_for_stop(.interval_ns(poll_for_stop_interval_ns)); + end endmodule : prim_present_tb diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_prince/prim_prince_sim.core b/vendor/lowrisc_ip/ip/prim/dv/prim_prince/prim_prince_sim.core index 02c6e821..38007c08 100644 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_prince/prim_prince_sim.core +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_prince/prim_prince_sim.core @@ -12,9 +12,11 @@ filesets: files_dv: depend: - - lowrisc:dv:crypto_dpi_prince:0.1 - lowrisc:dv:dv_utils + - lowrisc:dv:dv_macros - lowrisc:dv:common_ifs + - lowrisc:dv:dv_test_status + - lowrisc:dv:crypto_dpi_prince files: - tb/prim_prince_tb.sv file_type: systemVerilogSource 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 4d588f24..9f18f551 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 @@ -11,6 +11,7 @@ // widths remain untested. module prim_prince_tb; + `include "dv_macros.svh" ////////////////////////////////////////////////////// // config @@ -44,6 +45,11 @@ module prim_prince_tb; localparam time ClkPeriod = 10000; + // This bit can be set from the command line to indicate that we are running a smoke regression, + // and to run just a single iteration of the test. + // This helps drastically reduce runtimes in the CI flows. + bit smoke_test; + ////////////////////////////////////////////////////// // Clock interface ////////////////////////////////////////////////////// @@ -100,15 +106,14 @@ module prim_prince_tb; bit [KeyWidth-1:0] key); bit [1:0][1:0][NumRoundsHalf-1:0][DataWidth-1:0] encrypted_text; - $display("Starting encryption with data[0x%0x] and key[0x%0x]!", plaintext, key); + check_encryption(plaintext, key, encrypted_text); - $display("Starting decryption pass!"); + check_decryption(encrypted_text, key); endtask - // Helper task to drive plaintext and key into each encryption instance. // Calls a subroutine to perform checks on the outputs (once they are available). task automatic check_encryption( @@ -209,35 +214,36 @@ module prim_prince_tb; err_msg = {$sformatf("%s mismatch in %s design with %0d rounds and old key schedule!\n", msg, reg_msg, i+1), $sformatf("Expected[0x%0x] - Actual[0x%0x]\n", expected_text_old_sched[i][j], - actual_text_old_sched[i][j]), - "TEST FAILED CHECKS"}; - $fatal(err_msg); + actual_text_old_sched[i][j])}; + $error(err_msg); + dv_test_status_pkg::dv_test_status(.passed(1'b0)); end // compare outputs generated using new key schedule. if (expected_text_new_sched[i][j] != actual_text_new_sched[i][j]) begin err_msg = {$sformatf("%s mismatch in %s design with %0d rounds and old key schedule!\n", msg, reg_msg, i+1), $sformatf("Expected[0x%0x] - Actual[0x%0x]\n", expected_text_new_sched[i][j], - actual_text_new_sched[i][j]), - "TEST FAILED CHECKS"}; - $fatal(err_msg); + actual_text_new_sched[i][j])}; + $error(err_msg); + dv_test_status_pkg::dv_test_status(.passed(1'b0)); end end end endtask - ////////////////////////////////////////////////////// // main testbench body ////////////////////////////////////////////////////// initial begin : p_stimuli + int num_trans; + string msg_id = $sformatf("%m"); // The key and plaintext/ciphertext to be fed into PRINCE instances. bit [KeyWidth/2-1:0] k0, k1; bit [DataWidth-1:0] plaintext; - clk_if.set_period_ns(ClkPeriod); + clk_if.set_period_ps(ClkPeriod); clk_if.set_active(); clk_if.apply_reset(); $timeformat(-12, 0, " ps", 12); @@ -273,25 +279,28 @@ module prim_prince_tb; test_prince(plaintext, {k1, k0}); // Test random vectors - for (int i = 0; i < 25000; i++) begin - if (!std::randomize(plaintext)) begin - $fatal("Randomization of plaintext failed!"); - end - if (!std::randomize(k0)) begin - $fatal("Randomization of k0 failed!"); - end - if (!std::randomize(k1)) begin - $fatal("Randomization of k1 failed!"); - end + void'($value$plusargs("smoke_test=%0b", smoke_test)); + num_trans = smoke_test ? 1 : $urandom_range(5000, 25000); + for (int i = 0; i < num_trans; i++) begin + `DV_CHECK_STD_RANDOMIZE_FATAL(plaintext, "", msg_id) + `DV_CHECK_STD_RANDOMIZE_FATAL(k0, "", msg_id) + `DV_CHECK_STD_RANDOMIZE_FATAL(k1, "", msg_id) test_prince(plaintext, {k1, k0}); end - // Final error checking and print out the test signature (expected by simulation flow). $display("All encryption and decryption passes were successful!"); - $display("TEST PASSED CHECKS"); + dv_test_status_pkg::dv_test_status(.passed(1'b1)); $finish(); end + // TODO: perhaps wrap this in a macro? + initial begin + bit poll_for_stop = 1'b1; + int unsigned poll_for_stop_interval_ns = 1000; + void'($value$plusargs("poll_for_stop=%0b", poll_for_stop)); + void'($value$plusargs("poll_for_stop_interval_ns=%0d", poll_for_stop_interval_ns)); + if (poll_for_stop) dv_utils_pkg::poll_for_stop(.interval_ns(poll_for_stop_interval_ns)); + end endmodule : prim_prince_tb diff --git a/vendor/lowrisc_ip/ip/prim/fpv/prim_alert_rxtx_async_fatal_fpv.core b/vendor/lowrisc_ip/ip/prim/fpv/prim_alert_rxtx_async_fatal_fpv.core new file mode 100644 index 00000000..8a8a3492 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/prim_alert_rxtx_async_fatal_fpv.core @@ -0,0 +1,31 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:fpv:prim_alert_rxtx_async_fatal_fpv:0.1" +description: "ALERT_HANDLER rxtx async fatal FPV target" +filesets: + files_formal: + depend: + - lowrisc:prim:all + files: + - vip/prim_alert_rxtx_async_assert_fpv.sv + - tb/prim_alert_rxtx_async_fatal_fpv.sv + - tb/prim_alert_rxtx_async_fatal_bind_fpv.sv + file_type: systemVerilogSource + +targets: + default: &default_target + # note, this setting is just used + # to generate a file list for jg + default_tool: icarus + filesets: + - files_formal + toplevel: + - prim_alert_rxtx_async_fatal_fpv + + formal: + <<: *default_target + + lint: + <<: *default_target diff --git a/vendor/lowrisc_ip/ip/prim/fpv/prim_alert_rxtx_fatal_fpv.core b/vendor/lowrisc_ip/ip/prim/fpv/prim_alert_rxtx_fatal_fpv.core new file mode 100644 index 00000000..23758f37 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/prim_alert_rxtx_fatal_fpv.core @@ -0,0 +1,31 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:fpv:prim_alert_rxtx_fatal_fpv:0.1" +description: "ALERT_HANDLER FPV target" +filesets: + files_formal: + depend: + - lowrisc:prim:all + files: + - vip/prim_alert_rxtx_assert_fpv.sv + - tb/prim_alert_rxtx_fatal_fpv.sv + - tb/prim_alert_rxtx_fatal_bind_fpv.sv + file_type: systemVerilogSource + +targets: + default: &default_target + # note, this setting is just used + # to generate a file list for jg + default_tool: icarus + filesets: + - files_formal + toplevel: + - prim_alert_rxtx_fatal_fpv + + formal: + <<: *default_target + + lint: + <<: *default_target diff --git a/vendor/lowrisc_ip/ip/prim/fpv/prim_secded_22_16_fpv.core b/vendor/lowrisc_ip/ip/prim/fpv/prim_secded_22_16_fpv.core new file mode 100644 index 00000000..5ed01f1f --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/prim_secded_22_16_fpv.core @@ -0,0 +1,33 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:fpv:prim_secded_22_16_fpv:0.1" +description: "SECDED FPV target" +filesets: + files_formal: + depend: + - lowrisc:prim:all + - lowrisc:prim:secded + files: + - vip/prim_secded_22_16_assert_fpv.sv + - tb/prim_secded_22_16_fpv.sv + - tb/prim_secded_22_16_bind_fpv.sv + file_type: systemVerilogSource + +targets: + default: &default_target + # note, this setting is just used + # to generate a file list for jg + default_tool: icarus + filesets: + - files_formal + toplevel: + - prim_secded_22_16_fpv + + formal: + <<: *default_target + + lint: + <<: *default_target + diff --git a/vendor/lowrisc_ip/ip/prim/fpv/prim_secded_28_22_fpv.core b/vendor/lowrisc_ip/ip/prim/fpv/prim_secded_28_22_fpv.core new file mode 100644 index 00000000..12f868aa --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/prim_secded_28_22_fpv.core @@ -0,0 +1,33 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:fpv:prim_secded_28_22_fpv:0.1" +description: "SECDED FPV target" +filesets: + files_formal: + depend: + - lowrisc:prim:all + - lowrisc:prim:secded + files: + - vip/prim_secded_28_22_assert_fpv.sv + - tb/prim_secded_28_22_fpv.sv + - tb/prim_secded_28_22_bind_fpv.sv + file_type: systemVerilogSource + +targets: + default: &default_target + # note, this setting is just used + # to generate a file list for jg + default_tool: icarus + filesets: + - files_formal + toplevel: + - prim_secded_28_22_fpv + + formal: + <<: *default_target + + lint: + <<: *default_target + diff --git a/vendor/lowrisc_ip/ip/prim/fpv/prim_secded_39_32_fpv.core b/vendor/lowrisc_ip/ip/prim/fpv/prim_secded_39_32_fpv.core new file mode 100644 index 00000000..85650dc4 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/prim_secded_39_32_fpv.core @@ -0,0 +1,33 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:fpv:prim_secded_39_32_fpv:0.1" +description: "SECDED FPV target" +filesets: + files_formal: + depend: + - lowrisc:prim:all + - lowrisc:prim:secded + files: + - vip/prim_secded_39_32_assert_fpv.sv + - tb/prim_secded_39_32_fpv.sv + - tb/prim_secded_39_32_bind_fpv.sv + file_type: systemVerilogSource + +targets: + default: &default_target + # note, this setting is just used + # to generate a file list for jg + default_tool: icarus + filesets: + - files_formal + toplevel: + - prim_secded_39_32_fpv + + formal: + <<: *default_target + + lint: + <<: *default_target + diff --git a/vendor/lowrisc_ip/ip/prim/fpv/prim_secded_64_57_fpv.core b/vendor/lowrisc_ip/ip/prim/fpv/prim_secded_64_57_fpv.core new file mode 100644 index 00000000..890cf29f --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/prim_secded_64_57_fpv.core @@ -0,0 +1,33 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:fpv:prim_secded_64_57_fpv:0.1" +description: "SECDED FPV target" +filesets: + files_formal: + depend: + - lowrisc:prim:all + - lowrisc:prim:secded + files: + - vip/prim_secded_64_57_assert_fpv.sv + - tb/prim_secded_64_57_fpv.sv + - tb/prim_secded_64_57_bind_fpv.sv + file_type: systemVerilogSource + +targets: + default: &default_target + # note, this setting is just used + # to generate a file list for jg + default_tool: icarus + filesets: + - files_formal + toplevel: + - prim_secded_64_57_fpv + + formal: + <<: *default_target + + lint: + <<: *default_target + diff --git a/vendor/lowrisc_ip/ip/prim/fpv/prim_secded_72_64_fpv.core b/vendor/lowrisc_ip/ip/prim/fpv/prim_secded_72_64_fpv.core new file mode 100644 index 00000000..d58bf130 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/prim_secded_72_64_fpv.core @@ -0,0 +1,33 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:fpv:prim_secded_72_64_fpv:0.1" +description: "SECDED FPV target" +filesets: + files_formal: + depend: + - lowrisc:prim:all + - lowrisc:prim:secded + files: + - vip/prim_secded_72_64_assert_fpv.sv + - tb/prim_secded_72_64_fpv.sv + - tb/prim_secded_72_64_bind_fpv.sv + file_type: systemVerilogSource + +targets: + default: &default_target + # note, this setting is just used + # to generate a file list for jg + default_tool: icarus + filesets: + - files_formal + toplevel: + - prim_secded_72_64_fpv + + formal: + <<: *default_target + + lint: + <<: *default_target + diff --git a/vendor/lowrisc_ip/ip/prim/fpv/prim_secded_hamming_22_16_fpv.core b/vendor/lowrisc_ip/ip/prim/fpv/prim_secded_hamming_22_16_fpv.core new file mode 100644 index 00000000..07b2e2b8 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/prim_secded_hamming_22_16_fpv.core @@ -0,0 +1,33 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:fpv:prim_secded_hamming_22_16_fpv:0.1" +description: "SECDED FPV target" +filesets: + files_formal: + depend: + - lowrisc:prim:all + - lowrisc:prim:secded + files: + - vip/prim_secded_hamming_22_16_assert_fpv.sv + - tb/prim_secded_hamming_22_16_fpv.sv + - tb/prim_secded_hamming_22_16_bind_fpv.sv + file_type: systemVerilogSource + +targets: + default: &default_target + # note, this setting is just used + # to generate a file list for jg + default_tool: icarus + filesets: + - files_formal + toplevel: + - prim_secded_hamming_22_16_fpv + + formal: + <<: *default_target + + lint: + <<: *default_target + diff --git a/vendor/lowrisc_ip/ip/prim/fpv/prim_secded_hamming_39_32_fpv.core b/vendor/lowrisc_ip/ip/prim/fpv/prim_secded_hamming_39_32_fpv.core new file mode 100644 index 00000000..f6a0846e --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/prim_secded_hamming_39_32_fpv.core @@ -0,0 +1,33 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:fpv:prim_secded_hamming_39_32_fpv:0.1" +description: "SECDED FPV target" +filesets: + files_formal: + depend: + - lowrisc:prim:all + - lowrisc:prim:secded + files: + - vip/prim_secded_hamming_39_32_assert_fpv.sv + - tb/prim_secded_hamming_39_32_fpv.sv + - tb/prim_secded_hamming_39_32_bind_fpv.sv + file_type: systemVerilogSource + +targets: + default: &default_target + # note, this setting is just used + # to generate a file list for jg + default_tool: icarus + filesets: + - files_formal + toplevel: + - prim_secded_hamming_39_32_fpv + + formal: + <<: *default_target + + lint: + <<: *default_target + diff --git a/vendor/lowrisc_ip/ip/prim/fpv/prim_secded_hamming_72_64_fpv.core b/vendor/lowrisc_ip/ip/prim/fpv/prim_secded_hamming_72_64_fpv.core new file mode 100644 index 00000000..caaa10b9 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/prim_secded_hamming_72_64_fpv.core @@ -0,0 +1,33 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:fpv:prim_secded_hamming_72_64_fpv:0.1" +description: "SECDED FPV target" +filesets: + files_formal: + depend: + - lowrisc:prim:all + - lowrisc:prim:secded + files: + - vip/prim_secded_hamming_72_64_assert_fpv.sv + - tb/prim_secded_hamming_72_64_fpv.sv + - tb/prim_secded_hamming_72_64_bind_fpv.sv + file_type: systemVerilogSource + +targets: + default: &default_target + # note, this setting is just used + # to generate a file list for jg + default_tool: icarus + filesets: + - files_formal + toplevel: + - prim_secded_hamming_72_64_fpv + + formal: + <<: *default_target + + lint: + <<: *default_target + diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_bind_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_bind_fpv.sv index 6e96ee6a..b5471fc9 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_bind_fpv.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_bind_fpv.sv @@ -18,8 +18,10 @@ module prim_alert_rxtx_async_bind_fpv; .alert_err_pi, .alert_err_ni, .alert_skew_i, + .alert_test_i, .alert_req_i, .alert_ack_o, + .alert_state_o, .ping_req_i, .ping_ok_o, .integ_fail_o, 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 new file mode 100644 index 00000000..bc0d39a9 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_fatal_bind_fpv.sv @@ -0,0 +1,31 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// + +module prim_alert_rxtx_async_fatal_bind_fpv; + + bind prim_alert_rxtx_async_fpv + prim_alert_rxtx_async_assert_fpv prim_alert_rxtx_async_assert_fpv ( + .clk_i, + .rst_ni, + .ping_err_pi, + .ping_err_ni, + .ping_skew_i, + .ack_err_pi, + .ack_err_ni, + .ack_skew_i, + .alert_err_pi, + .alert_err_ni, + .alert_skew_i, + .alert_test_i, + .alert_req_i, + .alert_ack_o, + .alert_state_o, + .ping_req_i, + .ping_ok_o, + .integ_fail_o, + .alert_o + ); + +endmodule : prim_alert_rxtx_async_fatal_bind_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_fatal_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_fatal_fpv.sv new file mode 100644 index 00000000..18408c6e --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_fatal_fpv.sv @@ -0,0 +1,117 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Testbench module for alert sender/receiver pair. Intended to use with +// a formal tool. + +module prim_alert_rxtx_async_fatal_fpv + import prim_alert_pkg::*; + import prim_esc_pkg::*; +( + input clk_i, + input rst_ni, + // for sigint error and skew injection only + input ping_err_pi, + input ping_err_ni, + input [1:0] ping_skew_i, + input ack_err_pi, + input ack_err_ni, + input [1:0] ack_skew_i, + input alert_err_pi, + input alert_err_ni, + input [1:0] alert_skew_i, + // normal I/Os + input alert_test_i, + input alert_req_i, + input ping_req_i, + output logic alert_ack_o, + output logic alert_state_o, + output logic ping_ok_o, + output logic integ_fail_o, + output logic alert_o +); + + // asynchronous case + localparam bit AsyncOn = 1'b1; + localparam bit IsFatal = 1'b1; + + logic ping_pd; + logic ping_nd; + logic ack_pd; + logic ack_nd; + logic alert_pd; + logic alert_nd; + + alert_rx_t alert_rx_out, alert_rx_in; + alert_tx_t alert_tx_out, alert_tx_in; + + // for the purposes of FPV, we currently emulate the asynchronous transition + // only in terms of the skew it may introduce (which is limited to +- 1 cycle) + logic [1:0] ping_pq; + logic [1:0] ping_nq; + logic [1:0] ack_pq; + logic [1:0] ack_nq; + logic [1:0] alert_pq; + logic [1:0] alert_nq; + + assign ping_pd = alert_rx_out.ping_p; + assign ping_nd = alert_rx_out.ping_n; + assign ack_pd = alert_rx_out.ack_p; + assign ack_nd = alert_rx_out.ack_n; + assign alert_rx_in.ping_p = ping_pq[ping_skew_i[0]] ^ ping_err_pi; + assign alert_rx_in.ping_n = ping_nq[ping_skew_i[1]] ^ ping_err_ni; + assign alert_rx_in.ack_p = ack_pq[ack_skew_i[0]] ^ ack_err_pi; + assign alert_rx_in.ack_n = ack_nq[ack_skew_i[1]] ^ ack_err_ni; + + assign alert_pd = alert_tx_out.alert_p; + assign alert_nd = alert_tx_out.alert_n; + assign alert_tx_in.alert_p = alert_pq[alert_skew_i[0]] ^ alert_err_pi; + assign alert_tx_in.alert_n = alert_nq[alert_skew_i[1]] ^ alert_err_ni; + + prim_alert_sender #( + .AsyncOn ( AsyncOn ), + .IsFatal ( IsFatal ) + ) i_prim_alert_sender ( + .clk_i , + .rst_ni , + .alert_test_i, + .alert_req_i, + .alert_ack_o, + .alert_state_o, + .alert_rx_i ( alert_rx_in ), + .alert_tx_o ( alert_tx_out ) + ); + + prim_alert_receiver #( + .AsyncOn ( AsyncOn ) + ) i_prim_alert_receiver ( + .clk_i , + .rst_ni , + .ping_req_i , + .ping_ok_o , + .integ_fail_o , + .alert_o , + .alert_rx_o ( alert_rx_out ), + .alert_tx_i ( alert_tx_in ) + ); + + always_ff @(posedge clk_i or negedge rst_ni) begin : p_skew_delay + if (!rst_ni) begin + ping_pq <= '0; + ping_nq <= '1; + ack_pq <= '0; + ack_nq <= '1; + alert_pq <= '0; + alert_nq <= '1; + end else begin + ping_pq <= {ping_pq [$high(ping_pq )-1:0], ping_pd}; + ping_nq <= {ping_nq [$high(ping_nq )-1:0], ping_nd}; + ack_pq <= {ack_pq [$high(ack_pq )-1:0], ack_pd}; + ack_nq <= {ack_nq [$high(ack_nq )-1:0], ack_nd}; + alert_pq <= {alert_pq[$high(alert_pq)-1:0], alert_pd}; + alert_nq <= {alert_nq[$high(alert_nq)-1:0], alert_nd}; + end + end + +endmodule : prim_alert_rxtx_async_fatal_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_fpv.sv index 786345fd..682acaa4 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_fpv.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_async_fpv.sv @@ -22,9 +22,11 @@ module prim_alert_rxtx_async_fpv input alert_err_ni, input [1:0] alert_skew_i, // normal I/Os + input alert_test_i, input alert_req_i, input ping_req_i, output logic alert_ack_o, + output logic alert_state_o, output logic ping_ok_o, output logic integ_fail_o, output logic alert_o @@ -71,8 +73,10 @@ module prim_alert_rxtx_async_fpv ) i_prim_alert_sender ( .clk_i , .rst_ni , + .alert_test_i, .alert_req_i, .alert_ack_o, + .alert_state_o, .alert_rx_i ( alert_rx_in ), .alert_tx_o ( alert_tx_out ) ); 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 18071d1b..a3d3236c 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_bind_fpv.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_bind_fpv.sv @@ -15,8 +15,10 @@ module prim_alert_rxtx_bind_fpv; .ack_err_ni, .alert_err_pi, .alert_err_ni, + .alert_test_i, .alert_req_i, .alert_ack_o, + .alert_state_o, .ping_req_i, .ping_ok_o, .integ_fail_o, 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 new file mode 100644 index 00000000..b02e57fe --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_fatal_bind_fpv.sv @@ -0,0 +1,29 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// + +module prim_alert_rxtx_fatal_bind_fpv; + + // this reuses the synchronous VIP. + bind prim_alert_rxtx_fpv + prim_alert_rxtx_assert_fpv prim_alert_rxtx_assert_fpv ( + .clk_i, + .rst_ni, + .ping_err_pi, + .ping_err_ni, + .ack_err_pi, + .ack_err_ni, + .alert_err_pi, + .alert_err_ni, + .alert_test_i, + .alert_req_i, + .alert_ack_o, + .alert_state_o, + .ping_req_i, + .ping_ok_o, + .integ_fail_o, + .alert_o + ); + +endmodule : prim_alert_rxtx_fatal_bind_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_fatal_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_fatal_fpv.sv new file mode 100644 index 00000000..2eeb2463 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_fatal_fpv.sv @@ -0,0 +1,74 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Testbench module for alert sender/receiver pair. Intended to use with +// a formal tool. + +module prim_alert_rxtx_fatal_fpv + import prim_alert_pkg::*; + import prim_esc_pkg::*; +( + input clk_i, + input rst_ni, + // for sigint error injection only + input ping_err_pi, + input ping_err_ni, + input ack_err_pi, + input ack_err_ni, + input alert_err_pi, + input alert_err_ni, + // normal I/Os + input alert_test_i, + input alert_req_i, + input ping_req_i, + output logic alert_ack_o, + output logic alert_state_o, + output logic ping_ok_o, + output logic integ_fail_o, + output logic alert_o +); + + // synchronous case + localparam bit AsyncOn = 1'b0; + localparam bit IsFatal = 1'b1; + + alert_rx_t alert_rx_out, alert_rx_in; + alert_tx_t alert_tx_out, alert_tx_in; + + assign alert_rx_in.ping_p = alert_rx_out.ping_p ^ ping_err_pi; + assign alert_rx_in.ping_n = alert_rx_out.ping_n ^ ping_err_ni; + assign alert_rx_in.ack_p = alert_rx_out.ack_p ^ ack_err_pi; + assign alert_rx_in.ack_n = alert_rx_out.ack_n ^ ack_err_ni; + + assign alert_tx_in.alert_p = alert_tx_out.alert_p ^ alert_err_pi; + assign alert_tx_in.alert_n = alert_tx_out.alert_n ^ alert_err_ni; + + prim_alert_sender #( + .AsyncOn ( AsyncOn ), + .IsFatal ( IsFatal ) + ) i_prim_alert_sender ( + .clk_i , + .rst_ni , + .alert_test_i, + .alert_req_i, + .alert_ack_o, + .alert_state_o, + .alert_rx_i ( alert_rx_in ), + .alert_tx_o ( alert_tx_out ) + ); + + prim_alert_receiver #( + .AsyncOn ( AsyncOn ) + ) i_prim_alert_receiver ( + .clk_i , + .rst_ni , + .ping_req_i , + .ping_ok_o , + .integ_fail_o , + .alert_o , + .alert_rx_o ( alert_rx_out ), + .alert_tx_i ( alert_tx_in ) + ); + +endmodule : prim_alert_rxtx_fatal_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_fpv.sv index a2023400..f89a0c21 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_fpv.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_alert_rxtx_fpv.sv @@ -19,9 +19,11 @@ module prim_alert_rxtx_fpv input alert_err_pi, input alert_err_ni, // normal I/Os + input alert_test_i, input alert_req_i, input ping_req_i, output logic alert_ack_o, + output logic alert_state_o, output logic ping_ok_o, output logic integ_fail_o, output logic alert_o @@ -46,8 +48,10 @@ module prim_alert_rxtx_fpv ) i_prim_alert_sender ( .clk_i , .rst_ni , + .alert_test_i, .alert_req_i, .alert_ack_o, + .alert_state_o, .alert_rx_i ( alert_rx_in ), .alert_tx_o ( alert_tx_out ) ); diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_22_16_bind_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_22_16_bind_fpv.sv new file mode 100644 index 00000000..4068a4f7 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_22_16_bind_fpv.sv @@ -0,0 +1,20 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED FPV bind file generated by util/design/secded_gen.py + +module prim_secded_22_16_bind_fpv; + + bind prim_secded_22_16_fpv + prim_secded_22_16_assert_fpv prim_secded_22_16_assert_fpv ( + .clk_i, + .rst_ni, + .in, + .d_o, + .syndrome_o, + .err_o, + .error_inject_i + ); + +endmodule : prim_secded_22_16_bind_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_22_16_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_22_16_fpv.sv new file mode 100644 index 00000000..9d1e56ff --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_22_16_fpv.sv @@ -0,0 +1,31 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED FPV testbench generated by util/design/secded_gen.py + +module prim_secded_22_16_fpv ( + input clk_i, + input rst_ni, + input [15:0] in, + output logic [15:0] d_o, + output logic [5:0] syndrome_o, + output logic [1:0] err_o, + input [21:0] error_inject_i +); + + logic [21:0] data_enc; + + prim_secded_22_16_enc prim_secded_22_16_enc ( + .in, + .out(data_enc) + ); + + prim_secded_22_16_dec prim_secded_22_16_dec ( + .in(data_enc ^ error_inject_i), + .d_o, + .syndrome_o, + .err_o + ); + +endmodule : prim_secded_22_16_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_28_22_bind_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_28_22_bind_fpv.sv new file mode 100644 index 00000000..aed16ca3 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_28_22_bind_fpv.sv @@ -0,0 +1,20 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED FPV bind file generated by util/design/secded_gen.py + +module prim_secded_28_22_bind_fpv; + + bind prim_secded_28_22_fpv + prim_secded_28_22_assert_fpv prim_secded_28_22_assert_fpv ( + .clk_i, + .rst_ni, + .in, + .d_o, + .syndrome_o, + .err_o, + .error_inject_i + ); + +endmodule : prim_secded_28_22_bind_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_28_22_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_28_22_fpv.sv new file mode 100644 index 00000000..2f2f8eda --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_28_22_fpv.sv @@ -0,0 +1,31 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED FPV testbench generated by util/design/secded_gen.py + +module prim_secded_28_22_fpv ( + input clk_i, + input rst_ni, + input [21:0] in, + output logic [21:0] d_o, + output logic [5:0] syndrome_o, + output logic [1:0] err_o, + input [27:0] error_inject_i +); + + logic [27:0] data_enc; + + prim_secded_28_22_enc prim_secded_28_22_enc ( + .in, + .out(data_enc) + ); + + prim_secded_28_22_dec prim_secded_28_22_dec ( + .in(data_enc ^ error_inject_i), + .d_o, + .syndrome_o, + .err_o + ); + +endmodule : prim_secded_28_22_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_39_32_bind_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_39_32_bind_fpv.sv new file mode 100644 index 00000000..29bf2506 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_39_32_bind_fpv.sv @@ -0,0 +1,20 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED FPV bind file generated by util/design/secded_gen.py + +module prim_secded_39_32_bind_fpv; + + bind prim_secded_39_32_fpv + prim_secded_39_32_assert_fpv prim_secded_39_32_assert_fpv ( + .clk_i, + .rst_ni, + .in, + .d_o, + .syndrome_o, + .err_o, + .error_inject_i + ); + +endmodule : prim_secded_39_32_bind_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_39_32_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_39_32_fpv.sv new file mode 100644 index 00000000..f848f457 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_39_32_fpv.sv @@ -0,0 +1,31 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED FPV testbench generated by util/design/secded_gen.py + +module prim_secded_39_32_fpv ( + input clk_i, + input rst_ni, + input [31:0] in, + output logic [31:0] d_o, + output logic [6:0] syndrome_o, + output logic [1:0] err_o, + input [38:0] error_inject_i +); + + logic [38:0] data_enc; + + prim_secded_39_32_enc prim_secded_39_32_enc ( + .in, + .out(data_enc) + ); + + prim_secded_39_32_dec prim_secded_39_32_dec ( + .in(data_enc ^ error_inject_i), + .d_o, + .syndrome_o, + .err_o + ); + +endmodule : prim_secded_39_32_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_64_57_bind_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_64_57_bind_fpv.sv new file mode 100644 index 00000000..1ef65e29 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_64_57_bind_fpv.sv @@ -0,0 +1,20 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED FPV bind file generated by util/design/secded_gen.py + +module prim_secded_64_57_bind_fpv; + + bind prim_secded_64_57_fpv + prim_secded_64_57_assert_fpv prim_secded_64_57_assert_fpv ( + .clk_i, + .rst_ni, + .in, + .d_o, + .syndrome_o, + .err_o, + .error_inject_i + ); + +endmodule : prim_secded_64_57_bind_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_64_57_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_64_57_fpv.sv new file mode 100644 index 00000000..6827db72 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_64_57_fpv.sv @@ -0,0 +1,31 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED FPV testbench generated by util/design/secded_gen.py + +module prim_secded_64_57_fpv ( + input clk_i, + input rst_ni, + input [56:0] in, + output logic [56:0] d_o, + output logic [6:0] syndrome_o, + output logic [1:0] err_o, + input [63:0] error_inject_i +); + + logic [63:0] data_enc; + + prim_secded_64_57_enc prim_secded_64_57_enc ( + .in, + .out(data_enc) + ); + + prim_secded_64_57_dec prim_secded_64_57_dec ( + .in(data_enc ^ error_inject_i), + .d_o, + .syndrome_o, + .err_o + ); + +endmodule : prim_secded_64_57_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_72_64_bind_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_72_64_bind_fpv.sv new file mode 100644 index 00000000..a3285d2f --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_72_64_bind_fpv.sv @@ -0,0 +1,20 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED FPV bind file generated by util/design/secded_gen.py + +module prim_secded_72_64_bind_fpv; + + bind prim_secded_72_64_fpv + prim_secded_72_64_assert_fpv prim_secded_72_64_assert_fpv ( + .clk_i, + .rst_ni, + .in, + .d_o, + .syndrome_o, + .err_o, + .error_inject_i + ); + +endmodule : prim_secded_72_64_bind_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_72_64_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_72_64_fpv.sv new file mode 100644 index 00000000..cbe2c8bb --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_72_64_fpv.sv @@ -0,0 +1,31 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED FPV testbench generated by util/design/secded_gen.py + +module prim_secded_72_64_fpv ( + input clk_i, + input rst_ni, + input [63:0] in, + output logic [63:0] d_o, + output logic [7:0] syndrome_o, + output logic [1:0] err_o, + input [71:0] error_inject_i +); + + logic [71:0] data_enc; + + prim_secded_72_64_enc prim_secded_72_64_enc ( + .in, + .out(data_enc) + ); + + prim_secded_72_64_dec prim_secded_72_64_dec ( + .in(data_enc ^ error_inject_i), + .d_o, + .syndrome_o, + .err_o + ); + +endmodule : prim_secded_72_64_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_hamming_22_16_bind_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_hamming_22_16_bind_fpv.sv new file mode 100644 index 00000000..42a8e63d --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_hamming_22_16_bind_fpv.sv @@ -0,0 +1,20 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED FPV bind file generated by util/design/secded_gen.py + +module prim_secded_hamming_22_16_bind_fpv; + + bind prim_secded_hamming_22_16_fpv + prim_secded_hamming_22_16_assert_fpv prim_secded_hamming_22_16_assert_fpv ( + .clk_i, + .rst_ni, + .in, + .d_o, + .syndrome_o, + .err_o, + .error_inject_i + ); + +endmodule : prim_secded_hamming_22_16_bind_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_hamming_22_16_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_hamming_22_16_fpv.sv new file mode 100644 index 00000000..25718057 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_hamming_22_16_fpv.sv @@ -0,0 +1,31 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED FPV testbench generated by util/design/secded_gen.py + +module prim_secded_hamming_22_16_fpv ( + input clk_i, + input rst_ni, + input [15:0] in, + output logic [15:0] d_o, + output logic [5:0] syndrome_o, + output logic [1:0] err_o, + input [21:0] error_inject_i +); + + logic [21:0] data_enc; + + prim_secded_hamming_22_16_enc prim_secded_hamming_22_16_enc ( + .in, + .out(data_enc) + ); + + prim_secded_hamming_22_16_dec prim_secded_hamming_22_16_dec ( + .in(data_enc ^ error_inject_i), + .d_o, + .syndrome_o, + .err_o + ); + +endmodule : prim_secded_hamming_22_16_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_hamming_39_32_bind_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_hamming_39_32_bind_fpv.sv new file mode 100644 index 00000000..d32d1e96 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_hamming_39_32_bind_fpv.sv @@ -0,0 +1,20 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED FPV bind file generated by util/design/secded_gen.py + +module prim_secded_hamming_39_32_bind_fpv; + + bind prim_secded_hamming_39_32_fpv + prim_secded_hamming_39_32_assert_fpv prim_secded_hamming_39_32_assert_fpv ( + .clk_i, + .rst_ni, + .in, + .d_o, + .syndrome_o, + .err_o, + .error_inject_i + ); + +endmodule : prim_secded_hamming_39_32_bind_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_hamming_39_32_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_hamming_39_32_fpv.sv new file mode 100644 index 00000000..32c49f4b --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_hamming_39_32_fpv.sv @@ -0,0 +1,31 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED FPV testbench generated by util/design/secded_gen.py + +module prim_secded_hamming_39_32_fpv ( + input clk_i, + input rst_ni, + input [31:0] in, + output logic [31:0] d_o, + output logic [6:0] syndrome_o, + output logic [1:0] err_o, + input [38:0] error_inject_i +); + + logic [38:0] data_enc; + + prim_secded_hamming_39_32_enc prim_secded_hamming_39_32_enc ( + .in, + .out(data_enc) + ); + + prim_secded_hamming_39_32_dec prim_secded_hamming_39_32_dec ( + .in(data_enc ^ error_inject_i), + .d_o, + .syndrome_o, + .err_o + ); + +endmodule : prim_secded_hamming_39_32_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_hamming_72_64_bind_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_hamming_72_64_bind_fpv.sv new file mode 100644 index 00000000..147fad1e --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_hamming_72_64_bind_fpv.sv @@ -0,0 +1,20 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED FPV bind file generated by util/design/secded_gen.py + +module prim_secded_hamming_72_64_bind_fpv; + + bind prim_secded_hamming_72_64_fpv + prim_secded_hamming_72_64_assert_fpv prim_secded_hamming_72_64_assert_fpv ( + .clk_i, + .rst_ni, + .in, + .d_o, + .syndrome_o, + .err_o, + .error_inject_i + ); + +endmodule : prim_secded_hamming_72_64_bind_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_hamming_72_64_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_hamming_72_64_fpv.sv new file mode 100644 index 00000000..6b3322fe --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/tb/prim_secded_hamming_72_64_fpv.sv @@ -0,0 +1,31 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED FPV testbench generated by util/design/secded_gen.py + +module prim_secded_hamming_72_64_fpv ( + input clk_i, + input rst_ni, + input [63:0] in, + output logic [63:0] d_o, + output logic [7:0] syndrome_o, + output logic [1:0] err_o, + input [71:0] error_inject_i +); + + logic [71:0] data_enc; + + prim_secded_hamming_72_64_enc prim_secded_hamming_72_64_enc ( + .in, + .out(data_enc) + ); + + prim_secded_hamming_72_64_dec prim_secded_hamming_72_64_dec ( + .in(data_enc ^ error_inject_i), + .d_o, + .syndrome_o, + .err_o + ); + +endmodule : prim_secded_hamming_72_64_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_alert_rxtx_assert_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_alert_rxtx_assert_fpv.sv index 70cfd6a6..f0e5b009 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_alert_rxtx_assert_fpv.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_alert_rxtx_assert_fpv.sv @@ -18,8 +18,10 @@ module prim_alert_rxtx_assert_fpv ( input alert_err_pi, input alert_err_ni, // normal I/Os + input alert_test_i, input alert_req_i, input alert_ack_o, + input alert_state_o, input ping_req_i, input ping_ok_o, input integ_fail_o, @@ -58,7 +60,7 @@ module prim_alert_rxtx_assert_fpv ( (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, + prim_alert_rxtx_fpv.i_prim_alert_receiver.Idle) |=> FullHandshake_S, clk_i, !rst_ni || error_present) `ASSERT(AlertHs_A, alert_req_i && (prim_alert_rxtx_fpv.i_prim_alert_sender.state_q == @@ -66,6 +68,19 @@ module prim_alert_rxtx_assert_fpv ( (prim_alert_rxtx_fpv.i_prim_alert_receiver.state_q == prim_alert_rxtx_fpv.i_prim_alert_receiver.Idle) |=> FullHandshake_S |-> alert_ack_o, clk_i, !rst_ni || error_present) + `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) |=> + FullHandshake_S, clk_i, !rst_ni || error_present) + // 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), + clk_i, !rst_ni || error_present) // transmission of pings // note: the complete transmission of pings only happen when no ping handshake is in progress @@ -78,15 +93,15 @@ module prim_alert_rxtx_assert_fpv ( prim_alert_rxtx_fpv.i_prim_alert_sender.PingHsPhase2}) && $rose(ping_req_i) |-> ping_ok_o == 0 throughout ping_req_i [->1], clk_i, !rst_ni || error_present) // transmission of alerts in case of no collision with ping enable - `ASSERT(AlertCheck0_A, !ping_req_i [*3] ##0 $rose(alert_req_i) && + `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) |=> alert_o, clk_i, !rst_ni || error_present || ping_req_i) // transmission of alerts in the general case which can include continous ping collisions - `ASSERT(AlertCheck1_A, alert_req_i |=> + `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), - clk_i, !rst_ni || error_present || alert_ack_o) + clk_i, !rst_ni || error_present || prim_alert_rxtx_fpv.i_prim_alert_sender.alert_clr) // basic liveness of FSMs in case no errors are present `ASSERT(FsmLivenessSender_A, diff --git a/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_alert_rxtx_async_assert_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_alert_rxtx_async_assert_fpv.sv index c1cf3942..568bfa0c 100644 --- a/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_alert_rxtx_async_assert_fpv.sv +++ b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_alert_rxtx_async_assert_fpv.sv @@ -21,8 +21,10 @@ module prim_alert_rxtx_async_assert_fpv ( input alert_err_ni, input [1:0] alert_skew_i, // normal I/Os + input alert_test_i, input alert_req_i, input alert_ack_o, + input alert_state_o, input ping_req_i, input ping_ok_o, input integ_fail_o, @@ -87,8 +89,20 @@ module prim_alert_rxtx_async_assert_fpv ( (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 - ##[0:5] alert_ack_o, + prim_alert_rxtx_async_fpv.i_prim_alert_receiver.Idle) |-> ##[0:5] FullHandshake_S, + clk_i, !rst_ni || error_setreg_q) + `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, + clk_i, !rst_ni || error_setreg_q) + // 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), clk_i, !rst_ni || error_setreg_q) // transmission of pings @@ -104,16 +118,17 @@ module prim_alert_rxtx_async_assert_fpv ( prim_alert_rxtx_async_fpv.i_prim_alert_sender.PingHsPhase2}) && $rose(ping_req_i) |-> ping_ok_o == 0 throughout ping_req_i[->1], clk_i, !rst_ni || error_setreg_q) // transmission of first alert assertion (no ping collision) - `ASSERT(AlertCheck0_A, !ping_req_i [*10] ##1 $rose(alert_req_i) && + `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) |-> ##[3:5] alert_o, clk_i, !rst_ni || ping_req_i || error_setreg_q) // eventual transmission of alerts in the general case which can include continous ping // collisions - `ASSERT(AlertCheck1_A, alert_req_i |-> + `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), - clk_i, !rst_ni || error_setreg_q || alert_ack_o) + clk_i, !rst_ni || error_setreg_q || + prim_alert_rxtx_async_fpv.i_prim_alert_sender.alert_clr) // basic liveness of FSMs in case no errors are present `ASSERT(FsmLivenessSender_A, !error_present [*2] ##1 !error_present && @@ -127,6 +142,4 @@ module prim_alert_rxtx_async_assert_fpv ( strong(##[1:$] (prim_alert_rxtx_async_fpv.i_prim_alert_receiver.state_q == prim_alert_rxtx_async_fpv.i_prim_alert_receiver.Idle)),clk_i, !rst_ni || error_present) - // TODO: add FSM liveness of 3x diff decoder instances - endmodule : prim_alert_rxtx_async_assert_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_secded_22_16_assert_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_secded_22_16_assert_fpv.sv new file mode 100644 index 00000000..3178743b --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_secded_22_16_assert_fpv.sv @@ -0,0 +1,33 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED FPV assertion file generated by util/design/secded_gen.py + +module prim_secded_22_16_assert_fpv ( + input clk_i, + input rst_ni, + input [15:0] in, + input [15:0] d_o, + input [5:0] syndrome_o, + input [1:0] err_o, + input [21:0] error_inject_i +); + + // Inject a maximum of two errors simultaneously. + `ASSUME_FPV(MaxTwoErrors_M, $countones(error_inject_i) <= 2) + // This bounds the input data state space to make sure the solver converges. + `ASSUME_FPV(DataLimit_M, $onehot0(in) || $onehot0(~in)) + // Single bit error detection + `ASSERT(SingleErrorDetect_A, $countones(error_inject_i) == 1 |-> err_o[0]) + `ASSERT(SingleErrorDetectReverse_A, err_o[0] |-> $countones(error_inject_i) == 1) + // Double bit error detection + `ASSERT(DoubleErrorDetect_A, $countones(error_inject_i) == 2 |-> err_o[1]) + `ASSERT(DoubleErrorDetectReverse_A, err_o[1] |-> $countones(error_inject_i) == 2) + // Single bit error correction (implicitly tests the syndrome output) + `ASSERT(SingleErrorCorrect_A, $countones(error_inject_i) < 2 |-> in == d_o) + // Basic syndrome check + `ASSERT(SyndromeCheck_A, |syndrome_o |-> $countones(error_inject_i) > 0) + `ASSERT(SyndromeCheckReverse_A, $countones(error_inject_i) > 0 |-> |syndrome_o) + +endmodule : prim_secded_22_16_assert_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_secded_28_22_assert_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_secded_28_22_assert_fpv.sv new file mode 100644 index 00000000..0ea98056 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_secded_28_22_assert_fpv.sv @@ -0,0 +1,33 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED FPV assertion file generated by util/design/secded_gen.py + +module prim_secded_28_22_assert_fpv ( + input clk_i, + input rst_ni, + input [21:0] in, + input [21:0] d_o, + input [5:0] syndrome_o, + input [1:0] err_o, + input [27:0] error_inject_i +); + + // Inject a maximum of two errors simultaneously. + `ASSUME_FPV(MaxTwoErrors_M, $countones(error_inject_i) <= 2) + // This bounds the input data state space to make sure the solver converges. + `ASSUME_FPV(DataLimit_M, $onehot0(in) || $onehot0(~in)) + // Single bit error detection + `ASSERT(SingleErrorDetect_A, $countones(error_inject_i) == 1 |-> err_o[0]) + `ASSERT(SingleErrorDetectReverse_A, err_o[0] |-> $countones(error_inject_i) == 1) + // Double bit error detection + `ASSERT(DoubleErrorDetect_A, $countones(error_inject_i) == 2 |-> err_o[1]) + `ASSERT(DoubleErrorDetectReverse_A, err_o[1] |-> $countones(error_inject_i) == 2) + // Single bit error correction (implicitly tests the syndrome output) + `ASSERT(SingleErrorCorrect_A, $countones(error_inject_i) < 2 |-> in == d_o) + // Basic syndrome check + `ASSERT(SyndromeCheck_A, |syndrome_o |-> $countones(error_inject_i) > 0) + `ASSERT(SyndromeCheckReverse_A, $countones(error_inject_i) > 0 |-> |syndrome_o) + +endmodule : prim_secded_28_22_assert_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_secded_39_32_assert_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_secded_39_32_assert_fpv.sv new file mode 100644 index 00000000..0168213e --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_secded_39_32_assert_fpv.sv @@ -0,0 +1,33 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED FPV assertion file generated by util/design/secded_gen.py + +module prim_secded_39_32_assert_fpv ( + input clk_i, + input rst_ni, + input [31:0] in, + input [31:0] d_o, + input [6:0] syndrome_o, + input [1:0] err_o, + input [38:0] error_inject_i +); + + // Inject a maximum of two errors simultaneously. + `ASSUME_FPV(MaxTwoErrors_M, $countones(error_inject_i) <= 2) + // This bounds the input data state space to make sure the solver converges. + `ASSUME_FPV(DataLimit_M, $onehot0(in) || $onehot0(~in)) + // Single bit error detection + `ASSERT(SingleErrorDetect_A, $countones(error_inject_i) == 1 |-> err_o[0]) + `ASSERT(SingleErrorDetectReverse_A, err_o[0] |-> $countones(error_inject_i) == 1) + // Double bit error detection + `ASSERT(DoubleErrorDetect_A, $countones(error_inject_i) == 2 |-> err_o[1]) + `ASSERT(DoubleErrorDetectReverse_A, err_o[1] |-> $countones(error_inject_i) == 2) + // Single bit error correction (implicitly tests the syndrome output) + `ASSERT(SingleErrorCorrect_A, $countones(error_inject_i) < 2 |-> in == d_o) + // Basic syndrome check + `ASSERT(SyndromeCheck_A, |syndrome_o |-> $countones(error_inject_i) > 0) + `ASSERT(SyndromeCheckReverse_A, $countones(error_inject_i) > 0 |-> |syndrome_o) + +endmodule : prim_secded_39_32_assert_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_secded_64_57_assert_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_secded_64_57_assert_fpv.sv new file mode 100644 index 00000000..ca9c8300 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_secded_64_57_assert_fpv.sv @@ -0,0 +1,33 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED FPV assertion file generated by util/design/secded_gen.py + +module prim_secded_64_57_assert_fpv ( + input clk_i, + input rst_ni, + input [56:0] in, + input [56:0] d_o, + input [6:0] syndrome_o, + input [1:0] err_o, + input [63:0] error_inject_i +); + + // Inject a maximum of two errors simultaneously. + `ASSUME_FPV(MaxTwoErrors_M, $countones(error_inject_i) <= 2) + // This bounds the input data state space to make sure the solver converges. + `ASSUME_FPV(DataLimit_M, $onehot0(in) || $onehot0(~in)) + // Single bit error detection + `ASSERT(SingleErrorDetect_A, $countones(error_inject_i) == 1 |-> err_o[0]) + `ASSERT(SingleErrorDetectReverse_A, err_o[0] |-> $countones(error_inject_i) == 1) + // Double bit error detection + `ASSERT(DoubleErrorDetect_A, $countones(error_inject_i) == 2 |-> err_o[1]) + `ASSERT(DoubleErrorDetectReverse_A, err_o[1] |-> $countones(error_inject_i) == 2) + // Single bit error correction (implicitly tests the syndrome output) + `ASSERT(SingleErrorCorrect_A, $countones(error_inject_i) < 2 |-> in == d_o) + // Basic syndrome check + `ASSERT(SyndromeCheck_A, |syndrome_o |-> $countones(error_inject_i) > 0) + `ASSERT(SyndromeCheckReverse_A, $countones(error_inject_i) > 0 |-> |syndrome_o) + +endmodule : prim_secded_64_57_assert_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_secded_72_64_assert_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_secded_72_64_assert_fpv.sv new file mode 100644 index 00000000..390345da --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_secded_72_64_assert_fpv.sv @@ -0,0 +1,33 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED FPV assertion file generated by util/design/secded_gen.py + +module prim_secded_72_64_assert_fpv ( + input clk_i, + input rst_ni, + input [63:0] in, + input [63:0] d_o, + input [7:0] syndrome_o, + input [1:0] err_o, + input [71:0] error_inject_i +); + + // Inject a maximum of two errors simultaneously. + `ASSUME_FPV(MaxTwoErrors_M, $countones(error_inject_i) <= 2) + // This bounds the input data state space to make sure the solver converges. + `ASSUME_FPV(DataLimit_M, $onehot0(in) || $onehot0(~in)) + // Single bit error detection + `ASSERT(SingleErrorDetect_A, $countones(error_inject_i) == 1 |-> err_o[0]) + `ASSERT(SingleErrorDetectReverse_A, err_o[0] |-> $countones(error_inject_i) == 1) + // Double bit error detection + `ASSERT(DoubleErrorDetect_A, $countones(error_inject_i) == 2 |-> err_o[1]) + `ASSERT(DoubleErrorDetectReverse_A, err_o[1] |-> $countones(error_inject_i) == 2) + // Single bit error correction (implicitly tests the syndrome output) + `ASSERT(SingleErrorCorrect_A, $countones(error_inject_i) < 2 |-> in == d_o) + // Basic syndrome check + `ASSERT(SyndromeCheck_A, |syndrome_o |-> $countones(error_inject_i) > 0) + `ASSERT(SyndromeCheckReverse_A, $countones(error_inject_i) > 0 |-> |syndrome_o) + +endmodule : prim_secded_72_64_assert_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_secded_hamming_22_16_assert_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_secded_hamming_22_16_assert_fpv.sv new file mode 100644 index 00000000..35e6a542 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_secded_hamming_22_16_assert_fpv.sv @@ -0,0 +1,33 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED FPV assertion file generated by util/design/secded_gen.py + +module prim_secded_hamming_22_16_assert_fpv ( + input clk_i, + input rst_ni, + input [15:0] in, + input [15:0] d_o, + input [5:0] syndrome_o, + input [1:0] err_o, + input [21:0] error_inject_i +); + + // Inject a maximum of two errors simultaneously. + `ASSUME_FPV(MaxTwoErrors_M, $countones(error_inject_i) <= 2) + // This bounds the input data state space to make sure the solver converges. + `ASSUME_FPV(DataLimit_M, $onehot0(in) || $onehot0(~in)) + // Single bit error detection + `ASSERT(SingleErrorDetect_A, $countones(error_inject_i) == 1 |-> err_o[0]) + `ASSERT(SingleErrorDetectReverse_A, err_o[0] |-> $countones(error_inject_i) == 1) + // Double bit error detection + `ASSERT(DoubleErrorDetect_A, $countones(error_inject_i) == 2 |-> err_o[1]) + `ASSERT(DoubleErrorDetectReverse_A, err_o[1] |-> $countones(error_inject_i) == 2) + // Single bit error correction (implicitly tests the syndrome output) + `ASSERT(SingleErrorCorrect_A, $countones(error_inject_i) < 2 |-> in == d_o) + // Basic syndrome check + `ASSERT(SyndromeCheck_A, |syndrome_o |-> $countones(error_inject_i) > 0) + `ASSERT(SyndromeCheckReverse_A, $countones(error_inject_i) > 0 |-> |syndrome_o) + +endmodule : prim_secded_hamming_22_16_assert_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_secded_hamming_39_32_assert_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_secded_hamming_39_32_assert_fpv.sv new file mode 100644 index 00000000..8e45b1e5 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_secded_hamming_39_32_assert_fpv.sv @@ -0,0 +1,33 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED FPV assertion file generated by util/design/secded_gen.py + +module prim_secded_hamming_39_32_assert_fpv ( + input clk_i, + input rst_ni, + input [31:0] in, + input [31:0] d_o, + input [6:0] syndrome_o, + input [1:0] err_o, + input [38:0] error_inject_i +); + + // Inject a maximum of two errors simultaneously. + `ASSUME_FPV(MaxTwoErrors_M, $countones(error_inject_i) <= 2) + // This bounds the input data state space to make sure the solver converges. + `ASSUME_FPV(DataLimit_M, $onehot0(in) || $onehot0(~in)) + // Single bit error detection + `ASSERT(SingleErrorDetect_A, $countones(error_inject_i) == 1 |-> err_o[0]) + `ASSERT(SingleErrorDetectReverse_A, err_o[0] |-> $countones(error_inject_i) == 1) + // Double bit error detection + `ASSERT(DoubleErrorDetect_A, $countones(error_inject_i) == 2 |-> err_o[1]) + `ASSERT(DoubleErrorDetectReverse_A, err_o[1] |-> $countones(error_inject_i) == 2) + // Single bit error correction (implicitly tests the syndrome output) + `ASSERT(SingleErrorCorrect_A, $countones(error_inject_i) < 2 |-> in == d_o) + // Basic syndrome check + `ASSERT(SyndromeCheck_A, |syndrome_o |-> $countones(error_inject_i) > 0) + `ASSERT(SyndromeCheckReverse_A, $countones(error_inject_i) > 0 |-> |syndrome_o) + +endmodule : prim_secded_hamming_39_32_assert_fpv diff --git a/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_secded_hamming_72_64_assert_fpv.sv b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_secded_hamming_72_64_assert_fpv.sv new file mode 100644 index 00000000..307941e9 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/fpv/vip/prim_secded_hamming_72_64_assert_fpv.sv @@ -0,0 +1,33 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED FPV assertion file generated by util/design/secded_gen.py + +module prim_secded_hamming_72_64_assert_fpv ( + input clk_i, + input rst_ni, + input [63:0] in, + input [63:0] d_o, + input [7:0] syndrome_o, + input [1:0] err_o, + input [71:0] error_inject_i +); + + // Inject a maximum of two errors simultaneously. + `ASSUME_FPV(MaxTwoErrors_M, $countones(error_inject_i) <= 2) + // This bounds the input data state space to make sure the solver converges. + `ASSUME_FPV(DataLimit_M, $onehot0(in) || $onehot0(~in)) + // Single bit error detection + `ASSERT(SingleErrorDetect_A, $countones(error_inject_i) == 1 |-> err_o[0]) + `ASSERT(SingleErrorDetectReverse_A, err_o[0] |-> $countones(error_inject_i) == 1) + // Double bit error detection + `ASSERT(DoubleErrorDetect_A, $countones(error_inject_i) == 2 |-> err_o[1]) + `ASSERT(DoubleErrorDetectReverse_A, err_o[1] |-> $countones(error_inject_i) == 2) + // Single bit error correction (implicitly tests the syndrome output) + `ASSERT(SingleErrorCorrect_A, $countones(error_inject_i) < 2 |-> in == d_o) + // Basic syndrome check + `ASSERT(SyndromeCheck_A, |syndrome_o |-> $countones(error_inject_i) > 0) + `ASSERT(SyndromeCheckReverse_A, $countones(error_inject_i) > 0 |-> |syndrome_o) + +endmodule : prim_secded_hamming_72_64_assert_fpv diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim.vlt b/vendor/lowrisc_ip/ip/prim/lint/prim.vlt index a35e814f..2b1c75d4 100644 --- a/vendor/lowrisc_ip/ip/prim/lint/prim.vlt +++ b/vendor/lowrisc_ip/ip/prim/lint/prim.vlt @@ -12,3 +12,7 @@ lint_off -rule UNUSED -file "*/rtl/prim_subreg.sv" -match "Signal is not used: ' // In passthrough mode, clk and reset are not read form within this module lint_off -rule UNUSED -file "*/rtl/prim_fifo_sync.sv" -match "*clk_i*" lint_off -rule UNUSED -file "*/rtl/prim_fifo_sync.sv" -match "*rst_ni*" + +// prim_lfsr +// lfsr_perm_test is just used for an SVA +lint_off -rule UNUSED -file "*/rtl/prim_lfsr.sv" -match "*lfsr_perm_test*" diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_clock_div.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_clock_div.waiver index c9b4a732..bd6e48c3 100644 --- a/vendor/lowrisc_ip/ip/prim/lint/prim_clock_div.waiver +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_clock_div.waiver @@ -6,3 +6,6 @@ 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_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" diff --git a/vendor/lowrisc_ip/ip/prim/prim.core b/vendor/lowrisc_ip/ip/prim/prim.core index 855b4c40..c83a248b 100644 --- a/vendor/lowrisc_ip/ip/prim/prim.core +++ b/vendor/lowrisc_ip/ip/prim/prim.core @@ -35,6 +35,7 @@ filesets: - rtl/prim_slicer.sv - rtl/prim_sync_reqack.sv - rtl/prim_sync_reqack_data.sv + - rtl/prim_sync_slow_fast.sv - rtl/prim_keccak.sv - rtl/prim_packer.sv - rtl/prim_packer_fifo.sv @@ -73,7 +74,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: diff --git a/vendor/lowrisc_ip/ip/prim/prim_buf.core b/vendor/lowrisc_ip/ip/prim/prim_buf.core index c77daf9d..e2028b98 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_buf.core +++ b/vendor/lowrisc_ip/ip/prim/prim_buf.core @@ -31,7 +31,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable generate: impl: diff --git a/vendor/lowrisc_ip/ip/prim/prim_clock_buf.core b/vendor/lowrisc_ip/ip/prim/prim_clock_buf.core index 7cab5c37..757d4832 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_clock_buf.core +++ b/vendor/lowrisc_ip/ip/prim/prim_clock_buf.core @@ -31,7 +31,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable generate: impl: diff --git a/vendor/lowrisc_ip/ip/prim/prim_clock_gating.core b/vendor/lowrisc_ip/ip/prim/prim_clock_gating.core index 91b46737..20be1209 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_clock_gating.core +++ b/vendor/lowrisc_ip/ip/prim/prim_clock_gating.core @@ -31,7 +31,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable generate: impl: diff --git a/vendor/lowrisc_ip/ip/prim/prim_clock_inv.core b/vendor/lowrisc_ip/ip/prim/prim_clock_inv.core index 8620ba28..97119199 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_clock_inv.core +++ b/vendor/lowrisc_ip/ip/prim/prim_clock_inv.core @@ -31,7 +31,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable generate: impl: diff --git a/vendor/lowrisc_ip/ip/prim/prim_clock_mux2.core b/vendor/lowrisc_ip/ip/prim/prim_clock_mux2.core index e29234e6..68566ac9 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_clock_mux2.core +++ b/vendor/lowrisc_ip/ip/prim/prim_clock_mux2.core @@ -31,7 +31,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable generate: impl: diff --git a/vendor/lowrisc_ip/ip/prim/prim_dom_and_2share.core b/vendor/lowrisc_ip/ip/prim/prim_dom_and_2share.core index 2f6def43..9376d665 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_dom_and_2share.core +++ b/vendor/lowrisc_ip/ip/prim/prim_dom_and_2share.core @@ -33,7 +33,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: diff --git a/vendor/lowrisc_ip/ip/prim/prim_flash.core b/vendor/lowrisc_ip/ip/prim/prim_flash.core index fcf26d7f..849506b2 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_flash.core +++ b/vendor/lowrisc_ip/ip/prim/prim_flash.core @@ -13,6 +13,8 @@ filesets: # 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: @@ -34,7 +36,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable generate: impl: diff --git a/vendor/lowrisc_ip/ip/prim/prim_flop.core b/vendor/lowrisc_ip/ip/prim/prim_flop.core index bcc7dc61..b56bbe65 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_flop.core +++ b/vendor/lowrisc_ip/ip/prim/prim_flop.core @@ -30,7 +30,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable generate: impl: diff --git a/vendor/lowrisc_ip/ip/prim/prim_flop_2sync.core b/vendor/lowrisc_ip/ip/prim/prim_flop_2sync.core index 6d11bdea..d2e2e767 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_flop_2sync.core +++ b/vendor/lowrisc_ip/ip/prim/prim_flop_2sync.core @@ -30,7 +30,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable generate: diff --git a/vendor/lowrisc_ip/ip/prim/prim_lc_dec.core b/vendor/lowrisc_ip/ip/prim/prim_lc_dec.core new file mode 100644 index 00000000..c22e4b6d --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/prim_lc_dec.core @@ -0,0 +1,54 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +name: "lowrisc:prim:lc_dec:0.1" +description: "Decoder for life cycle control signals." +filesets: + files_rtl: + depend: + - lowrisc:prim:buf + - lowrisc:ip:lc_ctrl_pkg + files: + - rtl/prim_lc_dec.sv + file_type: systemVerilogSource + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + file_type: vlt + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + # - lint/prim_lc_sync.waiver + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + +targets: + default: &default_target + filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) + - files_rtl + + lint: + <<: *default_target + default_tool: verilator + parameters: + - SYNTHESIS=true + tools: + verilator: + mode: lint-only + verilator_options: + - "-Wall" diff --git a/vendor/lowrisc_ip/ip/prim/prim_lc_sender.core b/vendor/lowrisc_ip/ip/prim/prim_lc_sender.core index d8cd27be..20e51665 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_lc_sender.core +++ b/vendor/lowrisc_ip/ip/prim/prim_lc_sender.core @@ -34,7 +34,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: &default_target diff --git a/vendor/lowrisc_ip/ip/prim/prim_lc_sync.core b/vendor/lowrisc_ip/ip/prim/prim_lc_sync.core index 61e25da8..0a8d4491 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_lc_sync.core +++ b/vendor/lowrisc_ip/ip/prim/prim_lc_sync.core @@ -35,7 +35,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: &default_target diff --git a/vendor/lowrisc_ip/ip/prim/prim_lfsr.core b/vendor/lowrisc_ip/ip/prim/prim_lfsr.core index 58060bfe..8d1c453d 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_lfsr.core +++ b/vendor/lowrisc_ip/ip/prim/prim_lfsr.core @@ -32,7 +32,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: &default_target diff --git a/vendor/lowrisc_ip/ip/prim/prim_otp.core b/vendor/lowrisc_ip/ip/prim/prim_otp.core index 4c1d474f..77ab06ce 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_otp.core +++ b/vendor/lowrisc_ip/ip/prim/prim_otp.core @@ -31,7 +31,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable generate: impl: diff --git a/vendor/lowrisc_ip/ip/prim/prim_otp_pkg.core b/vendor/lowrisc_ip/ip/prim/prim_otp_pkg.core index 06b3dcfe..9b603ec4 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_otp_pkg.core +++ b/vendor/lowrisc_ip/ip/prim/prim_otp_pkg.core @@ -29,7 +29,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: &default_target diff --git a/vendor/lowrisc_ip/ip/prim/prim_pad_wrapper.core b/vendor/lowrisc_ip/ip/prim/prim_pad_wrapper.core index c74355de..c7264c63 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_pad_wrapper.core +++ b/vendor/lowrisc_ip/ip/prim/prim_pad_wrapper.core @@ -31,7 +31,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable generate: impl: diff --git a/vendor/lowrisc_ip/ip/prim/prim_ram_1p.core b/vendor/lowrisc_ip/ip/prim/prim_ram_1p.core index 387eaf9b..85110182 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_ram_1p.core +++ b/vendor/lowrisc_ip/ip/prim/prim_ram_1p.core @@ -31,7 +31,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable generate: impl: diff --git a/vendor/lowrisc_ip/ip/prim/prim_ram_1p_adv.core b/vendor/lowrisc_ip/ip/prim/prim_ram_1p_adv.core index bb109ba7..e0bed14a 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_ram_1p_adv.core +++ b/vendor/lowrisc_ip/ip/prim/prim_ram_1p_adv.core @@ -34,7 +34,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: diff --git a/vendor/lowrisc_ip/ip/prim/prim_ram_2p.core b/vendor/lowrisc_ip/ip/prim/prim_ram_2p.core index 91003228..7b72a71f 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_ram_2p.core +++ b/vendor/lowrisc_ip/ip/prim/prim_ram_2p.core @@ -31,7 +31,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable generate: impl: diff --git a/vendor/lowrisc_ip/ip/prim/prim_rom.core b/vendor/lowrisc_ip/ip/prim/prim_rom.core index 9f78826a..0a0ae936 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_rom.core +++ b/vendor/lowrisc_ip/ip/prim/prim_rom.core @@ -31,7 +31,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable generate: impl: diff --git a/vendor/lowrisc_ip/ip/prim/prim_secded.core b/vendor/lowrisc_ip/ip/prim/prim_secded.core index abcad6c4..87a248e7 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_secded.core +++ b/vendor/lowrisc_ip/ip/prim/prim_secded.core @@ -14,8 +14,14 @@ filesets: - rtl/prim_secded_28_22_enc.sv - rtl/prim_secded_39_32_dec.sv - rtl/prim_secded_39_32_enc.sv + - rtl/prim_secded_64_57_dec.sv + - rtl/prim_secded_64_57_enc.sv - rtl/prim_secded_72_64_dec.sv - rtl/prim_secded_72_64_enc.sv + - rtl/prim_secded_hamming_22_16_dec.sv + - rtl/prim_secded_hamming_22_16_enc.sv + - rtl/prim_secded_hamming_39_32_dec.sv + - rtl/prim_secded_hamming_39_32_enc.sv - rtl/prim_secded_hamming_72_64_dec.sv - rtl/prim_secded_hamming_72_64_enc.sv file_type: systemVerilogSource diff --git a/vendor/lowrisc_ip/ip/prim/prim_usb_diff_rx.core b/vendor/lowrisc_ip/ip/prim/prim_usb_diff_rx.core index 1284b088..f34cea4e 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_usb_diff_rx.core +++ b/vendor/lowrisc_ip/ip/prim/prim_usb_diff_rx.core @@ -31,7 +31,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable generate: impl: diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_alert_sender.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_alert_sender.sv index 9898ff6e..c1b385b7 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_alert_sender.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_alert_sender.sv @@ -12,6 +12,17 @@ // can keep alert_req_i asserted until it has been ack'd (transferred to the alert // receiver). The parent module is not required to use this. // +// 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. +// 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 +// single alert handshakes. This input behaves exactly the same way as the +// alert_req_i input with IsFatal set to 0. Test alerts do not cause alert_ack_o +// to be asserted, nor are they latched until reset (regardless of the value of the +// IsFatal parameter). +// // Further, this module supports in-band ping testing, which means that a level // change on the ping_p/n diff pair will result in a full-handshake response // on alert_p/n and ack_p/n. @@ -34,13 +45,20 @@ module prim_alert_sender import prim_alert_pkg::*; #( // enables additional synchronization logic - parameter bit AsyncOn = 1'b1 + parameter bit AsyncOn = 1'b1, + // alert sender will latch the incoming alert event permanently and + // keep on sending alert events until the next reset. + parameter bit IsFatal = 1'b0 ) ( input clk_i, input rst_ni, + // alert test trigger (this will never be latched, even if IsFatal == 1) + input alert_test_i, // native alert from the peripheral input alert_req_i, output logic alert_ack_o, + // state of the alert latching register + output logic alert_state_o, // ping input diff pair and ack diff pair input alert_rx_t alert_rx_i, // alert output diff pair @@ -110,14 +128,32 @@ module prim_alert_sender // alert and ping set regs logic alert_set_d, alert_set_q, alert_clr; + logic alert_test_set_d, alert_test_set_q; logic ping_set_d, ping_set_q, ping_clr; + logic alert_req_trigger, alert_test_trigger, ping_trigger; - // if handshake is ongoing, capture additional alert requests - assign alert_set_d = (alert_clr) ? 1'b0 : (alert_set_q | alert_req_i); - assign ping_set_d = (ping_clr) ? 1'b0 : (ping_set_q | ping_event); + // if handshake is ongoing, capture additional alert requests. + assign alert_req_trigger = alert_req_i | alert_set_q; + if (IsFatal) begin : gen_fatal + assign alert_set_d = alert_req_trigger; + end else begin : gen_recov + assign alert_set_d = (alert_clr) ? 1'b0 : alert_req_trigger; + end - // alert event acknowledge - assign alert_ack_o = alert_clr; + // the alert test request is always cleared. + assign alert_test_trigger = alert_test_i | alert_test_set_q; + assign alert_test_set_d = (alert_clr) ? 1'b0 : alert_test_trigger; + + logic alert_trigger; + assign alert_trigger = alert_req_trigger | alert_test_trigger; + + assign ping_trigger = ping_set_q | ping_event; + assign ping_set_d = (ping_clr) ? 1'b0 : ping_trigger; + + + // alert event acknowledge and state (not affected by alert_test_i) + assign alert_ack_o = alert_clr & alert_set_q; + assign alert_state_o = alert_set_q; // this FSM performs a full four phase handshake upon a ping or alert trigger. // note that the latency of the alert_p/n diff pair is at least one cycle @@ -127,19 +163,19 @@ module prim_alert_sender // signal that condition over to the receiver. always_comb begin : p_fsm // default - state_d = state_q; - alert_p = 1'b0; - alert_n = 1'b1; - ping_clr = 1'b0; - alert_clr = 1'b0; + state_d = state_q; + alert_p = 1'b0; + alert_n = 1'b1; + ping_clr = 1'b0; + alert_clr = 1'b0; unique case (state_q) Idle: begin // alert always takes precedence - if (alert_req_i || alert_set_q || ping_event || ping_set_q) begin - state_d = (alert_req_i || alert_set_q) ? AlertHsPhase1 : PingHsPhase1; - alert_p = 1'b1; - alert_n = 1'b0; + if (alert_trigger || ping_trigger) begin + state_d = (alert_trigger) ? AlertHsPhase1 : PingHsPhase1; + alert_p = 1'b1; + alert_n = 1'b0; end end // waiting for ack from receiver @@ -222,17 +258,19 @@ module prim_alert_sender always_ff @(posedge clk_i or negedge rst_ni) begin : p_reg if (!rst_ni) begin - state_q <= Idle; - alert_pq <= 1'b0; - alert_nq <= 1'b1; - alert_set_q <= 1'b0; - ping_set_q <= 1'b0; + state_q <= Idle; + alert_pq <= 1'b0; + alert_nq <= 1'b1; + alert_set_q <= 1'b0; + alert_test_set_q <= 1'b0; + ping_set_q <= 1'b0; end else begin - state_q <= state_d; - alert_pq <= alert_pd; - alert_nq <= alert_nd; - alert_set_q <= alert_set_d; - ping_set_q <= ping_set_d; + state_q <= state_d; + alert_pq <= alert_pd; + alert_nq <= alert_nd; + alert_set_q <= alert_set_d; + alert_test_set_q <= alert_test_set_d; + ping_set_q <= ping_set_d; end end @@ -278,8 +316,27 @@ module prim_alert_sender $rose(alert_tx_o.alert_p), clk_i, !rst_ni || (alert_tx_o.alert_p == alert_tx_o.alert_n)) end + // Test the alert state output. + `ASSERT(AlertState0_A, alert_set_q === alert_state_o) + + if (IsFatal) begin : gen_fatal_assert + `ASSERT(AlertState1_A, alert_req_i |=> alert_state_o) + `ASSERT(AlertState2_A, alert_state_o |=> $stable(alert_state_o)) + `ASSERT(AlertState3_A, alert_ack_o |=> alert_state_o) + end else begin : gen_recov_assert + `ASSERT(AlertState1_A, alert_req_i && !alert_clr |=> alert_state_o) + `ASSERT(AlertState2_A, alert_req_i && alert_ack_o |=> !alert_state_o) + end + + // The alert test input should not set the alert state register. + `ASSERT(AlertTest1_A, alert_test_i && !alert_req_i && !alert_state_o |=> $stable(alert_state_o)) + // if alert_req_i is true, handshakes should be continuously repeated `ASSERT(AlertHs_A, alert_req_i && state_q == Idle |=> $rose(alert_tx_o.alert_p), clk_i, !rst_ni || (alert_tx_o.alert_p == alert_tx_o.alert_n)) + // if alert_test_i is true, handshakes should be continuously repeated + `ASSERT(AlertTestHs_A, alert_test_i && state_q == Idle |=> $rose(alert_tx_o.alert_p), + clk_i, !rst_ni || (alert_tx_o.alert_p == alert_tx_o.alert_n)) + endmodule : prim_alert_sender diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async.sv index 3a7e8c15..558ab57d 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async.sv @@ -28,10 +28,10 @@ module prim_fifo_async #( output [DepthW-1:0] rdepth_o ); - `ASSERT_INIT(paramCheckDepth, Depth >= 3) + // Depth must be a power of 2 for the gray code pointers to work + `ASSERT_INIT(ParamCheckDepth_A, (Depth > 2) && (Depth == 2**$clog2(Depth))) localparam int unsigned PTRV_W = $clog2(Depth); - localparam logic [PTRV_W-1:0] DepthMinus1 = PTRV_W'(Depth - 1); localparam int unsigned PTR_WIDTH = PTRV_W+1; logic [PTR_WIDTH-1:0] fifo_wptr, fifo_rptr; @@ -58,23 +58,15 @@ module prim_fifo_async #( if (!rst_wr_ni) begin fifo_wptr <= {(PTR_WIDTH){1'b0}}; end else if (fifo_incr_wptr) begin - if (fifo_wptr[PTR_WIDTH-2:0] == DepthMinus1) begin - fifo_wptr <= {~fifo_wptr[PTR_WIDTH-1],{(PTR_WIDTH-1){1'b0}}}; - end else begin - fifo_wptr <= fifo_wptr + {{(PTR_WIDTH-1){1'b0}},1'b1}; + fifo_wptr <= fifo_wptr + PTR_WIDTH'(1); end - end // gray-coded version always_ff @(posedge clk_wr_i or negedge rst_wr_ni) if (!rst_wr_ni) begin fifo_wptr_gray <= {(PTR_WIDTH){1'b0}}; end else if (fifo_incr_wptr) begin - if (fifo_wptr[PTR_WIDTH-2:0] == DepthMinus1) begin - fifo_wptr_gray <= dec2gray({~fifo_wptr[PTR_WIDTH-1],{(PTR_WIDTH-1){1'b0}}}); - end else begin - fifo_wptr_gray <= dec2gray(fifo_wptr + {{(PTR_WIDTH-1){1'b0}},1'b1}); - end + fifo_wptr_gray <= dec2gray(fifo_wptr + PTR_WIDTH'(1)); end prim_flop_2sync #(.Width(PTR_WIDTH)) sync_wptr ( @@ -93,23 +85,15 @@ module prim_fifo_async #( if (!rst_rd_ni) begin fifo_rptr <= {(PTR_WIDTH){1'b0}}; end else if (fifo_incr_rptr) begin - if (fifo_rptr[PTR_WIDTH-2:0] == DepthMinus1) begin - fifo_rptr <= {~fifo_rptr[PTR_WIDTH-1],{(PTR_WIDTH-1){1'b0}}}; - end else begin - fifo_rptr <= fifo_rptr + {{(PTR_WIDTH-1){1'b0}},1'b1}; + fifo_rptr <= fifo_rptr + PTR_WIDTH'(1); end - end // gray-coded version always_ff @(posedge clk_rd_i or negedge rst_rd_ni) if (!rst_rd_ni) begin fifo_rptr_gray <= {(PTR_WIDTH){1'b0}}; end else if (fifo_incr_rptr) begin - if (fifo_rptr[PTR_WIDTH-2:0] == DepthMinus1) begin - fifo_rptr_gray <= dec2gray({~fifo_rptr[PTR_WIDTH-1],{(PTR_WIDTH-1){1'b0}}}); - end else begin - fifo_rptr_gray <= dec2gray(fifo_rptr + {{(PTR_WIDTH-1){1'b0}},1'b1}); - end + fifo_rptr_gray <= dec2gray(fifo_rptr + PTR_WIDTH'(1)); end prim_flop_2sync #(.Width(PTR_WIDTH)) sync_rptr ( 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 af559ace..77b8230f 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_sync.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_sync.sv @@ -27,9 +27,11 @@ module prim_fifo_sync #( input rready_i, output [Width-1:0] rdata_o, // occupancy + output full_o, output [DepthW-1:0] depth_o ); + // FIFO is in complete passthrough mode if (Depth == 0) begin : gen_passthru_fifo `ASSERT_INIT(paramCheckPass, Pass == 1) @@ -42,6 +44,7 @@ module prim_fifo_sync #( // host facing assign wready_o = rready_i; + assign full_o = rready_i; // this avoids lint warnings logic unused_clr; @@ -56,6 +59,16 @@ module prim_fifo_sync #( logic [PTR_WIDTH-1:0] fifo_wptr, fifo_rptr; logic fifo_incr_wptr, fifo_incr_rptr, fifo_empty; + // module under reset flag + logic under_rst; + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + under_rst <= 1'b1; + end else if (under_rst) begin + under_rst <= ~under_rst; + end + end + // create the write and read pointers logic full, empty; logic wptr_msb; @@ -71,11 +84,15 @@ module prim_fifo_sync #( (wptr_msb == rptr_msb) ? DepthW'(wptr_value) - DepthW'(rptr_value) : (DepthW'(Depth) - DepthW'(rptr_value) + DepthW'(wptr_value)) ; - assign fifo_incr_wptr = wvalid_i & wready_o; - assign fifo_incr_rptr = rvalid_o & rready_i; + assign fifo_incr_wptr = wvalid_i & wready_o & ~under_rst; + assign fifo_incr_rptr = rvalid_o & rready_i & ~under_rst; - assign wready_o = ~full; - assign rvalid_o = ~empty; + // full and not ready for write are two different concepts. + // 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 & ~under_rst; + assign full_o = full; + assign rvalid_o = ~empty & ~under_rst; always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin 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 599179b8..be09a7c8 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_intr_hw.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_intr_hw.sv @@ -40,7 +40,7 @@ module prim_intr_hw # ( // flop the interrupt output always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin - intr_o <= 1'b0; + intr_o <= '0; end else begin intr_o <= reg2hw_intr_state_q_i & reg2hw_intr_enable_q_i; end diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_lc_dec.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_lc_dec.sv new file mode 100644 index 00000000..78845ae5 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_lc_dec.sv @@ -0,0 +1,28 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Decoder for life cycle control signals with additional +// input buffers. + +module prim_lc_dec ( + input lc_ctrl_pkg::lc_tx_t lc_en_i, + output logic lc_en_dec_o +); + +logic [lc_ctrl_pkg::TxWidth-1:0] lc_en; +logic [lc_ctrl_pkg::TxWidth-1:0] lc_en_out; +assign lc_en = lc_en_i; + +// The buffer cells have a don't touch constraint on them +// such that synthesis tools won't collapse them +for (genvar k = 0; k < lc_ctrl_pkg::TxWidth; k++) begin : gen_bits + prim_buf u_prim_buf ( + .in_i ( lc_en[k] ), + .out_o ( lc_en_out[k] ) + ); +end + +assign lc_en_dec_o = (lc_en_out == lc_ctrl_pkg::On); + +endmodule : prim_lc_dec 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 a5593a35..72b825b3 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sync.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sync.sv @@ -41,6 +41,10 @@ module prim_lc_sync #( .q_o(lc_en) ); end else begin : gen_no_flops + logic unused_clk; + logic unused_rst; + assign unused_clk = clk_i; + assign unused_rst = rst_ni; assign lc_en = lc_en_i; end diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_lfsr.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_lfsr.sv index b78f4b8c..73e18b4e 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_lfsr.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_lfsr.sv @@ -60,7 +60,7 @@ module prim_lfsr #( output logic [StateOutDw-1:0] state_o // (partial) LFSR state output ); - // automatically generated with get-lfsr-coeffs.py script + // automatically generated with util/design/get-lfsr-coeffs.py script localparam int unsigned GAL_XOR_LUT_OFF = 4; localparam logic [63:0] GAL_XOR_COEFFS [61] = '{ 64'h9, diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_packer_fifo.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_packer_fifo.sv old mode 100755 new mode 100644 index f76f779e..0b82c59b --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_packer_fifo.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_packer_fifo.sv @@ -47,7 +47,6 @@ module prim_packer_fifo #( // derived parameters localparam int MaxW = (InW > OutW) ? InW : OutW, localparam int MinW = (InW < OutW) ? InW : OutW, -// localparam int DepthW = $clog2(MaxW/MinW) + ~|$clog2(MaxW/MinW) localparam int DepthW = $clog2(MaxW/MinW) ) ( input logic clk_i , @@ -64,6 +63,8 @@ module prim_packer_fifo #( output logic [DepthW:0] depth_o ); + localparam int unsigned WidthRatio = MaxW / MinW; + localparam bit [DepthW:0] FullDepth = WidthRatio[DepthW:0]; // signals logic load_data; @@ -72,24 +73,30 @@ module prim_packer_fifo #( // flops logic [DepthW:0] depth_q, depth_d; logic [MaxW-1:0] data_q, data_d; + logic clr_q, clr_d; always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin depth_q <= '0; data_q <= '0; + clr_q <= 1'b1; end else begin depth_q <= depth_d; data_q <= data_d; + clr_q <= clr_d; end end + // flop for handling reset case for clr + assign clr_d = clr_i; + assign depth_o = depth_q; if (InW < OutW) begin : gen_pack_mode logic [MaxW-1:0] wdata_shifted; - assign wdata_shifted = wdata_i << (depth_q*InW); - assign clear_data = (rready_i && rvalid_o) || clr_i; + assign wdata_shifted = {{OutW - InW{1'b0}}, wdata_i} << (depth_q*InW); + assign clear_data = (rready_i && rvalid_o) || clr_q; assign load_data = wvalid_i && wready_o; assign depth_d = clear_data ? '0 : @@ -101,9 +108,9 @@ module prim_packer_fifo #( data_q; // set outputs - assign wready_o = !(depth_q == (MaxW/MinW)); + assign wready_o = !(depth_q == FullDepth) && !clr_q; assign rdata_o = data_q; - assign rvalid_o = (depth_q == (MaxW/MinW)); + assign rvalid_o = (depth_q == FullDepth) && !clr_q; end else begin : gen_unpack_mode logic [MaxW-1:0] rdata_shifted; // ri lint_check_waive NOT_READ @@ -121,9 +128,9 @@ module prim_packer_fifo #( end assign lsb_is_one = {{DepthW{1'b0}},1'b1}; // ri lint_check_waive ZERO_REP - assign max_value = (MaxW/MinW); + assign max_value = FullDepth; assign rdata_shifted = data_q >> ptr_q*OutW; - assign clear_data = (rready_i && (depth_q == lsb_is_one)) || clr_i; + assign clear_data = (rready_i && (depth_q == lsb_is_one)) || clr_q; assign load_data = wvalid_i && wready_o; assign pull_data = rvalid_o && rready_i; @@ -141,9 +148,9 @@ module prim_packer_fifo #( data_q; // set outputs - assign wready_o = (depth_q == '0); + assign wready_o = (depth_q == '0) && !clr_q; assign rdata_o = rdata_shifted[OutW-1:0]; - assign rvalid_o = !(depth_q == '0); + assign rvalid_o = !(depth_q == '0) && !clr_q; end 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 072cfb10..072c8aad 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 @@ -28,6 +28,11 @@ module prim_ram_1p_adv #( parameter bit EnableInputPipeline = 0, // Adds an input register (read latency +1) parameter bit EnableOutputPipeline = 0, // Adds an output register (read latency +1) + // This switch allows to switch to standard Hamming ECC instead of the HSIAO ECC. + // It is recommended to leave this parameter at its default setting (HSIAO), + // since this results in a more compact and faster implementation. + parameter bit HammingECC = 0, + localparam int Aw = prim_util_pkg::vbits(Depth) ) ( input clk_i, @@ -132,21 +137,53 @@ module prim_ram_1p_adv #( assign wmask_d = {TotalWidth{1'b1}}; if (Width == 16) begin : gen_secded_22_16 - prim_secded_22_16_enc u_enc (.in(wdata_i), .out(wdata_d)); - prim_secded_22_16_dec u_dec ( - .in (rdata_sram), - .d_o (rdata_d[0+:Width]), - .syndrome_o ( ), - .err_o (rerror_d) - ); + if (HammingECC) begin : gen_hamming + prim_secded_hamming_22_16_enc u_enc ( + .in(wdata_i), + .out(wdata_d) + ); + prim_secded_hamming_22_16_dec u_dec ( + .in (rdata_sram), + .d_o (rdata_d[0+:Width]), + .syndrome_o ( ), + .err_o (rerror_d) + ); + end else begin : gen_hsiao + prim_secded_22_16_enc u_enc ( + .in(wdata_i), + .out(wdata_d) + ); + prim_secded_22_16_dec u_dec ( + .in (rdata_sram), + .d_o (rdata_d[0+:Width]), + .syndrome_o ( ), + .err_o (rerror_d) + ); + end end else if (Width == 32) begin : gen_secded_39_32 - prim_secded_39_32_enc u_enc (.in(wdata_i), .out(wdata_d)); - prim_secded_39_32_dec u_dec ( - .in (rdata_sram), - .d_o (rdata_d[0+:Width]), - .syndrome_o ( ), - .err_o (rerror_d) - ); + if (HammingECC) begin : gen_hamming + prim_secded_hamming_39_32_enc u_enc ( + .in(wdata_i), + .out(wdata_d) + ); + prim_secded_hamming_39_32_dec u_dec ( + .in (rdata_sram), + .d_o (rdata_d[0+:Width]), + .syndrome_o ( ), + .err_o (rerror_d) + ); + end else begin : gen_hsiao + prim_secded_39_32_enc u_enc ( + .in(wdata_i), + .out(wdata_d) + ); + prim_secded_39_32_dec u_dec ( + .in (rdata_sram), + .d_o (rdata_d[0+:Width]), + .syndrome_o ( ), + .err_o (rerror_d) + ); + end end end else if (EnableParity) begin : gen_byte_parity 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 57ce7e8b..faaa307b 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 @@ -24,34 +24,41 @@ `include "prim_assert.sv" module prim_ram_1p_scr #( - parameter int Depth = 16*1024, // Needs to be a power of 2 if NumAddrScrRounds > 0. - parameter int Width = 32, // Needs to be byte aligned for parity - parameter int CfgWidth = 8, // WTC, RTC, etc + parameter int Depth = 16*1024, // Needs to be a power of 2 if NumAddrScrRounds > 0. + 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. + parameter int CfgWidth = 8, // WTC, RTC, etc // Scrambling parameters. Note that this needs to be low-latency, hence we have to keep the // amount of cipher rounds low. PRINCE has 5 half rounds in its original form, which corresponds // to 2*5 + 1 effective rounds. Setting this to 2 halves this to approximately 5 effective rounds. - parameter int NumPrinceRoundsHalf = 2, // Number of PRINCE half rounds, can be [1..5] - // Number of extra intra-byte diffusion rounds. Setting this to 0 disables intra-byte diffusion. - parameter int NumByteScrRounds = 2, + // Number of PRINCE half rounds, can be [1..5] + parameter int NumPrinceRoundsHalf = 2, + // Number of extra diffusion rounds. Setting this to 0 to disable diffusion. + parameter int NumDiffRounds = 2, + // This parameter governs the block-width of additional diffusion layers. + // For intra-byte diffusion, set this parameter to 8. + // Note that DataBitsPerMask must be a multiple of this parameter. + parameter int DiffWidth = DataBitsPerMask, // Number of address scrambling rounds. Setting this to 0 disables address scrambling. - parameter int NumAddrScrRounds = 2, + parameter int NumAddrScrRounds = 2, // If set to 1, the same 64bit key stream is replicated if the data port is wider than 64bit. // If set to 0, the cipher primitive is replicated, and together with a wider nonce input, // a unique keystream is generated for the full data width. - parameter bit ReplicateKeyStream = 1'b0, + parameter bit ReplicateKeyStream = 1'b0, // Derived parameters - localparam int AddrWidth = prim_util_pkg::vbits(Depth), + localparam int AddrWidth = prim_util_pkg::vbits(Depth), // Depending on the data width, we need to instantiate multiple parallel cipher primitives to // create a keystream that is wide enough (PRINCE has a block size of 64bit) - localparam int NumParScr = (ReplicateKeyStream) ? 1 : (Width + 63) / 64, - localparam int NumParKeystr = (ReplicateKeyStream) ? (Width + 63) / 64 : 1, + localparam int NumParScr = (ReplicateKeyStream) ? 1 : (Width + 63) / 64, + localparam int NumParKeystr = (ReplicateKeyStream) ? (Width + 63) / 64 : 1, // This is given by the PRINCE cipher primitive. All parallel cipher modules // use the same key, but they use a different IV - localparam int DataKeyWidth = 128, + localparam int DataKeyWidth = 128, // Each 64 bit scrambling primitive requires a 64bit IV - localparam int NonceWidth = 64 * NumParScr + localparam int NonceWidth = 64 * NumParScr ) ( input clk_i, input rst_ni, @@ -83,6 +90,8 @@ module prim_ram_1p_scr #( // The depth needs to be a power of 2 in case address scrambling is turned on `ASSERT_INIT(DepthPow2Check_A, NumAddrScrRounds <= '0 || 2**$clog2(Depth) == Depth) + `ASSERT_INIT(DiffWidthAligned_A, (DataBitsPerMask % DiffWidth) == 0) + `ASSERT_INIT(DiffWidthWithParity_A, EnableParity && (DiffWidth == 8) || !EnableParity) ///////////////////////////////////////// // Pending Write and Address Registers // @@ -206,45 +215,49 @@ module prim_ram_1p_scr #( // read path. This allows us to hide a part of the combinational delay of the PRINCE primitive // behind the propagation delay of the SRAM macro and the per-byte diffusion step. - // Write path. Note that since this does not fan out into the interconnect, the write path is not - // as critical as the read path below in terms of timing. - logic [Width-1:0] wdata_scr_d, wdata_scr_q, wdata_q; - for (genvar k = 0; k < Width/8; k++) begin : gen_diffuse_wdata - // Apply the keystream first - logic [7:0] wdata_xor; - assign wdata_xor = wdata_q[k*8 +: 8] ^ keystream_repl[k*8 +: 8]; - - // byte aligned diffusion using a substitution / permutation network - prim_subst_perm #( - .DataWidth ( 8 ), - .NumRounds ( NumByteScrRounds ), - .Decrypt ( 0 ) - ) u_prim_subst_perm ( - .data_i ( wdata_xor ), - .key_i ( '0 ), - .data_o ( wdata_scr_d[k*8 +: 8] ) - ); - end - - // Read path. This is timing critical. The keystream XOR operation is performed last in order to - // hide the combinational delay of the PRINCE primitive behind the propagation delay of the - // SRAM and the byte diffusion. logic [Width-1:0] rdata_scr, rdata; - for (genvar k = 0; k < Width/8; k++) begin : gen_undiffuse_rdata - // Reverse diffusion first - logic [7:0] rdata_xor; + logic [Width-1:0] wdata_scr_d, wdata_scr_q, wdata_q; + for (genvar k = 0; k < (Width + DiffWidth - 1) / DiffWidth; k++) begin : gen_diffuse_data + // If the Width is not divisible by DiffWidth, we need to adjust the width of the last slice. + localparam int LocalWidth = (Width - k * DiffWidth >= DiffWidth) ? DiffWidth : + (Width - k * DiffWidth); + + // Write path. Note that since this does not fan out into the interconnect, the write path is not + // as critical as the read path below in terms of timing. + // Apply the keystream first + logic [LocalWidth-1:0] wdata_xor; + assign wdata_xor = wdata_q[k*DiffWidth +: LocalWidth] ^ + keystream_repl[k*DiffWidth +: LocalWidth]; + + // Byte aligned diffusion using a substitution / permutation network prim_subst_perm #( - .DataWidth ( 8 ), - .NumRounds ( NumByteScrRounds ), + .DataWidth ( LocalWidth ), + .NumRounds ( NumDiffRounds ), + .Decrypt ( 0 ) + ) u_prim_subst_perm_enc ( + .data_i ( wdata_xor ), + .key_i ( '0 ), + .data_o ( wdata_scr_d[k*DiffWidth +: LocalWidth] ) + ); + + // Read path. This is timing critical. The keystream XOR operation is performed last in order to + // hide the combinational delay of the PRINCE primitive behind the propagation delay of the + // SRAM and the byte diffusion. + // Reverse diffusion first + logic [LocalWidth-1:0] rdata_xor; + prim_subst_perm #( + .DataWidth ( LocalWidth ), + .NumRounds ( NumDiffRounds ), .Decrypt ( 1 ) - ) u_prim_subst_perm ( - .data_i ( rdata_scr[k*8 +: 8] ), - .key_i ( '0 ), - .data_o ( rdata_xor ) + ) u_prim_subst_perm_dec ( + .data_i ( rdata_scr[k*DiffWidth +: LocalWidth] ), + .key_i ( '0 ), + .data_o ( rdata_xor ) ); // Apply Keystream, replicate it if needed - assign rdata[k*8 +: 8] = rdata_xor ^ keystream_repl[k*8 +: 8]; + assign rdata[k*DiffWidth +: LocalWidth] = rdata_xor ^ + keystream_repl[k*DiffWidth +: LocalWidth]; end //////////////////////////////////////////////// @@ -331,10 +344,10 @@ module prim_ram_1p_scr #( prim_ram_1p_adv #( .Depth(Depth), .Width(Width), - .DataBitsPerMask(8), + .DataBitsPerMask(DataBitsPerMask), .CfgW(CfgWidth), .EnableECC(1'b0), - .EnableParity(1'b1), // We are using byte parity + .EnableParity(EnableParity), .EnableInputPipeline(1'b0), .EnableOutputPipeline(1'b0) ) u_prim_ram_1p_adv ( diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_2p_adv.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_2p_adv.sv index 278a7a8f..9a5d82cf 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_2p_adv.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_2p_adv.sv @@ -28,6 +28,11 @@ module prim_ram_2p_adv #( parameter bit EnableInputPipeline = 0, // Adds an input register (read latency +1) parameter bit EnableOutputPipeline = 0, // Adds an output register (read latency +1) + // This switch allows to switch to standard Hamming ECC instead of the HSIAO ECC. + // It is recommended to leave this parameter at its default setting (HSIAO), + // since this results in a more compact and faster implementation. + parameter bit HammingECC = 0, + localparam int Aw = prim_util_pkg::vbits(Depth) ) ( input clk_i, @@ -63,7 +68,8 @@ module prim_ram_2p_adv #( .EnableECC (EnableECC), .EnableParity (EnableParity), .EnableInputPipeline (EnableInputPipeline), - .EnableOutputPipeline(EnableOutputPipeline) + .EnableOutputPipeline(EnableOutputPipeline), + .HammingECC (HammingECC) ) i_prim_ram_2p_async_adv ( .clk_a_i(clk_i), .rst_a_ni(rst_ni), 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 3c8721ac..b594d943 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 @@ -28,6 +28,11 @@ module prim_ram_2p_async_adv #( parameter bit EnableInputPipeline = 0, // Adds an input register (read latency +1) parameter bit EnableOutputPipeline = 0, // Adds an output register (read latency +1) + // This switch allows to switch to standard Hamming ECC instead of the HSIAO ECC. + // It is recommended to leave this parameter at its default setting (HSIAO), + // since this results in a more compact and faster implementation. + parameter bit HammingECC = 0, + localparam int Aw = prim_util_pkg::vbits(Depth) ) ( input clk_a_i, @@ -176,20 +181,49 @@ module prim_ram_2p_async_adv #( assign b_wmask_d = {TotalWidth{1'b1}}; if (Width == 32) begin : gen_secded_39_32 - prim_secded_39_32_enc u_enc_a (.in(a_wdata_i), .out(a_wdata_d)); - prim_secded_39_32_dec u_dec_a ( - .in (a_rdata_sram), - .d_o (a_rdata_d[0+:Width]), - .syndrome_o ( ), - .err_o (a_rerror_d) - ); - prim_secded_39_32_enc u_enc_b (.in(b_wdata_i), .out(b_wdata_d)); - prim_secded_39_32_dec u_dec_b ( - .in (b_rdata_sram), - .d_o (b_rdata_d[0+:Width]), - .syndrome_o ( ), - .err_o (b_rerror_d) - ); + if (HammingECC) begin : gen_hamming + prim_secded_hamming_39_32_enc u_enc_a ( + .in(a_wdata_i), + .out(a_wdata_d) + ); + prim_secded_hamming_39_32_dec u_dec_a ( + .in (a_rdata_sram), + .d_o (a_rdata_d[0+:Width]), + .syndrome_o ( ), + .err_o (a_rerror_d) + ); + prim_secded_hamming_39_32_enc u_enc_b ( + .in(b_wdata_i), + .out(b_wdata_d) + ); + prim_secded_hamming_39_32_dec u_dec_b ( + .in (b_rdata_sram), + .d_o (b_rdata_d[0+:Width]), + .syndrome_o ( ), + .err_o (b_rerror_d) + ); + end else begin : gen_hsiao + prim_secded_39_32_enc u_enc_a ( + .in(a_wdata_i), + .out(a_wdata_d) + ); + prim_secded_39_32_dec u_dec_a ( + .in (a_rdata_sram), + .d_o (a_rdata_d[0+:Width]), + .syndrome_o ( ), + .err_o (a_rerror_d) + ); + prim_secded_39_32_enc u_enc_b ( + .in(b_wdata_i), + .out(b_wdata_d) + ); + prim_secded_39_32_dec u_dec_b ( + .in (b_rdata_sram), + .d_o (b_rdata_d[0+:Width]), + .syndrome_o ( ), + .err_o (b_rerror_d) + ); + end end end else if (EnableParity) begin : gen_byte_parity diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_22_16_dec.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_22_16_dec.sv index 4a12a6da..5710cb64 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_22_16_dec.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_22_16_dec.sv @@ -2,7 +2,8 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 // -// SECDED Decoder generated by secded_gen.py +// SECDED Decoder generated by +// util/design/secded_gen.py -m 6 -k 16 -s 3741324996 -c hsiao module prim_secded_22_16_dec ( input [21:0] in, @@ -14,35 +15,34 @@ module prim_secded_22_16_dec ( logic single_error; // Syndrome calculation - assign syndrome_o[0] = in[16] ^ in[0] ^ in[1] ^ in[5] ^ in[8] ^ in[9] ^ in[10] ^ in[11] ^ in[15]; - assign syndrome_o[1] = in[17] ^ in[0] ^ in[4] ^ in[5] ^ in[6] ^ in[8] ^ in[12] ^ in[13] ^ in[14]; - assign syndrome_o[2] = in[18] ^ in[1] ^ in[3] ^ in[4] ^ in[6] ^ in[7] ^ in[8] ^ in[10] ^ in[13]; - assign syndrome_o[3] = in[19] ^ in[1] ^ in[2] ^ in[3] ^ in[11] ^ in[12] ^ in[13] ^ in[14] ^ - in[15]; - assign syndrome_o[4] = in[20] ^ in[2] ^ in[3] ^ in[5] ^ in[6] ^ in[7] ^ in[9] ^ in[11] ^ in[12]; - assign syndrome_o[5] = in[21] ^ in[0] ^ in[2] ^ in[4] ^ in[7] ^ in[9] ^ in[10] ^ in[14] ^ in[15]; + assign syndrome_o[0] = ^(in & 22'h01C5C6); + assign syndrome_o[1] = ^(in & 22'h023317); + assign syndrome_o[2] = ^(in & 22'h049E2C); + assign syndrome_o[3] = ^(in & 22'h0831E9); + assign syndrome_o[4] = ^(in & 22'h10CA71); + assign syndrome_o[5] = ^(in & 22'h206C9A); // Corrected output calculation - assign d_o[0] = (syndrome_o == 6'h23) ^ in[0]; - assign d_o[1] = (syndrome_o == 6'hd) ^ in[1]; - assign d_o[2] = (syndrome_o == 6'h38) ^ in[2]; - assign d_o[3] = (syndrome_o == 6'h1c) ^ in[3]; - assign d_o[4] = (syndrome_o == 6'h26) ^ in[4]; - assign d_o[5] = (syndrome_o == 6'h13) ^ in[5]; - assign d_o[6] = (syndrome_o == 6'h16) ^ in[6]; - assign d_o[7] = (syndrome_o == 6'h34) ^ in[7]; - assign d_o[8] = (syndrome_o == 6'h7) ^ in[8]; - assign d_o[9] = (syndrome_o == 6'h31) ^ in[9]; + assign d_o[0] = (syndrome_o == 6'h1a) ^ in[0]; + assign d_o[1] = (syndrome_o == 6'h23) ^ in[1]; + assign d_o[2] = (syndrome_o == 6'h7) ^ in[2]; + assign d_o[3] = (syndrome_o == 6'h2c) ^ in[3]; + assign d_o[4] = (syndrome_o == 6'h32) ^ in[4]; + assign d_o[5] = (syndrome_o == 6'h1c) ^ in[5]; + assign d_o[6] = (syndrome_o == 6'h19) ^ in[6]; + assign d_o[7] = (syndrome_o == 6'h29) ^ in[7]; + assign d_o[8] = (syndrome_o == 6'hb) ^ in[8]; + assign d_o[9] = (syndrome_o == 6'h16) ^ in[9]; assign d_o[10] = (syndrome_o == 6'h25) ^ in[10]; - assign d_o[11] = (syndrome_o == 6'h19) ^ in[11]; - assign d_o[12] = (syndrome_o == 6'h1a) ^ in[12]; - assign d_o[13] = (syndrome_o == 6'he) ^ in[13]; - assign d_o[14] = (syndrome_o == 6'h2a) ^ in[14]; - assign d_o[15] = (syndrome_o == 6'h29) ^ in[15]; + assign d_o[11] = (syndrome_o == 6'h34) ^ in[11]; + assign d_o[12] = (syndrome_o == 6'he) ^ in[12]; + assign d_o[13] = (syndrome_o == 6'h2a) ^ in[13]; + assign d_o[14] = (syndrome_o == 6'h31) ^ in[14]; + assign d_o[15] = (syndrome_o == 6'h15) ^ in[15]; // err_o calc. bit0: single error, bit1: double error assign single_error = ^syndrome_o; - assign err_o[0] = single_error; + assign err_o[0] = single_error; assign err_o[1] = ~single_error & (|syndrome_o); -endmodule +endmodule : prim_secded_22_16_dec diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_22_16_enc.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_22_16_enc.sv index 5e3256b1..6110a88f 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_22_16_enc.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_22_16_enc.sv @@ -2,34 +2,22 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 // -// SECDED Encoder generated by secded_gen.py +// SECDED Encoder generated by +// util/design/secded_gen.py -m 6 -k 16 -s 3741324996 -c hsiao module prim_secded_22_16_enc ( input [15:0] in, output logic [21:0] out ); - assign out[0] = in[0] ; - assign out[1] = in[1] ; - assign out[2] = in[2] ; - assign out[3] = in[3] ; - assign out[4] = in[4] ; - assign out[5] = in[5] ; - assign out[6] = in[6] ; - assign out[7] = in[7] ; - assign out[8] = in[8] ; - assign out[9] = in[9] ; - assign out[10] = in[10] ; - assign out[11] = in[11] ; - assign out[12] = in[12] ; - assign out[13] = in[13] ; - assign out[14] = in[14] ; - assign out[15] = in[15] ; - assign out[16] = in[0] ^ in[1] ^ in[5] ^ in[8] ^ in[9] ^ in[10] ^ in[11] ^ in[15]; - assign out[17] = in[0] ^ in[4] ^ in[5] ^ in[6] ^ in[8] ^ in[12] ^ in[13] ^ in[14]; - assign out[18] = in[1] ^ in[3] ^ in[4] ^ in[6] ^ in[7] ^ in[8] ^ in[10] ^ in[13]; - assign out[19] = in[1] ^ in[2] ^ in[3] ^ in[11] ^ in[12] ^ in[13] ^ in[14] ^ in[15]; - assign out[20] = in[2] ^ in[3] ^ in[5] ^ in[6] ^ in[7] ^ in[9] ^ in[11] ^ in[12]; - assign out[21] = in[0] ^ in[2] ^ in[4] ^ in[7] ^ in[9] ^ in[10] ^ in[14] ^ in[15]; -endmodule + always_comb begin : p_encode + out = 22'(in); + out[16] = ^(out & 22'h00C5C6); + out[17] = ^(out & 22'h003317); + out[18] = ^(out & 22'h009E2C); + out[19] = ^(out & 22'h0031E9); + out[20] = ^(out & 22'h00CA71); + out[21] = ^(out & 22'h006C9A); + end +endmodule : prim_secded_22_16_enc diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_28_22_dec.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_28_22_dec.sv index 6452c512..0c06ff1c 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_28_22_dec.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_28_22_dec.sv @@ -2,7 +2,8 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 // -// SECDED Decoder generated by secded_gen.py +// SECDED Decoder generated by +// util/design/secded_gen.py -m 6 -k 22 -s 4256260335 -c hsiao module prim_secded_28_22_dec ( input [27:0] in, @@ -14,18 +15,12 @@ module prim_secded_28_22_dec ( logic single_error; // Syndrome calculation - assign syndrome_o[0] = in[22] ^ in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4] ^ in[5] ^ in[6] ^ in[7] - ^ in[8] ^ in[9] ^ in[20] ^ in[21]; - assign syndrome_o[1] = in[23] ^ in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[10] ^ in[11] ^ in[12] ^ in[13] - ^ in[14] ^ in[15] ^ in[20] ^ in[21]; - assign syndrome_o[2] = in[24] ^ in[0] ^ in[4] ^ in[5] ^ in[6] ^ in[10] ^ in[11] ^ in[12] ^ in[16] - ^ in[17] ^ in[18] ^ in[20]; - assign syndrome_o[3] = in[25] ^ in[1] ^ in[4] ^ in[7] ^ in[8] ^ in[10] ^ in[13] ^ in[14] ^ in[16] - ^ in[17] ^ in[19] ^ in[21]; - assign syndrome_o[4] = in[26] ^ in[2] ^ in[5] ^ in[7] ^ in[9] ^ in[11] ^ in[13] ^ in[15] ^ in[16] - ^ in[18] ^ in[19] ^ in[20] ^ in[21]; - assign syndrome_o[5] = in[27] ^ in[3] ^ in[6] ^ in[8] ^ in[9] ^ in[12] ^ in[14] ^ in[15] ^ in[17] - ^ in[18] ^ in[19] ^ in[20] ^ in[21]; + assign syndrome_o[0] = ^(in & 28'h07003FF); + assign syndrome_o[1] = ^(in & 28'h0B0FC0F); + assign syndrome_o[2] = ^(in & 28'h1371C71); + assign syndrome_o[3] = ^(in & 28'h23B6592); + assign syndrome_o[4] = ^(in & 28'h42DAAA4); + assign syndrome_o[5] = ^(in & 28'h81ED348); // Corrected output calculation assign d_o[0] = (syndrome_o == 6'h7) ^ in[0]; @@ -48,12 +43,12 @@ module prim_secded_28_22_dec ( assign d_o[17] = (syndrome_o == 6'h2c) ^ in[17]; assign d_o[18] = (syndrome_o == 6'h34) ^ in[18]; assign d_o[19] = (syndrome_o == 6'h38) ^ in[19]; - assign d_o[20] = (syndrome_o == 6'h37) ^ in[20]; - assign d_o[21] = (syndrome_o == 6'h3b) ^ in[21]; + assign d_o[20] = (syndrome_o == 6'h2f) ^ in[20]; + assign d_o[21] = (syndrome_o == 6'h1f) ^ in[21]; // err_o calc. bit0: single error, bit1: double error assign single_error = ^syndrome_o; - assign err_o[0] = single_error; + assign err_o[0] = single_error; assign err_o[1] = ~single_error & (|syndrome_o); -endmodule +endmodule : prim_secded_28_22_dec diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_28_22_enc.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_28_22_enc.sv index 0c1f023d..2d57cc4f 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_28_22_enc.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_28_22_enc.sv @@ -2,46 +2,22 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 // -// SECDED Encoder generated by secded_gen.py +// SECDED Encoder generated by +// util/design/secded_gen.py -m 6 -k 22 -s 4256260335 -c hsiao module prim_secded_28_22_enc ( input [21:0] in, output logic [27:0] out ); - assign out[0] = in[0] ; - assign out[1] = in[1] ; - assign out[2] = in[2] ; - assign out[3] = in[3] ; - assign out[4] = in[4] ; - assign out[5] = in[5] ; - assign out[6] = in[6] ; - assign out[7] = in[7] ; - assign out[8] = in[8] ; - assign out[9] = in[9] ; - assign out[10] = in[10] ; - assign out[11] = in[11] ; - assign out[12] = in[12] ; - assign out[13] = in[13] ; - assign out[14] = in[14] ; - assign out[15] = in[15] ; - assign out[16] = in[16] ; - assign out[17] = in[17] ; - assign out[18] = in[18] ; - assign out[19] = in[19] ; - assign out[20] = in[20] ; - assign out[21] = in[21] ; - assign out[22] = in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4] ^ in[5] ^ in[6] ^ in[7] ^ in[8] ^ in[9] - ^ in[20] ^ in[21]; - assign out[23] = in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[10] ^ in[11] ^ in[12] ^ in[13] ^ in[14] - ^ in[15] ^ in[20] ^ in[21]; - assign out[24] = in[0] ^ in[4] ^ in[5] ^ in[6] ^ in[10] ^ in[11] ^ in[12] ^ in[16] ^ in[17] - ^ in[18] ^ in[20]; - assign out[25] = in[1] ^ in[4] ^ in[7] ^ in[8] ^ in[10] ^ in[13] ^ in[14] ^ in[16] ^ in[17] - ^ in[19] ^ in[21]; - assign out[26] = in[2] ^ in[5] ^ in[7] ^ in[9] ^ in[11] ^ in[13] ^ in[15] ^ in[16] ^ in[18] - ^ in[19] ^ in[20] ^ in[21]; - assign out[27] = in[3] ^ in[6] ^ in[8] ^ in[9] ^ in[12] ^ in[14] ^ in[15] ^ in[17] ^ in[18] - ^ in[19] ^ in[20] ^ in[21]; -endmodule + always_comb begin : p_encode + out = 28'(in); + out[22] = ^(out & 28'h03003FF); + out[23] = ^(out & 28'h030FC0F); + out[24] = ^(out & 28'h0371C71); + out[25] = ^(out & 28'h03B6592); + out[26] = ^(out & 28'h02DAAA4); + out[27] = ^(out & 28'h01ED348); + end +endmodule : prim_secded_28_22_enc diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_39_32_dec.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_39_32_dec.sv index b6a89c6d..93873ef1 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_39_32_dec.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_39_32_dec.sv @@ -2,7 +2,8 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 // -// SECDED Decoder generated by secded_gen.py +// SECDED Decoder generated by +// util/design/secded_gen.py -m 7 -k 32 -s 3759507082 -c hsiao module prim_secded_39_32_dec ( input [38:0] in, @@ -14,64 +15,51 @@ module prim_secded_39_32_dec ( logic single_error; // Syndrome calculation - assign syndrome_o[0] = in[32] ^ in[2] ^ in[3] ^ in[7] ^ in[8] ^ in[14] ^ in[15] - ^ in[16] ^ in[18] ^ in[19] ^ in[23] ^ in[24] ^ in[28] ^ in[29] - ; - assign syndrome_o[1] = in[33] ^ in[3] ^ in[6] ^ in[8] ^ in[12] ^ in[13] ^ in[15] - ^ in[17] ^ in[19] ^ in[21] ^ in[25] ^ in[27] ^ in[29] ^ in[30] - ^ in[31] ; - assign syndrome_o[2] = in[34] ^ in[0] ^ in[5] ^ in[7] ^ in[9] ^ in[10] ^ in[12] - ^ in[13] ^ in[15] ^ in[16] ^ in[22] ^ in[23] ^ in[26] ^ in[27] - ^ in[31] ; - assign syndrome_o[3] = in[35] ^ in[0] ^ in[1] ^ in[4] ^ in[6] ^ in[9] ^ in[11] - ^ in[12] ^ in[14] ^ in[22] ^ in[23] ^ in[25] ^ in[28] ^ in[29] - ^ in[30] ; - assign syndrome_o[4] = in[36] ^ in[0] ^ in[2] ^ in[3] ^ in[4] ^ in[5] ^ in[11] - ^ in[17] ^ in[20] ^ in[24] ^ in[26] ^ in[27] ^ in[30] ; - assign syndrome_o[5] = in[37] ^ in[1] ^ in[2] ^ in[4] ^ in[6] ^ in[10] ^ in[13] - ^ in[14] ^ in[16] ^ in[18] ^ in[19] ^ in[20] ^ in[21] ^ in[22] - ^ in[26] ; - assign syndrome_o[6] = in[38] ^ in[1] ^ in[5] ^ in[7] ^ in[8] ^ in[9] ^ in[10] - ^ in[11] ^ in[17] ^ in[18] ^ in[20] ^ in[21] ^ in[24] ^ in[25] - ^ in[28] ^ in[31] ; + assign syndrome_o[0] = ^(in & 39'h01432358F1); + assign syndrome_o[1] = ^(in & 39'h02991D7680); + assign syndrome_o[2] = ^(in & 39'h04417AA04E); + assign syndrome_o[3] = ^(in & 39'h08EC104B1E); + assign syndrome_o[4] = ^(in & 39'h10A484A4E5); + assign syndrome_o[5] = ^(in & 39'h2016ED0B28); + assign syndrome_o[6] = ^(in & 39'h403AC29513); // Corrected output calculation - assign d_o[0] = (syndrome_o == 7'h1c) ^ in[0]; - assign d_o[1] = (syndrome_o == 7'h68) ^ in[1]; - assign d_o[2] = (syndrome_o == 7'h31) ^ in[2]; - assign d_o[3] = (syndrome_o == 7'h13) ^ in[3]; - assign d_o[4] = (syndrome_o == 7'h38) ^ in[4]; - assign d_o[5] = (syndrome_o == 7'h54) ^ in[5]; - assign d_o[6] = (syndrome_o == 7'h2a) ^ in[6]; - assign d_o[7] = (syndrome_o == 7'h45) ^ in[7]; - assign d_o[8] = (syndrome_o == 7'h43) ^ in[8]; - assign d_o[9] = (syndrome_o == 7'h4c) ^ in[9]; - assign d_o[10] = (syndrome_o == 7'h64) ^ in[10]; - assign d_o[11] = (syndrome_o == 7'h58) ^ in[11]; - assign d_o[12] = (syndrome_o == 7'he) ^ in[12]; - assign d_o[13] = (syndrome_o == 7'h26) ^ in[13]; - assign d_o[14] = (syndrome_o == 7'h29) ^ in[14]; - assign d_o[15] = (syndrome_o == 7'h7) ^ in[15]; - assign d_o[16] = (syndrome_o == 7'h25) ^ in[16]; - assign d_o[17] = (syndrome_o == 7'h52) ^ in[17]; - assign d_o[18] = (syndrome_o == 7'h61) ^ in[18]; - assign d_o[19] = (syndrome_o == 7'h23) ^ in[19]; - assign d_o[20] = (syndrome_o == 7'h70) ^ in[20]; - assign d_o[21] = (syndrome_o == 7'h62) ^ in[21]; - assign d_o[22] = (syndrome_o == 7'h2c) ^ in[22]; - assign d_o[23] = (syndrome_o == 7'hd) ^ in[23]; - assign d_o[24] = (syndrome_o == 7'h51) ^ in[24]; - assign d_o[25] = (syndrome_o == 7'h4a) ^ in[25]; - assign d_o[26] = (syndrome_o == 7'h34) ^ in[26]; - assign d_o[27] = (syndrome_o == 7'h16) ^ in[27]; - assign d_o[28] = (syndrome_o == 7'h49) ^ in[28]; - assign d_o[29] = (syndrome_o == 7'hb) ^ in[29]; - assign d_o[30] = (syndrome_o == 7'h1a) ^ in[30]; - assign d_o[31] = (syndrome_o == 7'h46) ^ in[31]; + assign d_o[0] = (syndrome_o == 7'h51) ^ in[0]; + assign d_o[1] = (syndrome_o == 7'h4c) ^ in[1]; + assign d_o[2] = (syndrome_o == 7'h1c) ^ in[2]; + assign d_o[3] = (syndrome_o == 7'h2c) ^ in[3]; + assign d_o[4] = (syndrome_o == 7'h49) ^ in[4]; + assign d_o[5] = (syndrome_o == 7'h31) ^ in[5]; + assign d_o[6] = (syndrome_o == 7'h15) ^ in[6]; + assign d_o[7] = (syndrome_o == 7'h13) ^ in[7]; + assign d_o[8] = (syndrome_o == 7'h68) ^ in[8]; + assign d_o[9] = (syndrome_o == 7'h2a) ^ in[9]; + assign d_o[10] = (syndrome_o == 7'h52) ^ in[10]; + assign d_o[11] = (syndrome_o == 7'h29) ^ in[11]; + assign d_o[12] = (syndrome_o == 7'h43) ^ in[12]; + assign d_o[13] = (syndrome_o == 7'h16) ^ in[13]; + assign d_o[14] = (syndrome_o == 7'hb) ^ in[14]; + assign d_o[15] = (syndrome_o == 7'h54) ^ in[15]; + assign d_o[16] = (syndrome_o == 7'h23) ^ in[16]; + assign d_o[17] = (syndrome_o == 7'h45) ^ in[17]; + assign d_o[18] = (syndrome_o == 7'h32) ^ in[18]; + assign d_o[19] = (syndrome_o == 7'h26) ^ in[19]; + assign d_o[20] = (syndrome_o == 7'he) ^ in[20]; + assign d_o[21] = (syndrome_o == 7'h25) ^ in[21]; + assign d_o[22] = (syndrome_o == 7'h64) ^ in[22]; + assign d_o[23] = (syndrome_o == 7'h70) ^ in[23]; + assign d_o[24] = (syndrome_o == 7'h7) ^ in[24]; + assign d_o[25] = (syndrome_o == 7'h61) ^ in[25]; + assign d_o[26] = (syndrome_o == 7'h38) ^ in[26]; + assign d_o[27] = (syndrome_o == 7'h4a) ^ in[27]; + assign d_o[28] = (syndrome_o == 7'h62) ^ in[28]; + assign d_o[29] = (syndrome_o == 7'h58) ^ in[29]; + assign d_o[30] = (syndrome_o == 7'hd) ^ in[30]; + assign d_o[31] = (syndrome_o == 7'h1a) ^ in[31]; // err_o calc. bit0: single error, bit1: double error assign single_error = ^syndrome_o; - assign err_o[0] = single_error; + assign err_o[0] = single_error; assign err_o[1] = ~single_error & (|syndrome_o); -endmodule +endmodule : prim_secded_39_32_dec diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_39_32_enc.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_39_32_enc.sv index ce4c26a0..f773a725 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_39_32_enc.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_39_32_enc.sv @@ -2,61 +2,23 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 // -// SECDED Encoder generated by secded_gen.py +// SECDED Encoder generated by +// util/design/secded_gen.py -m 7 -k 32 -s 3759507082 -c hsiao module prim_secded_39_32_enc ( input [31:0] in, output logic [38:0] out ); - assign out[0] = in[0] ; - assign out[1] = in[1] ; - assign out[2] = in[2] ; - assign out[3] = in[3] ; - assign out[4] = in[4] ; - assign out[5] = in[5] ; - assign out[6] = in[6] ; - assign out[7] = in[7] ; - assign out[8] = in[8] ; - assign out[9] = in[9] ; - assign out[10] = in[10] ; - assign out[11] = in[11] ; - assign out[12] = in[12] ; - assign out[13] = in[13] ; - assign out[14] = in[14] ; - assign out[15] = in[15] ; - assign out[16] = in[16] ; - assign out[17] = in[17] ; - assign out[18] = in[18] ; - assign out[19] = in[19] ; - assign out[20] = in[20] ; - assign out[21] = in[21] ; - assign out[22] = in[22] ; - assign out[23] = in[23] ; - assign out[24] = in[24] ; - assign out[25] = in[25] ; - assign out[26] = in[26] ; - assign out[27] = in[27] ; - assign out[28] = in[28] ; - assign out[29] = in[29] ; - assign out[30] = in[30] ; - assign out[31] = in[31] ; - assign out[32] = in[2] ^ in[3] ^ in[7] ^ in[8] ^ in[14] ^ in[15] ^ in[16] - ^ in[18] ^ in[19] ^ in[23] ^ in[24] ^ in[28] ^ in[29] ; - assign out[33] = in[3] ^ in[6] ^ in[8] ^ in[12] ^ in[13] ^ in[15] ^ in[17] - ^ in[19] ^ in[21] ^ in[25] ^ in[27] ^ in[29] ^ in[30] ^ in[31] ; - assign out[34] = in[0] ^ in[5] ^ in[7] ^ in[9] ^ in[10] ^ in[12] ^ in[13] - ^ in[15] ^ in[16] ^ in[22] ^ in[23] ^ in[26] ^ in[27] ^ in[31] ; - assign out[35] = in[0] ^ in[1] ^ in[4] ^ in[6] ^ in[9] ^ in[11] ^ in[12] - ^ in[14] ^ in[22] ^ in[23] ^ in[25] ^ in[28] ^ in[29] ^ in[30] - ; - assign out[36] = in[0] ^ in[2] ^ in[3] ^ in[4] ^ in[5] ^ in[11] ^ in[17] - ^ in[20] ^ in[24] ^ in[26] ^ in[27] ^ in[30] ; - assign out[37] = in[1] ^ in[2] ^ in[4] ^ in[6] ^ in[10] ^ in[13] ^ in[14] - ^ in[16] ^ in[18] ^ in[19] ^ in[20] ^ in[21] ^ in[22] ^ in[26] - ; - assign out[38] = in[1] ^ in[5] ^ in[7] ^ in[8] ^ in[9] ^ in[10] ^ in[11] - ^ in[17] ^ in[18] ^ in[20] ^ in[21] ^ in[24] ^ in[25] ^ in[28] - ^ in[31] ; -endmodule + always_comb begin : p_encode + out = 39'(in); + out[32] = ^(out & 39'h00432358F1); + out[33] = ^(out & 39'h00991D7680); + out[34] = ^(out & 39'h00417AA04E); + out[35] = ^(out & 39'h00EC104B1E); + out[36] = ^(out & 39'h00A484A4E5); + out[37] = ^(out & 39'h0016ED0B28); + out[38] = ^(out & 39'h003AC29513); + end +endmodule : prim_secded_39_32_enc diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_64_57_dec.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_64_57_dec.sv new file mode 100644 index 00000000..be2ae3e4 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_64_57_dec.sv @@ -0,0 +1,90 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED Decoder generated by +// util/design/secded_gen.py -m 7 -k 57 -s 2871209727 -c hsiao + +module prim_secded_64_57_dec ( + input [63:0] in, + output logic [56:0] d_o, + output logic [6:0] syndrome_o, + output logic [1:0] err_o +); + + logic single_error; + + // Syndrome calculation + assign syndrome_o[0] = ^(in & 64'h0303FFF800007FFF); + assign syndrome_o[1] = ^(in & 64'h057C1FF801FF801F); + assign syndrome_o[2] = ^(in & 64'h09BDE1F87E0781E1); + assign syndrome_o[3] = ^(in & 64'h11DEEE3B8E388E22); + assign syndrome_o[4] = ^(in & 64'h21EF76CDB2C93244); + assign syndrome_o[5] = ^(in & 64'h41F7BB56D5525488); + assign syndrome_o[6] = ^(in & 64'h81FBDDA769A46910); + + // Corrected output calculation + assign d_o[0] = (syndrome_o == 7'h7) ^ in[0]; + assign d_o[1] = (syndrome_o == 7'hb) ^ in[1]; + assign d_o[2] = (syndrome_o == 7'h13) ^ in[2]; + assign d_o[3] = (syndrome_o == 7'h23) ^ in[3]; + assign d_o[4] = (syndrome_o == 7'h43) ^ in[4]; + assign d_o[5] = (syndrome_o == 7'hd) ^ in[5]; + assign d_o[6] = (syndrome_o == 7'h15) ^ in[6]; + assign d_o[7] = (syndrome_o == 7'h25) ^ in[7]; + assign d_o[8] = (syndrome_o == 7'h45) ^ in[8]; + assign d_o[9] = (syndrome_o == 7'h19) ^ in[9]; + assign d_o[10] = (syndrome_o == 7'h29) ^ in[10]; + assign d_o[11] = (syndrome_o == 7'h49) ^ in[11]; + assign d_o[12] = (syndrome_o == 7'h31) ^ in[12]; + assign d_o[13] = (syndrome_o == 7'h51) ^ in[13]; + assign d_o[14] = (syndrome_o == 7'h61) ^ in[14]; + assign d_o[15] = (syndrome_o == 7'he) ^ in[15]; + assign d_o[16] = (syndrome_o == 7'h16) ^ in[16]; + assign d_o[17] = (syndrome_o == 7'h26) ^ in[17]; + assign d_o[18] = (syndrome_o == 7'h46) ^ in[18]; + assign d_o[19] = (syndrome_o == 7'h1a) ^ in[19]; + assign d_o[20] = (syndrome_o == 7'h2a) ^ in[20]; + assign d_o[21] = (syndrome_o == 7'h4a) ^ in[21]; + assign d_o[22] = (syndrome_o == 7'h32) ^ in[22]; + assign d_o[23] = (syndrome_o == 7'h52) ^ in[23]; + assign d_o[24] = (syndrome_o == 7'h62) ^ in[24]; + assign d_o[25] = (syndrome_o == 7'h1c) ^ in[25]; + assign d_o[26] = (syndrome_o == 7'h2c) ^ in[26]; + assign d_o[27] = (syndrome_o == 7'h4c) ^ in[27]; + assign d_o[28] = (syndrome_o == 7'h34) ^ in[28]; + assign d_o[29] = (syndrome_o == 7'h54) ^ in[29]; + assign d_o[30] = (syndrome_o == 7'h64) ^ in[30]; + assign d_o[31] = (syndrome_o == 7'h38) ^ in[31]; + assign d_o[32] = (syndrome_o == 7'h58) ^ in[32]; + assign d_o[33] = (syndrome_o == 7'h68) ^ in[33]; + assign d_o[34] = (syndrome_o == 7'h70) ^ in[34]; + assign d_o[35] = (syndrome_o == 7'h1f) ^ in[35]; + assign d_o[36] = (syndrome_o == 7'h2f) ^ in[36]; + assign d_o[37] = (syndrome_o == 7'h4f) ^ in[37]; + assign d_o[38] = (syndrome_o == 7'h37) ^ in[38]; + assign d_o[39] = (syndrome_o == 7'h57) ^ in[39]; + assign d_o[40] = (syndrome_o == 7'h67) ^ in[40]; + assign d_o[41] = (syndrome_o == 7'h3b) ^ in[41]; + assign d_o[42] = (syndrome_o == 7'h5b) ^ in[42]; + assign d_o[43] = (syndrome_o == 7'h6b) ^ in[43]; + assign d_o[44] = (syndrome_o == 7'h73) ^ in[44]; + assign d_o[45] = (syndrome_o == 7'h3d) ^ in[45]; + assign d_o[46] = (syndrome_o == 7'h5d) ^ in[46]; + assign d_o[47] = (syndrome_o == 7'h6d) ^ in[47]; + assign d_o[48] = (syndrome_o == 7'h75) ^ in[48]; + assign d_o[49] = (syndrome_o == 7'h79) ^ in[49]; + assign d_o[50] = (syndrome_o == 7'h3e) ^ in[50]; + assign d_o[51] = (syndrome_o == 7'h5e) ^ in[51]; + assign d_o[52] = (syndrome_o == 7'h6e) ^ in[52]; + assign d_o[53] = (syndrome_o == 7'h76) ^ in[53]; + assign d_o[54] = (syndrome_o == 7'h7a) ^ in[54]; + assign d_o[55] = (syndrome_o == 7'h7c) ^ in[55]; + assign d_o[56] = (syndrome_o == 7'h7f) ^ in[56]; + + // err_o calc. bit0: single error, bit1: double error + assign single_error = ^syndrome_o; + assign err_o[0] = single_error; + assign err_o[1] = ~single_error & (|syndrome_o); + +endmodule : prim_secded_64_57_dec diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_64_57_enc.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_64_57_enc.sv new file mode 100644 index 00000000..f0f85f82 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_64_57_enc.sv @@ -0,0 +1,24 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED Encoder generated by +// util/design/secded_gen.py -m 7 -k 57 -s 2871209727 -c hsiao + +module prim_secded_64_57_enc ( + input [56:0] in, + output logic [63:0] out +); + + always_comb begin : p_encode + out = 64'(in); + out[57] = ^(out & 64'h0103FFF800007FFF); + out[58] = ^(out & 64'h017C1FF801FF801F); + out[59] = ^(out & 64'h01BDE1F87E0781E1); + out[60] = ^(out & 64'h01DEEE3B8E388E22); + out[61] = ^(out & 64'h01EF76CDB2C93244); + out[62] = ^(out & 64'h01F7BB56D5525488); + out[63] = ^(out & 64'h01FBDDA769A46910); + end + +endmodule : prim_secded_64_57_enc diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_72_64_dec.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_72_64_dec.sv index eb4ad3ed..ebe5c7df 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_72_64_dec.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_72_64_dec.sv @@ -2,7 +2,8 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 // -// SECDED Decoder generated by secded_gen.py +// SECDED Decoder generated by +// util/design/secded_gen.py -m 8 -k 64 -s 3843802612 -c hsiao module prim_secded_72_64_dec ( input [71:0] in, @@ -14,38 +15,14 @@ module prim_secded_72_64_dec ( logic single_error; // Syndrome calculation - assign syndrome_o[0] = in[64] ^ in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4] ^ in[5] ^ in[6] ^ in[7] - ^ in[8] ^ in[9] ^ in[10] ^ in[11] ^ in[12] ^ in[13] ^ in[14] ^ in[15] - ^ in[16] ^ in[17] ^ in[18] ^ in[19] ^ in[20] ^ in[57] ^ in[59] ^ in[60] - ^ in[61] ^ in[62]; - assign syndrome_o[1] = in[65] ^ in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4] ^ in[5] ^ in[21] ^ in[22] - ^ in[23] ^ in[24] ^ in[25] ^ in[26] ^ in[27] ^ in[28] ^ in[29] ^ in[30] - ^ in[31] ^ in[32] ^ in[33] ^ in[34] ^ in[35] ^ in[56] ^ in[57] ^ in[60] - ^ in[62] ^ in[63]; - assign syndrome_o[2] = in[66] ^ in[0] ^ in[6] ^ in[7] ^ in[8] ^ in[9] ^ in[10] ^ in[21] ^ in[22] - ^ in[23] ^ in[24] ^ in[25] ^ in[36] ^ in[37] ^ in[38] ^ in[39] ^ in[40] - ^ in[41] ^ in[42] ^ in[43] ^ in[44] ^ in[45] ^ in[56] ^ in[57] ^ in[58] - ^ in[61] ^ in[62]; - assign syndrome_o[3] = in[67] ^ in[1] ^ in[6] ^ in[11] ^ in[12] ^ in[13] ^ in[14] ^ in[21] - ^ in[26] ^ in[27] ^ in[28] ^ in[29] ^ in[36] ^ in[37] ^ in[38] ^ in[39] - ^ in[46] ^ in[47] ^ in[48] ^ in[49] ^ in[50] ^ in[51] ^ in[56] ^ in[58] - ^ in[59] ^ in[62] ^ in[63]; - assign syndrome_o[4] = in[68] ^ in[2] ^ in[7] ^ in[11] ^ in[15] ^ in[16] ^ in[17] ^ in[22] - ^ in[26] ^ in[30] ^ in[31] ^ in[32] ^ in[36] ^ in[40] ^ in[41] ^ in[42] - ^ in[46] ^ in[47] ^ in[48] ^ in[52] ^ in[53] ^ in[54] ^ in[58] ^ in[59] - ^ in[60] ^ in[61] ^ in[63]; - assign syndrome_o[5] = in[69] ^ in[3] ^ in[8] ^ in[12] ^ in[15] ^ in[18] ^ in[19] ^ in[23] - ^ in[27] ^ in[30] ^ in[33] ^ in[34] ^ in[37] ^ in[40] ^ in[43] ^ in[44] - ^ in[46] ^ in[49] ^ in[50] ^ in[52] ^ in[53] ^ in[55] ^ in[56] ^ in[57] - ^ in[58] ^ in[60] ^ in[63]; - assign syndrome_o[6] = in[70] ^ in[4] ^ in[9] ^ in[13] ^ in[16] ^ in[18] ^ in[20] ^ in[24] - ^ in[28] ^ in[31] ^ in[33] ^ in[35] ^ in[38] ^ in[41] ^ in[43] ^ in[45] - ^ in[47] ^ in[49] ^ in[51] ^ in[52] ^ in[54] ^ in[55] ^ in[56] ^ in[57] - ^ in[59] ^ in[61] ^ in[63]; - assign syndrome_o[7] = in[71] ^ in[5] ^ in[10] ^ in[14] ^ in[17] ^ in[19] ^ in[20] ^ in[25] - ^ in[29] ^ in[32] ^ in[34] ^ in[35] ^ in[39] ^ in[42] ^ in[44] ^ in[45] - ^ in[48] ^ in[50] ^ in[51] ^ in[53] ^ in[54] ^ in[55] ^ in[58] ^ in[59] - ^ in[60] ^ in[61] ^ in[62]; + assign syndrome_o[0] = ^(in & 72'h019B000000001FFFFF); + assign syndrome_o[1] = ^(in & 72'h027900000FFFE0003F); + assign syndrome_o[2] = ^(in & 72'h04DC003FF003E007C1); + assign syndrome_o[3] = ^(in & 72'h08370FC0F03C207842); + assign syndrome_o[4] = ^(in & 72'h10EA71C711C4438884); + assign syndrome_o[5] = ^(in & 72'h202FB65926488C9108); + assign syndrome_o[6] = ^(in & 72'h40E6DAAA4A91152210); + assign syndrome_o[7] = ^(in & 72'h80D5ED348D221A4420); // Corrected output calculation assign d_o[0] = (syndrome_o == 8'h7) ^ in[0]; @@ -104,18 +81,18 @@ module prim_secded_72_64_dec ( assign d_o[53] = (syndrome_o == 8'hb0) ^ in[53]; assign d_o[54] = (syndrome_o == 8'hd0) ^ in[54]; assign d_o[55] = (syndrome_o == 8'he0) ^ in[55]; - assign d_o[56] = (syndrome_o == 8'h6e) ^ in[56]; - assign d_o[57] = (syndrome_o == 8'h67) ^ in[57]; - assign d_o[58] = (syndrome_o == 8'hbc) ^ in[58]; - assign d_o[59] = (syndrome_o == 8'hd9) ^ in[59]; - assign d_o[60] = (syndrome_o == 8'hb3) ^ in[60]; - assign d_o[61] = (syndrome_o == 8'hd5) ^ in[61]; - assign d_o[62] = (syndrome_o == 8'h8f) ^ in[62]; - assign d_o[63] = (syndrome_o == 8'h7a) ^ in[63]; + assign d_o[56] = (syndrome_o == 8'hab) ^ in[56]; + assign d_o[57] = (syndrome_o == 8'h79) ^ in[57]; + assign d_o[58] = (syndrome_o == 8'hec) ^ in[58]; + assign d_o[59] = (syndrome_o == 8'h37) ^ in[59]; + assign d_o[60] = (syndrome_o == 8'h8f) ^ in[60]; + assign d_o[61] = (syndrome_o == 8'h7a) ^ in[61]; + assign d_o[62] = (syndrome_o == 8'hd6) ^ in[62]; + assign d_o[63] = (syndrome_o == 8'hd5) ^ in[63]; // err_o calc. bit0: single error, bit1: double error assign single_error = ^syndrome_o; - assign err_o[0] = single_error; + assign err_o[0] = single_error; assign err_o[1] = ~single_error & (|syndrome_o); -endmodule +endmodule : prim_secded_72_64_dec diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_72_64_enc.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_72_64_enc.sv index cf89f379..93f2e1c9 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_72_64_enc.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_72_64_enc.sv @@ -2,100 +2,24 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 // -// SECDED Encoder generated by secded_gen.py +// SECDED Encoder generated by +// util/design/secded_gen.py -m 8 -k 64 -s 3843802612 -c hsiao module prim_secded_72_64_enc ( input [63:0] in, output logic [71:0] out ); - assign out[0] = in[0] ; - assign out[1] = in[1] ; - assign out[2] = in[2] ; - assign out[3] = in[3] ; - assign out[4] = in[4] ; - assign out[5] = in[5] ; - assign out[6] = in[6] ; - assign out[7] = in[7] ; - assign out[8] = in[8] ; - assign out[9] = in[9] ; - assign out[10] = in[10] ; - assign out[11] = in[11] ; - assign out[12] = in[12] ; - assign out[13] = in[13] ; - assign out[14] = in[14] ; - assign out[15] = in[15] ; - assign out[16] = in[16] ; - assign out[17] = in[17] ; - assign out[18] = in[18] ; - assign out[19] = in[19] ; - assign out[20] = in[20] ; - assign out[21] = in[21] ; - assign out[22] = in[22] ; - assign out[23] = in[23] ; - assign out[24] = in[24] ; - assign out[25] = in[25] ; - assign out[26] = in[26] ; - assign out[27] = in[27] ; - assign out[28] = in[28] ; - assign out[29] = in[29] ; - assign out[30] = in[30] ; - assign out[31] = in[31] ; - assign out[32] = in[32] ; - assign out[33] = in[33] ; - assign out[34] = in[34] ; - assign out[35] = in[35] ; - assign out[36] = in[36] ; - assign out[37] = in[37] ; - assign out[38] = in[38] ; - assign out[39] = in[39] ; - assign out[40] = in[40] ; - assign out[41] = in[41] ; - assign out[42] = in[42] ; - assign out[43] = in[43] ; - assign out[44] = in[44] ; - assign out[45] = in[45] ; - assign out[46] = in[46] ; - assign out[47] = in[47] ; - assign out[48] = in[48] ; - assign out[49] = in[49] ; - assign out[50] = in[50] ; - assign out[51] = in[51] ; - assign out[52] = in[52] ; - assign out[53] = in[53] ; - assign out[54] = in[54] ; - assign out[55] = in[55] ; - assign out[56] = in[56] ; - assign out[57] = in[57] ; - assign out[58] = in[58] ; - assign out[59] = in[59] ; - assign out[60] = in[60] ; - assign out[61] = in[61] ; - assign out[62] = in[62] ; - assign out[63] = in[63] ; - assign out[64] = in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4] ^ in[5] ^ in[6] ^ in[7] ^ in[8] ^ in[9] - ^ in[10] ^ in[11] ^ in[12] ^ in[13] ^ in[14] ^ in[15] ^ in[16] ^ in[17] ^ in[18] - ^ in[19] ^ in[20] ^ in[57] ^ in[59] ^ in[60] ^ in[61] ^ in[62]; - assign out[65] = in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4] ^ in[5] ^ in[21] ^ in[22] ^ in[23] ^ in[24] - ^ in[25] ^ in[26] ^ in[27] ^ in[28] ^ in[29] ^ in[30] ^ in[31] ^ in[32] ^ in[33] - ^ in[34] ^ in[35] ^ in[56] ^ in[57] ^ in[60] ^ in[62] ^ in[63]; - assign out[66] = in[0] ^ in[6] ^ in[7] ^ in[8] ^ in[9] ^ in[10] ^ in[21] ^ in[22] ^ in[23] - ^ in[24] ^ in[25] ^ in[36] ^ in[37] ^ in[38] ^ in[39] ^ in[40] ^ in[41] ^ in[42] - ^ in[43] ^ in[44] ^ in[45] ^ in[56] ^ in[57] ^ in[58] ^ in[61] ^ in[62]; - assign out[67] = in[1] ^ in[6] ^ in[11] ^ in[12] ^ in[13] ^ in[14] ^ in[21] ^ in[26] ^ in[27] - ^ in[28] ^ in[29] ^ in[36] ^ in[37] ^ in[38] ^ in[39] ^ in[46] ^ in[47] ^ in[48] - ^ in[49] ^ in[50] ^ in[51] ^ in[56] ^ in[58] ^ in[59] ^ in[62] ^ in[63]; - assign out[68] = in[2] ^ in[7] ^ in[11] ^ in[15] ^ in[16] ^ in[17] ^ in[22] ^ in[26] ^ in[30] - ^ in[31] ^ in[32] ^ in[36] ^ in[40] ^ in[41] ^ in[42] ^ in[46] ^ in[47] ^ in[48] - ^ in[52] ^ in[53] ^ in[54] ^ in[58] ^ in[59] ^ in[60] ^ in[61] ^ in[63]; - assign out[69] = in[3] ^ in[8] ^ in[12] ^ in[15] ^ in[18] ^ in[19] ^ in[23] ^ in[27] ^ in[30] - ^ in[33] ^ in[34] ^ in[37] ^ in[40] ^ in[43] ^ in[44] ^ in[46] ^ in[49] ^ in[50] - ^ in[52] ^ in[53] ^ in[55] ^ in[56] ^ in[57] ^ in[58] ^ in[60] ^ in[63]; - assign out[70] = in[4] ^ in[9] ^ in[13] ^ in[16] ^ in[18] ^ in[20] ^ in[24] ^ in[28] ^ in[31] - ^ in[33] ^ in[35] ^ in[38] ^ in[41] ^ in[43] ^ in[45] ^ in[47] ^ in[49] ^ in[51] - ^ in[52] ^ in[54] ^ in[55] ^ in[56] ^ in[57] ^ in[59] ^ in[61] ^ in[63]; - assign out[71] = in[5] ^ in[10] ^ in[14] ^ in[17] ^ in[19] ^ in[20] ^ in[25] ^ in[29] ^ in[32] - ^ in[34] ^ in[35] ^ in[39] ^ in[42] ^ in[44] ^ in[45] ^ in[48] ^ in[50] ^ in[51] - ^ in[53] ^ in[54] ^ in[55] ^ in[58] ^ in[59] ^ in[60] ^ in[61] ^ in[62]; -endmodule + always_comb begin : p_encode + out = 72'(in); + out[64] = ^(out & 72'h009B000000001FFFFF); + out[65] = ^(out & 72'h007900000FFFE0003F); + out[66] = ^(out & 72'h00DC003FF003E007C1); + out[67] = ^(out & 72'h00370FC0F03C207842); + out[68] = ^(out & 72'h00EA71C711C4438884); + out[69] = ^(out & 72'h002FB65926488C9108); + out[70] = ^(out & 72'h00E6DAAA4A91152210); + out[71] = ^(out & 72'h00D5ED348D221A4420); + end +endmodule : prim_secded_72_64_enc diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_22_16_dec.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_22_16_dec.sv new file mode 100644 index 00000000..49f247e8 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_22_16_dec.sv @@ -0,0 +1,46 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED Decoder generated by +// util/design/secded_gen.py -m 6 -k 16 -s 1997031251 -c hamming + +module prim_secded_hamming_22_16_dec ( + input [21:0] in, + output logic [15:0] d_o, + output logic [5:0] syndrome_o, + output logic [1:0] err_o +); + + + // Syndrome calculation + assign syndrome_o[0] = ^(in & 22'h01AD5B); + assign syndrome_o[1] = ^(in & 22'h02366D); + assign syndrome_o[2] = ^(in & 22'h04C78E); + assign syndrome_o[3] = ^(in & 22'h0807F0); + assign syndrome_o[4] = ^(in & 22'h10F800); + assign syndrome_o[5] = ^(in & 22'h3FFFFF); + + // Corrected output calculation + assign d_o[0] = (syndrome_o == 6'h23) ^ in[0]; + assign d_o[1] = (syndrome_o == 6'h25) ^ in[1]; + assign d_o[2] = (syndrome_o == 6'h26) ^ in[2]; + assign d_o[3] = (syndrome_o == 6'h27) ^ in[3]; + assign d_o[4] = (syndrome_o == 6'h29) ^ in[4]; + assign d_o[5] = (syndrome_o == 6'h2a) ^ in[5]; + assign d_o[6] = (syndrome_o == 6'h2b) ^ in[6]; + assign d_o[7] = (syndrome_o == 6'h2c) ^ in[7]; + assign d_o[8] = (syndrome_o == 6'h2d) ^ in[8]; + assign d_o[9] = (syndrome_o == 6'h2e) ^ in[9]; + assign d_o[10] = (syndrome_o == 6'h2f) ^ in[10]; + assign d_o[11] = (syndrome_o == 6'h31) ^ in[11]; + assign d_o[12] = (syndrome_o == 6'h32) ^ in[12]; + assign d_o[13] = (syndrome_o == 6'h33) ^ in[13]; + assign d_o[14] = (syndrome_o == 6'h34) ^ in[14]; + assign d_o[15] = (syndrome_o == 6'h35) ^ in[15]; + + // err_o calc. bit0: single error, bit1: double error + assign err_o[0] = syndrome_o[5]; + assign err_o[1] = |syndrome_o[4:0] & ~syndrome_o[5]; + +endmodule : prim_secded_hamming_22_16_dec diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_22_16_enc.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_22_16_enc.sv new file mode 100644 index 00000000..12fb5af9 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_22_16_enc.sv @@ -0,0 +1,23 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED Encoder generated by +// util/design/secded_gen.py -m 6 -k 16 -s 1997031251 -c hamming + +module prim_secded_hamming_22_16_enc ( + input [15:0] in, + output logic [21:0] out +); + + always_comb begin : p_encode + out = 22'(in); + out[16] = ^(out & 22'h00AD5B); + out[17] = ^(out & 22'h00366D); + out[18] = ^(out & 22'h00C78E); + out[19] = ^(out & 22'h0007F0); + out[20] = ^(out & 22'h00F800); + out[21] = ^(out & 22'h1FFFFF); + end + +endmodule : prim_secded_hamming_22_16_enc diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_39_32_dec.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_39_32_dec.sv new file mode 100644 index 00000000..b86692fb --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_39_32_dec.sv @@ -0,0 +1,63 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED Decoder generated by +// util/design/secded_gen.py -m 7 -k 32 -s 390368410 -c hamming + +module prim_secded_hamming_39_32_dec ( + input [38:0] in, + output logic [31:0] d_o, + output logic [6:0] syndrome_o, + output logic [1:0] err_o +); + + + // Syndrome calculation + assign syndrome_o[0] = ^(in & 39'h0156AAAD5B); + assign syndrome_o[1] = ^(in & 39'h029B33366D); + assign syndrome_o[2] = ^(in & 39'h04E3C3C78E); + assign syndrome_o[3] = ^(in & 39'h0803FC07F0); + assign syndrome_o[4] = ^(in & 39'h1003FFF800); + assign syndrome_o[5] = ^(in & 39'h20FC000000); + assign syndrome_o[6] = ^(in & 39'h7FFFFFFFFF); + + // Corrected output calculation + assign d_o[0] = (syndrome_o == 7'h43) ^ in[0]; + assign d_o[1] = (syndrome_o == 7'h45) ^ in[1]; + assign d_o[2] = (syndrome_o == 7'h46) ^ in[2]; + assign d_o[3] = (syndrome_o == 7'h47) ^ in[3]; + assign d_o[4] = (syndrome_o == 7'h49) ^ in[4]; + assign d_o[5] = (syndrome_o == 7'h4a) ^ in[5]; + assign d_o[6] = (syndrome_o == 7'h4b) ^ in[6]; + assign d_o[7] = (syndrome_o == 7'h4c) ^ in[7]; + assign d_o[8] = (syndrome_o == 7'h4d) ^ in[8]; + assign d_o[9] = (syndrome_o == 7'h4e) ^ in[9]; + assign d_o[10] = (syndrome_o == 7'h4f) ^ in[10]; + assign d_o[11] = (syndrome_o == 7'h51) ^ in[11]; + assign d_o[12] = (syndrome_o == 7'h52) ^ in[12]; + assign d_o[13] = (syndrome_o == 7'h53) ^ in[13]; + assign d_o[14] = (syndrome_o == 7'h54) ^ in[14]; + assign d_o[15] = (syndrome_o == 7'h55) ^ in[15]; + assign d_o[16] = (syndrome_o == 7'h56) ^ in[16]; + assign d_o[17] = (syndrome_o == 7'h57) ^ in[17]; + assign d_o[18] = (syndrome_o == 7'h58) ^ in[18]; + assign d_o[19] = (syndrome_o == 7'h59) ^ in[19]; + assign d_o[20] = (syndrome_o == 7'h5a) ^ in[20]; + assign d_o[21] = (syndrome_o == 7'h5b) ^ in[21]; + assign d_o[22] = (syndrome_o == 7'h5c) ^ in[22]; + assign d_o[23] = (syndrome_o == 7'h5d) ^ in[23]; + assign d_o[24] = (syndrome_o == 7'h5e) ^ in[24]; + assign d_o[25] = (syndrome_o == 7'h5f) ^ in[25]; + assign d_o[26] = (syndrome_o == 7'h61) ^ in[26]; + assign d_o[27] = (syndrome_o == 7'h62) ^ in[27]; + assign d_o[28] = (syndrome_o == 7'h63) ^ in[28]; + assign d_o[29] = (syndrome_o == 7'h64) ^ in[29]; + assign d_o[30] = (syndrome_o == 7'h65) ^ in[30]; + assign d_o[31] = (syndrome_o == 7'h66) ^ in[31]; + + // err_o calc. bit0: single error, bit1: double error + assign err_o[0] = syndrome_o[6]; + assign err_o[1] = |syndrome_o[5:0] & ~syndrome_o[6]; + +endmodule : prim_secded_hamming_39_32_dec diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_39_32_enc.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_39_32_enc.sv new file mode 100644 index 00000000..1cce5538 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_39_32_enc.sv @@ -0,0 +1,24 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED Encoder generated by +// util/design/secded_gen.py -m 7 -k 32 -s 390368410 -c hamming + +module prim_secded_hamming_39_32_enc ( + input [31:0] in, + output logic [38:0] out +); + + always_comb begin : p_encode + out = 39'(in); + out[32] = ^(out & 39'h0056AAAD5B); + out[33] = ^(out & 39'h009B33366D); + out[34] = ^(out & 39'h00E3C3C78E); + out[35] = ^(out & 39'h0003FC07F0); + out[36] = ^(out & 39'h0003FFF800); + out[37] = ^(out & 39'h00FC000000); + out[38] = ^(out & 39'h3FFFFFFFFF); + end + +endmodule : prim_secded_hamming_39_32_enc diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_72_64_dec.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_72_64_dec.sv index 8ac63933..5b797d5b 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_72_64_dec.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_72_64_dec.sv @@ -2,7 +2,8 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 // -// SECDED Decoder generated by secded_gen.py +// SECDED Decoder generated by +// util/design/secded_gen.py -m 8 -k 64 -s 1218923287 -c hamming module prim_secded_hamming_72_64_dec ( input [71:0] in, @@ -11,45 +12,16 @@ module prim_secded_hamming_72_64_dec ( output logic [1:0] err_o ); - logic single_error; // Syndrome calculation - assign syndrome_o[0] = in[64] ^ in[0] ^ in[1] ^ in[3] ^ in[4] ^ in[6] ^ in[8] ^ in[10] ^ in[11] - ^ in[13] ^ in[15] ^ in[17] ^ in[19] ^ in[21] ^ in[23] ^ in[25] ^ in[26] - ^ in[28] ^ in[30] ^ in[32] ^ in[34] ^ in[36] ^ in[38] ^ in[40] ^ in[42] - ^ in[44] ^ in[46] ^ in[48] ^ in[50] ^ in[52] ^ in[54] ^ in[56] ^ in[57] - ^ in[59] ^ in[61] ^ in[63]; - assign syndrome_o[1] = in[65] ^ in[0] ^ in[2] ^ in[3] ^ in[5] ^ in[6] ^ in[9] ^ in[10] ^ in[12] - ^ in[13] ^ in[16] ^ in[17] ^ in[20] ^ in[21] ^ in[24] ^ in[25] ^ in[27] - ^ in[28] ^ in[31] ^ in[32] ^ in[35] ^ in[36] ^ in[39] ^ in[40] ^ in[43] - ^ in[44] ^ in[47] ^ in[48] ^ in[51] ^ in[52] ^ in[55] ^ in[56] ^ in[58] - ^ in[59] ^ in[62] ^ in[63]; - assign syndrome_o[2] = in[66] ^ in[1] ^ in[2] ^ in[3] ^ in[7] ^ in[8] ^ in[9] ^ in[10] ^ in[14] - ^ in[15] ^ in[16] ^ in[17] ^ in[22] ^ in[23] ^ in[24] ^ in[25] ^ in[29] - ^ in[30] ^ in[31] ^ in[32] ^ in[37] ^ in[38] ^ in[39] ^ in[40] ^ in[45] - ^ in[46] ^ in[47] ^ in[48] ^ in[53] ^ in[54] ^ in[55] ^ in[56] ^ in[60] - ^ in[61] ^ in[62] ^ in[63]; - assign syndrome_o[3] = in[67] ^ in[4] ^ in[5] ^ in[6] ^ in[7] ^ in[8] ^ in[9] ^ in[10] ^ in[18] - ^ in[19] ^ in[20] ^ in[21] ^ in[22] ^ in[23] ^ in[24] ^ in[25] ^ in[33] - ^ in[34] ^ in[35] ^ in[36] ^ in[37] ^ in[38] ^ in[39] ^ in[40] ^ in[49] - ^ in[50] ^ in[51] ^ in[52] ^ in[53] ^ in[54] ^ in[55] ^ in[56]; - assign syndrome_o[4] = in[68] ^ in[11] ^ in[12] ^ in[13] ^ in[14] ^ in[15] ^ in[16] ^ in[17] - ^ in[18] ^ in[19] ^ in[20] ^ in[21] ^ in[22] ^ in[23] ^ in[24] ^ in[25] - ^ in[41] ^ in[42] ^ in[43] ^ in[44] ^ in[45] ^ in[46] ^ in[47] ^ in[48] - ^ in[49] ^ in[50] ^ in[51] ^ in[52] ^ in[53] ^ in[54] ^ in[55] ^ in[56]; - assign syndrome_o[5] = in[69] ^ in[26] ^ in[27] ^ in[28] ^ in[29] ^ in[30] ^ in[31] ^ in[32] - ^ in[33] ^ in[34] ^ in[35] ^ in[36] ^ in[37] ^ in[38] ^ in[39] ^ in[40] - ^ in[41] ^ in[42] ^ in[43] ^ in[44] ^ in[45] ^ in[46] ^ in[47] ^ in[48] - ^ in[49] ^ in[50] ^ in[51] ^ in[52] ^ in[53] ^ in[54] ^ in[55] ^ in[56]; - assign syndrome_o[6] = in[70] ^ in[57] ^ in[58] ^ in[59] ^ in[60] ^ in[61] ^ in[62] ^ in[63]; - assign syndrome_o[7] = in[71] ^ in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4] ^ in[5] ^ in[6] ^ in[7] - ^ in[8] ^ in[9] ^ in[10] ^ in[11] ^ in[12] ^ in[13] ^ in[14] ^ in[15] - ^ in[16] ^ in[17] ^ in[18] ^ in[19] ^ in[20] ^ in[21] ^ in[22] ^ in[23] - ^ in[24] ^ in[25] ^ in[26] ^ in[27] ^ in[28] ^ in[29] ^ in[30] ^ in[31] - ^ in[32] ^ in[33] ^ in[34] ^ in[35] ^ in[36] ^ in[37] ^ in[38] ^ in[39] - ^ in[40] ^ in[41] ^ in[42] ^ in[43] ^ in[44] ^ in[45] ^ in[46] ^ in[47] - ^ in[48] ^ in[49] ^ in[50] ^ in[51] ^ in[52] ^ in[53] ^ in[54] ^ in[55] - ^ in[56] ^ in[57] ^ in[58] ^ in[59] ^ in[60] ^ in[61] ^ in[62] ^ in[63]; + assign syndrome_o[0] = ^(in & 72'h01AB55555556AAAD5B); + assign syndrome_o[1] = ^(in & 72'h02CD9999999B33366D); + assign syndrome_o[2] = ^(in & 72'h04F1E1E1E1E3C3C78E); + assign syndrome_o[3] = ^(in & 72'h0801FE01FE03FC07F0); + assign syndrome_o[4] = ^(in & 72'h1001FFFE0003FFF800); + assign syndrome_o[5] = ^(in & 72'h2001FFFFFFFC000000); + assign syndrome_o[6] = ^(in & 72'h40FE00000000000000); + assign syndrome_o[7] = ^(in & 72'hFFFFFFFFFFFFFFFFFF); // Corrected output calculation assign d_o[0] = (syndrome_o == 8'h83) ^ in[0]; @@ -118,8 +90,7 @@ module prim_secded_hamming_72_64_dec ( assign d_o[63] = (syndrome_o == 8'hc7) ^ in[63]; // err_o calc. bit0: single error, bit1: double error - assign single_error = ^syndrome_o; - assign err_o[0] = single_error; - assign err_o[1] = ~single_error & (|syndrome_o); -endmodule + assign err_o[0] = syndrome_o[7]; + assign err_o[1] = |syndrome_o[6:0] & ~syndrome_o[7]; +endmodule : prim_secded_hamming_72_64_dec diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_72_64_enc.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_72_64_enc.sv index 49f92fc5..edd07382 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_72_64_enc.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_72_64_enc.sv @@ -2,108 +2,24 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 // -// SECDED Encoder generated by secded_gen.py +// SECDED Encoder generated by +// util/design/secded_gen.py -m 8 -k 64 -s 1218923287 -c hamming module prim_secded_hamming_72_64_enc ( input [63:0] in, output logic [71:0] out ); - assign out[0] = in[0] ; - assign out[1] = in[1] ; - assign out[2] = in[2] ; - assign out[3] = in[3] ; - assign out[4] = in[4] ; - assign out[5] = in[5] ; - assign out[6] = in[6] ; - assign out[7] = in[7] ; - assign out[8] = in[8] ; - assign out[9] = in[9] ; - assign out[10] = in[10] ; - assign out[11] = in[11] ; - assign out[12] = in[12] ; - assign out[13] = in[13] ; - assign out[14] = in[14] ; - assign out[15] = in[15] ; - assign out[16] = in[16] ; - assign out[17] = in[17] ; - assign out[18] = in[18] ; - assign out[19] = in[19] ; - assign out[20] = in[20] ; - assign out[21] = in[21] ; - assign out[22] = in[22] ; - assign out[23] = in[23] ; - assign out[24] = in[24] ; - assign out[25] = in[25] ; - assign out[26] = in[26] ; - assign out[27] = in[27] ; - assign out[28] = in[28] ; - assign out[29] = in[29] ; - assign out[30] = in[30] ; - assign out[31] = in[31] ; - assign out[32] = in[32] ; - assign out[33] = in[33] ; - assign out[34] = in[34] ; - assign out[35] = in[35] ; - assign out[36] = in[36] ; - assign out[37] = in[37] ; - assign out[38] = in[38] ; - assign out[39] = in[39] ; - assign out[40] = in[40] ; - assign out[41] = in[41] ; - assign out[42] = in[42] ; - assign out[43] = in[43] ; - assign out[44] = in[44] ; - assign out[45] = in[45] ; - assign out[46] = in[46] ; - assign out[47] = in[47] ; - assign out[48] = in[48] ; - assign out[49] = in[49] ; - assign out[50] = in[50] ; - assign out[51] = in[51] ; - assign out[52] = in[52] ; - assign out[53] = in[53] ; - assign out[54] = in[54] ; - assign out[55] = in[55] ; - assign out[56] = in[56] ; - assign out[57] = in[57] ; - assign out[58] = in[58] ; - assign out[59] = in[59] ; - assign out[60] = in[60] ; - assign out[61] = in[61] ; - assign out[62] = in[62] ; - assign out[63] = in[63] ; - assign out[64] = in[0] ^ in[1] ^ in[3] ^ in[4] ^ in[6] ^ in[8] ^ in[10] ^ in[11] ^ in[13] ^ in[15] - ^ in[17] ^ in[19] ^ in[21] ^ in[23] ^ in[25] ^ in[26] ^ in[28] ^ in[30] ^ in[32] - ^ in[34] ^ in[36] ^ in[38] ^ in[40] ^ in[42] ^ in[44] ^ in[46] ^ in[48] ^ in[50] - ^ in[52] ^ in[54] ^ in[56] ^ in[57] ^ in[59] ^ in[61] ^ in[63]; - assign out[65] = in[0] ^ in[2] ^ in[3] ^ in[5] ^ in[6] ^ in[9] ^ in[10] ^ in[12] ^ in[13] ^ in[16] - ^ in[17] ^ in[20] ^ in[21] ^ in[24] ^ in[25] ^ in[27] ^ in[28] ^ in[31] ^ in[32] - ^ in[35] ^ in[36] ^ in[39] ^ in[40] ^ in[43] ^ in[44] ^ in[47] ^ in[48] ^ in[51] - ^ in[52] ^ in[55] ^ in[56] ^ in[58] ^ in[59] ^ in[62] ^ in[63]; - assign out[66] = in[1] ^ in[2] ^ in[3] ^ in[7] ^ in[8] ^ in[9] ^ in[10] ^ in[14] ^ in[15] ^ in[16] - ^ in[17] ^ in[22] ^ in[23] ^ in[24] ^ in[25] ^ in[29] ^ in[30] ^ in[31] ^ in[32] - ^ in[37] ^ in[38] ^ in[39] ^ in[40] ^ in[45] ^ in[46] ^ in[47] ^ in[48] ^ in[53] - ^ in[54] ^ in[55] ^ in[56] ^ in[60] ^ in[61] ^ in[62] ^ in[63]; - assign out[67] = in[4] ^ in[5] ^ in[6] ^ in[7] ^ in[8] ^ in[9] ^ in[10] ^ in[18] ^ in[19] ^ in[20] - ^ in[21] ^ in[22] ^ in[23] ^ in[24] ^ in[25] ^ in[33] ^ in[34] ^ in[35] ^ in[36] - ^ in[37] ^ in[38] ^ in[39] ^ in[40] ^ in[49] ^ in[50] ^ in[51] ^ in[52] ^ in[53] - ^ in[54] ^ in[55] ^ in[56]; - assign out[68] = in[11] ^ in[12] ^ in[13] ^ in[14] ^ in[15] ^ in[16] ^ in[17] ^ in[18] ^ in[19] - ^ in[20] ^ in[21] ^ in[22] ^ in[23] ^ in[24] ^ in[25] ^ in[41] ^ in[42] ^ in[43] - ^ in[44] ^ in[45] ^ in[46] ^ in[47] ^ in[48] ^ in[49] ^ in[50] ^ in[51] ^ in[52] - ^ in[53] ^ in[54] ^ in[55] ^ in[56]; - assign out[69] = in[26] ^ in[27] ^ in[28] ^ in[29] ^ in[30] ^ in[31] ^ in[32] ^ in[33] ^ in[34] - ^ in[35] ^ in[36] ^ in[37] ^ in[38] ^ in[39] ^ in[40] ^ in[41] ^ in[42] ^ in[43] - ^ in[44] ^ in[45] ^ in[46] ^ in[47] ^ in[48] ^ in[49] ^ in[50] ^ in[51] ^ in[52] - ^ in[53] ^ in[54] ^ in[55] ^ in[56]; - assign out[70] = in[57] ^ in[58] ^ in[59] ^ in[60] ^ in[61] ^ in[62] ^ in[63]; - assign out[71] = in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4] ^ in[5] ^ in[6] ^ in[7] ^ in[8] ^ in[9] - ^ in[10] ^ in[11] ^ in[12] ^ in[13] ^ in[14] ^ in[15] ^ in[16] ^ in[17] ^ in[18] - ^ in[19] ^ in[20] ^ in[21] ^ in[22] ^ in[23] ^ in[24] ^ in[25] ^ in[26] ^ in[27] - ^ in[28] ^ in[29] ^ in[30] ^ in[31] ^ in[32] ^ in[33] ^ in[34] ^ in[35] ^ in[36] - ^ in[37] ^ in[38] ^ in[39] ^ in[40] ^ in[41] ^ in[42] ^ in[43] ^ in[44] ^ in[45] - ^ in[46] ^ in[47] ^ in[48] ^ in[49] ^ in[50] ^ in[51] ^ in[52] ^ in[53] ^ in[54] - ^ in[55] ^ in[56] ^ in[57] ^ in[58] ^ in[59] ^ in[60] ^ in[61] ^ in[62] ^ in[63]; -endmodule + always_comb begin : p_encode + out = 72'(in); + out[64] = ^(out & 72'h00AB55555556AAAD5B); + out[65] = ^(out & 72'h00CD9999999B33366D); + out[66] = ^(out & 72'h00F1E1E1E1E3C3C78E); + out[67] = ^(out & 72'h0001FE01FE03FC07F0); + out[68] = ^(out & 72'h0001FFFE0003FFF800); + out[69] = ^(out & 72'h0001FFFFFFFC000000); + out[70] = ^(out & 72'h00FE00000000000000); + out[71] = ^(out & 72'h7FFFFFFFFFFFFFFFFF); + end +endmodule : prim_secded_hamming_72_64_enc 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 bd803496..2df22ea8 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_sram_arbiter.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_sram_arbiter.sv @@ -112,10 +112,11 @@ module prim_sram_arbiter #( .wvalid_i (sram_req_o & ~sram_write_o), // Push only for read .wready_o (), // TODO: Generate Error .wdata_i (gnt_o), - .depth_o (), // Not used .rvalid_o (), // TODO; Generate error if sram_rvalid_i but rvalid==0 .rready_i (sram_ack), - .rdata_o (steer) + .rdata_o (steer), + .full_o (), + .depth_o () // Not used ); assign rsp_rvalid_o = steer & {N{sram_rvalid_i}}; diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_slow_fast.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_slow_fast.sv new file mode 100644 index 00000000..8bffa1d5 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_slow_fast.sv @@ -0,0 +1,59 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Slow to fast clock synchronizer +// This module is designed to be used for efficient sampling of signals from a slow clock to a much +// faster clock. +// +// The data is captured into flops on the negative edge of the slow clock (when the data should be +// stable). Because the slow clock passes through a two-flop synchronizer, the ratio of clock speeds +// needs to be high to guarantee that the data will be stable when sampled. +// +// A ratio of at-least 10:1 in clock speeds is recommended. + +module prim_sync_slow_fast #( + parameter int unsigned Width = 32 +) ( + input logic clk_slow_i, + input logic clk_fast_i, + input logic rst_fast_ni, + input logic [Width-1:0] wdata_i, // Slow domain + output logic [Width-1:0] rdata_o // Fast domain +); + + logic sync_clk_slow, sync_clk_slow_q; + logic wdata_en; + logic [Width-1:0] wdata_q; + + // Synchronize the slow clock to the fast domain + prim_flop_2sync #(.Width(1)) sync_slow_clk ( + .clk_i (clk_fast_i), + .rst_ni (rst_fast_ni), + .d_i (clk_slow_i), + .q_o (sync_clk_slow)); + + // Register the synchronized clk + always_ff @(posedge clk_fast_i or negedge rst_fast_ni) begin + if (!rst_fast_ni) begin + sync_clk_slow_q <= 1'b0; + end else begin + sync_clk_slow_q <= sync_clk_slow; + end + end + + // Find the negative edge of the synchronized slow clk + assign wdata_en = sync_clk_slow_q & !sync_clk_slow; + + // Sample the slow data on the negative edge + always_ff @(posedge clk_fast_i or negedge rst_fast_ni) begin + if (!rst_fast_ni) begin + wdata_q <= '0; + end else if (wdata_en) begin + wdata_q <= wdata_i; + end + end + + assign rdata_o = wdata_q; + +endmodule 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 6093646c..36960c65 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_util_pkg.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_util_pkg.sv @@ -27,9 +27,12 @@ package prim_util_pkg; */ function automatic integer _clog2(integer value); integer result; - value = value - 1; - for (result = 0; value > 0; result = result + 1) begin - value = value >> 1; + // 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 @@ -77,7 +80,7 @@ package prim_util_pkg; // 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 : prim_util_pkg::_clog2(value); + return (value == 1) ? 1 : _clog2(value); `else return (value == 1) ? 1 : $clog2(value); `endif diff --git a/vendor/lowrisc_ip/ip/prim/util/gen-lfsr-seed.py b/vendor/lowrisc_ip/ip/prim/util/gen-lfsr-seed.py deleted file mode 100755 index 6bf56e69..00000000 --- a/vendor/lowrisc_ip/ip/prim/util/gen-lfsr-seed.py +++ /dev/null @@ -1,161 +0,0 @@ -#!/usr/bin/env python3 -# Copyright lowRISC contributors. -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 -r"""This script generates random seeds and state permutations for LFSRs -and outputs them them as a packed SV logic vectors suitable for use with -prim_lfsr.sv. -""" -import argparse -import random -import textwrap -import logging as log -from math import ceil, log2 - - -SV_INSTRUCTIONS = """ ------------------------------------------------- -| COPY PASTE THE CODE TEMPLATE BELOW INTO YOUR | -| RTL CODE, INLUDING THE COMMENT IN ORDER TO | -| EASE AUDITABILITY AND REPRODUCIBILITY. | ------------------------------------------------- -""" - - -def _as_snake_case_prefix(name): - """ Convert PascalCase name into snake_case name""" - outname = "" - for c in name: - if c.isupper() and len(outname) > 0: - outname += '_' - outname += c.lower() - return outname + ('_' if name else '') - - -def _get_random_data_hex_literal(width): - """ Fetch 'width' random bits and return them as hex literal""" - width = int(width) - literal_str = hex(random.getrandbits(width)) - literal_str = str(width) + "'h" + literal_str[2:] - return literal_str - - -def _blockify(s, size, limit): - """ Make sure the output does not exceed a certain size per line""" - - str_idx = 2 - remain = size % (limit * 4) - numbits = remain if remain else limit * 4 - s_list = [] - - remain = size - while remain > 0: - s_incr = int(numbits / 4) - s_list.append("{}'h{}".format(numbits, s[str_idx: str_idx + s_incr])) - str_idx += s_incr - remain -= numbits - numbits = limit * 4 - - return(",\n ".join(s_list)) - - -def _get_random_perm_hex_literal(numel): - """ Compute a random permutation of 'numel' elements and - return as packed hex literal""" - num_elements = int(numel) - width = int(ceil(log2(num_elements))) - idx = [x for x in range(num_elements)] - random.shuffle(idx) - literal_str = "" - for k in idx: - literal_str += format(k, '0' + str(width) + 'b') - # convert to hex for space efficiency - literal_str = hex(int(literal_str, 2)) - return _blockify(literal_str, width * numel, 64) - - -def _wrapped_docstring(): - '''Return a text-wrapped version of the module docstring''' - paras = [] - para = [] - for line in __doc__.strip().split('\n'): - line = line.strip() - if not line: - if para: - paras.append('\n'.join(para)) - para = [] - else: - para.append(line) - if para: - paras.append('\n'.join(para)) - - return '\n\n'.join(textwrap.fill(p) for p in paras) - - -def main(): - log.basicConfig(level=log.INFO, - format="%(asctime)s - %(message)s", - datefmt="%Y-%m-%d %H:%M") - - parser = argparse.ArgumentParser( - prog="gen-lfsre-perm", - description=_wrapped_docstring(), - formatter_class=argparse.RawDescriptionHelpFormatter) - parser.add_argument('-w', - '--width', - type=int, - default=32, - metavar='<#bitwidth>', - help='LFSR width.') - parser.add_argument('-s', - '--seed', - type=int, - metavar='', - help='Custom seed for RNG.') - parser.add_argument('-p', - '--prefix', - type=str, - metavar='name', - default="", - help='Optional prefix to add to ' - 'types and parameters. ' - 'Make sure this is PascalCase.') - - args = parser.parse_args() - - if args.width <= 0: - log.error("LFSR width must be nonzero") - exit(1) - - if args.seed is None: - random.seed() - args.seed = random.getrandbits(32) - - random.seed(args.seed) - - print(SV_INSTRUCTIONS) - - type_prefix = _as_snake_case_prefix(args.prefix) - - outstr = ''' -// These LFSR parameters have been generated with -// $ hw/ip/prim/util/gen-lfsr-seed.py --width {} --seed {} --prefix "{}" -parameter int {}LfsrWidth = {}; -typedef logic [{}LfsrWidth-1:0] {}lfsr_seed_t; -typedef logic [{}LfsrWidth-1:0][$clog2({}LfsrWidth)-1:0] {}lfsr_perm_t; -parameter {}lfsr_seed_t RndCnst{}LfsrSeedDefault = {}; -parameter {}lfsr_perm_t RndCnst{}LfsrPermDefault = {{ - {} -}}; -'''.format(args.width, args.seed, args.prefix, - args.prefix, args.width, - args.prefix, type_prefix, - args.prefix, args.prefix, type_prefix, - type_prefix, args.prefix, _get_random_data_hex_literal(args.width), - type_prefix, args.prefix, _get_random_perm_hex_literal(args.width)) - - print(outstr) - - -if __name__ == "__main__": - main() diff --git a/vendor/lowrisc_ip/ip/prim/util/get-lfsr-coeffs.py b/vendor/lowrisc_ip/ip/prim/util/get-lfsr-coeffs.py deleted file mode 100755 index 44c41521..00000000 --- a/vendor/lowrisc_ip/ip/prim/util/get-lfsr-coeffs.py +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/env python3 -# Copyright lowRISC contributors. -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 - -import argparse -import glob -import os -import shutil -import subprocess -import sys - -import wget - -USAGE = """./get_lfsr_coeffs.py [-t ] [-o ] [-f] [--fib] - -Downloads LFSR constants from [1] and dumps them in SystemVerilog format -(for use in prim_lfsr.sv). These coeffs are for a Galois XOR type LFSR, and cover -implementations ranging from 4 to 64bits. - -Alternatively, the script can also extract the XNOR Fibonacci type LFSR coefficients -from the XILINX application note 52 [2] by specifying the --fib switch. Note that this -depends on the pdftotext utility for Linux. - -[1] https://users.ece.cmu.edu/~koopman/lfsr/ - -[2] https://www.xilinx.com/support/documentation/application_notes/xapp052.pdf -""" - -# configuration for Galois -MIN_LFSR_LEN = 4 -MAX_LFSR_LEN = 64 -BASE_URL = 'https://users.ece.cmu.edu/~koopman/lfsr/' - -# configuration for Fibonacci -FIB_URL = 'https://www.xilinx.com/support/documentation/application_notes/xapp052.pdf' -PDF_NAME = 'xapp052' -LINE_FILTER = [ - 'Table 3: Taps for Maximum-Length LFSR Counters', - 'XAPP 052 July 7,1996 (Version 1.1)' -] - - -# helper function to write out coeffs -def dump_coeffs(lfsrType, widths, coeffs, outfile): - # widths consistency check - for k in range(widths[0], widths[-1] + 1): - # print("%d -- %d" % (k,widths[k-widths[0]])) - if k != widths[k - widths[0]]: - print("Error: widths is not consistently increasing") - sys.exit(1) - - # select first coefficient in each file and print to SV LUT - with outfile: - decl_str = "localparam int unsigned %s_LUT_OFF = %d;\n" \ - % (lfsrType, min(widths)) - outfile.write(decl_str) - decl_str = "localparam logic [%d:0] %s_COEFFS [%d] = '{ " \ - % (max(widths) - 1, lfsrType, max(widths)-min(widths)+1) - outfile.write(decl_str) - comma = ',\n' - spaces = '' - for k in widths: - if k == max(widths): - comma = "" - if k == min(widths) + 1: - for l in range(len(decl_str)): - spaces += ' ' - outfile.write("%s%d'h%s%s" % \ - (spaces, max(widths), coeffs[k-widths[0]], comma)) - outfile.write(' };\n') - - -# converts list with bit positions to a hex bit mask string -def to_bit_mask(bitPositions): - - bitMask = 0 - for b in bitPositions: - bitMask += 2**(b - 1) - - return "%X" % bitMask - - -def main(): - parser = argparse.ArgumentParser( - prog="get-lfsr-coeffs", - formatter_class=argparse.RawDescriptionHelpFormatter, - usage=USAGE, - description=__doc__, - epilog='defaults or the filename - can be used for stdin/stdout') - parser.add_argument( - '-t', - '--tempfolder', - help="""temporary folder to download the lfsr constant files -to (defaults to lfsr_tmp)""", - default='lfsr_tmp') - parser.add_argument('--fib', - help='download fibonacci coefficients', - action='store_true') - parser.add_argument('-f', - '--force', - help='overwrites tempfolder', - action='store_true') - parser.add_argument('-o', - '--output', - type=argparse.FileType('w'), - default=sys.stdout, - metavar='file', - help='Output file (default stdout)') - - args = parser.parse_args() - - if args.force and os.path.exists(args.tempfolder): - shutil.rmtree(args.tempfolder) - - if not os.path.exists(args.tempfolder): - # download coefficient files - os.makedirs(args.tempfolder, exist_ok=args.force) - os.chdir(args.tempfolder) - - if args.fib: - lfsrType = 'FIB_XNOR' - - wget.download(FIB_URL) - cmd = ['pdftotext %s.pdf' % PDF_NAME, '> %s.txt' % PDF_NAME] - subprocess.call(cmd, shell=True) - print("") - cmd = ['grep -A 350 "%s" %s.txt > table.txt' \ - % (LINE_FILTER[0], PDF_NAME)] - subprocess.call(cmd, shell=True) - - # parse the table - widths = [] - coeffs = [] - columnType = 0 - with open('table.txt') as infile: - for line in infile: - line = line.strip() - if line and line not in LINE_FILTER: - if line == 'n': - columnType = 0 - # yes, this is a typo in the PDF :) - elif line == 'XNOR from': - columnType = 1 - elif columnType: - tmpCoeffs = [int(c) for c in line.split(',')] - coeffs += [tmpCoeffs] - else: - widths += [int(line)] - - # # printout for checking - # for (w,c) in zip(widths,coeffs): - # print("width: %d > coeffs: %s" % (w, str(c))) - - # convert to bitmask - for k in range(len(coeffs)): - coeffs[k] = to_bit_mask(coeffs[k]) - - else: - lfsrType = 'GAL_XOR' - - for k in range(MIN_LFSR_LEN, MAX_LFSR_LEN + 1): - url = '%s%d.txt' % (BASE_URL, k) - print("\nDownloading %d bit LFSR coeffs from %s..." % (k, url)) - wget.download(url) - print("") - - widths = [] - coeffs = [] - for k in range(MIN_LFSR_LEN, MAX_LFSR_LEN + 1): - filename = '%d.txt' % k - with open(filename) as infile: - # read the first line - widths += [k] - coeffs += [infile.readline().strip()] - - # write to stdout or file - dump_coeffs(lfsrType, widths, coeffs, outfile=args.output) - else: - print("Temporary directory already exists, abort...") - sys.exit(1) - - -if __name__ == '__main__': - main() diff --git a/vendor/lowrisc_ip/ip/prim/util/keccak_rc.py b/vendor/lowrisc_ip/ip/prim/util/keccak_rc.py deleted file mode 100755 index 1ee97d0f..00000000 --- a/vendor/lowrisc_ip/ip/prim/util/keccak_rc.py +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env python3 -# Copyright lowRISC contributors. -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 -r"""Calculate Round Constant -""" - -import argparse -import bitarray as ba -import logging as log - - -def main(): - parser = argparse.ArgumentParser( - prog="keccak round constant generator", - description= - '''This tool generates the round constants based on the given max round number''' - ) - parser.add_argument( - '-r', - type=int, - default=24, - help='''Max Round value. Default is SHA3 Keccak round %(default)''') - parser.add_argument('--verbose', '-v', action='store_true', help='Verbose') - - args = parser.parse_args() - - if (args.verbose): - log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG) - else: - log.basicConfig(format="%(levelname)s: %(message)s") - - if args.r < 1: - log.error("Max Round value should be greater than 0") - - # Create 0..255 bit array - rc = ba.bitarray(256) - rc.setall(0) - - r = ba.bitarray('10000000') - rc[0] = True # t%255 == 0 -> 1 - for i in range(1, 256): - # Update from t=1 to t=255 - r_d = ba.bitarray('0') + r - if r_d[8]: - #Flip 0,4,5,6 - r = r_d[0:8] ^ ba.bitarray('10001110') - else: - r = r_d[0:8] - - rc[i] = r[0] - - ## Print rc - print(rc) - - ## Round - - rcs = [] # Each entry represent the round - for rnd in range(0, args.r): - # Let RC=0 - rndconst = ba.bitarray(64) - rndconst.setall(0) - # for j [0 .. L] RC[2**j-1] = rc(j+7*rnd) - for j in range(0, 7): #0 to 6 - rndconst[2**j - 1] = rc[(j + 7 * rnd) % 255] - print("64'h{}, // Round {}".format(rndhex(rndconst), rnd)) - - -def rndhex(bit) -> str: - return bit[::-1].tobytes().hex() - - -if __name__ == "__main__": - main() diff --git a/vendor/lowrisc_ip/ip/prim/util/secded_gen.py b/vendor/lowrisc_ip/ip/prim/util/secded_gen.py deleted file mode 100755 index 53142b22..00000000 --- a/vendor/lowrisc_ip/ip/prim/util/secded_gen.py +++ /dev/null @@ -1,393 +0,0 @@ -#!/usr/bin/env python3 -# Copyright lowRISC contributors. -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 -r"""SECDED encoder/decoder generator - -Current version doesn't optimize Fan-In. It uses Hsiao code (modified version -of Hamming code + parity). Please refer https://arxiv.org/pdf/0803.1217.pdf -""" - -# TODO: Add FPV assertions in the encoder/decoder module - -import argparse -import itertools -import logging as log -import math -import os -import random -import sys -import time -from pathlib import PurePath - -COPYRIGHT = """// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 -// -""" -CODE_OPTIONS = ['hsiao', 'hamming'] - -def min_paritysize(k): - # SECDED --> Hamming distance 'd': 4 - # 2^(m-1) should cover (m+k) - for m in range(2, 10): - if 2**m >= (k + m + 1): - return m + 1 - return -1 - - -def ideal_fanin(k, m): - """Compute Ideal Max Fanin of any bit in the ecc codes.""" - fanin = 0 - needed = k - for select in range(3, m + 1, 2): - combinations = list(itertools.combinations(range(m), select)) - if len(combinations) <= needed: - fanin += int(math.ceil(float(len(combinations) * select) / m)) - needed -= len(combinations) - else: - fanin += int(math.ceil(float(needed * select) / m)) - needed = 0 - if not needed: - break - return fanin - - -def calc_fanin(width, codes): - """Sum the ones in a column""" - fanins = [0] * width - log.info("Calc Code: {}".format(codes)) - for i in codes: - for e in i: - fanins[e] += 1 - - return fanins - - -def print_comb(n, - k, - m, - cur_m, - codes, - start_cnt, - max_width=100, - prefix="", - first_indent=0): - """Print XOR comb. - - @param[max_width] Maximum Width of str - @param[prefix] The prepend string at the first line - @param[first_indent] The number of character that indented at the first line - e.g. first_indent := 2 - {prefix}in[nn] ... - ^ in[nn] ^ in[nn] - - result: - {prefix}in[nn] ^ ... in[nn] - ^ in[nn] ^ ... in[nn]; - """ - outstr = "" - line = prefix - prepend_len = len(prefix) - cnt = start_cnt - first = True - for j in range(k): - temp_str = "" - if cur_m in codes[j]: - if not first: - temp_str += " ^" - if first: - first = False - temp_str += " in[%d]" % (j) - temp_len = len(temp_str) - - if len(line) + temp_len > max_width: - outstr += line + "\n" - line = ' ' * (prepend_len - first_indent) + temp_str - else: - line += temp_str - outstr += line + ";\n" - return outstr - - -def print_enc(n, k, m, codes): - outstr = "" - for i in range(k): - outstr += " assign out[%d] = in[%d] ;\n" % (i, i) - - for i in range(m): - # Print parity computation - outstr += print_comb(n, k, m, i, codes, 0, 100, - " assign out[%d] =" % (i + k), 2) - return outstr - - -def calc_syndrome(code): - log.info("in syncrome {}".format(code)) - return sum(map((lambda x: 2**x), code)) - -# return whether an integer is a power of 2 -def is_pow2(n): - return (n & (n-1) == 0) and n != 0 - -def is_odd(n): - return (n % 2) > 0 - -# k = data bits -# m = parity bits -# generate hsiao code -def hsiao_code(k, m): - # using itertools combinations, generate odd number of 1 in a row - - required_row = k # k rows are needed, decreasing everytime when it acquite - - fanin_ideal = ideal_fanin(k, m) - log.info("Ideal Fan-In value: %d" % fanin_ideal) - - # Each entry represents a row in below parity matrix - # Entry is tuple and the value inside is the position of ones - # e.g. (0,1,2) in m:=7 - # row -> [1 1 1 0 0 0 0] - codes = [] - - ## Find code matrix ======================================================= - # This is main part to find the parity matrix. - # For example, find SECDED for 4bit message is to find 4x4 matrix as below - # | 1 0 0 0 x x x x | - # | 0 1 0 0 x x x x | - # | 0 0 1 0 x x x x | - # | 0 0 0 1 x x x x | - # Then message _k_ X matrix_code ==> original message with parity - # - # Make a row to have even number of 1 including the I matrix. - # This helps to calculate the syndrom at the decoding stage. - # To reduce the max fan-in, Starting with smallest number 3. - # the number means the number of one in a row. - # Small number of ones means smaller fan-in overall. - - for step in range(3, m + 1, 2): - # starting from 3 as I matrix represents data - # Increased by 2 as number of 1 should be even in a row (odd excluding I) - - # get the list of combinations [0, .., m-1] with `step` - # e.g. step := 3 ==> [(0,1,2), (0,1,3), ... ] - candidate = list(itertools.combinations(range(m), step)) - - if len(candidate) <= required_row: - # we need more round use all of them - codes.extend(candidate) - required_row -= len(candidate) - else: - ## Find optimized fan-in ========================================== - - # Calculate each row fan-in with current - fanins = calc_fanin(m, codes) - while required_row != 0: - # Let's shuffle - # Shuffling makes the sequence randomized --> it reduces the - # fanin as the code takes randomly at the end of the round - - # TODO: There should be a clever way to find the subset without - # random retrying. - # Suggested this algorithm - # https://en.wikipedia.org/wiki/Assignment_problem - random.shuffle(candidate) - - # Take a subset - subset = candidate[0:required_row] - - subset_fanins = calc_fanin(m, subset) - # Check if it exceeds Ideal Fan-In - ideal = True - for i in range(m): - if fanins[i] + subset_fanins[i] > fanin_ideal: - # Exceeded. Retry - ideal = False - break - - if ideal: - required_row = 0 - - # Append to the code matrix - codes.extend(subset) - - if required_row == 0: - # Found everything! - break - - log.info("Hsiao codes {}".format(codes)) - return codes - -# n = total bits -# k = data bits -# m = parity bits -# generate hamming code -def hamming_code(n, k, m): - - # construct a list of code tuples. - # Tuple corresponds to each bit position and shows which parity bit it participates in - # Only the data bits are shown, the parity bits are not. - codes = [] - for pos in range(1, n+1): - # this is a valid parity bit position or the final parity bit - if (is_pow2(pos) or pos == n): - continue - else: - code = () - for p in range(m): - - # this is the starting parity position - parity_pos = 2**p - - # back-track to the closest parity bit multiple and see if it is even or odd - # If even, we are in the skip phase, do not include - # If odd, we are in the include phase - parity_chk = int((pos - (pos % parity_pos)) / parity_pos) - log.debug("At position {} parity value {}, {}" \ - .format(pos, parity_pos, parity_chk)) - - # valid for inclusion or final parity bit that includes everything - if is_odd(parity_chk) or p == m-1: - code = code + (p,) - log.info("add {} to tuple {}".format(p, code)) - - codes.append(code) - - log.info("Hamming codes {}".format(codes)) - return codes - - -def print_dec(n, k, m, codes): - outstr = "" - outstr += " logic single_error;\n" - outstr += "\n" - outstr += " // Syndrome calculation\n" - for i in range(m): - # Print combination - outstr += print_comb(n, k, m, i, codes, 1, 100, - " assign syndrome_o[%d] = in[%d] ^" % (i, k + i), - len(" in[%d] ^" % (k + i)) + 2) - - outstr += "\n" - outstr += " // Corrected output calculation\n" - for i in range(k): - synd_v = calc_syndrome(codes[i]) - outstr += " assign d_o[%d] = (syndrome_o == %d'h%x) ^ in[%d];\n" % ( - i, m, calc_syndrome(codes[i]), i) - outstr += "\n" - outstr += " // err_o calc. bit0: single error, bit1: double error\n" - outstr += " assign single_error = ^syndrome_o;\n" - outstr += " assign err_o[0] = single_error;\n" - outstr += " assign err_o[1] = ~single_error & (|syndrome_o);\n" - return outstr - - -def main(): - parser = argparse.ArgumentParser( - prog="secded_gen", - description='''This tool generates Single Error Correction Double Error - Detection(SECDED) encoder and decoder modules in SystemVerilog. - ''') - parser.add_argument( - '-m', - type=int, - default=7, - help= - 'parity length. If fan-in is too big, increasing m helps. (default: %(default)s)' - ) - parser.add_argument( - '-k', - type=int, - default=32, - help= - 'code length. Minimum \'m\' is calculated by the tool (default: %(default)s)' - ) - parser.add_argument( - '-c', - default='hsiao', - help= - 'ECC code used. Options: hsiao / hamming (default: %(default)s)' - ) - parser.add_argument( - '--outdir', - default='../rtl', - help= - 'output directory. The output file will be named `prim_secded___enc/dec.sv` (default: %(default)s)' - ) - parser.add_argument('--verbose', '-v', action='store_true', help='Verbose') - - args = parser.parse_args() - - if (args.verbose): - log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG) - else: - log.basicConfig(format="%(levelname)s: %(message)s") - - # Error checking - if (args.k <= 1 or args.k > 120): - log.error("Current tool doesn't support the value k (%d)", args.k) - k = args.k - - if (args.m <= 1 or args.m > 20): - log.error("Current tool doesn't support the value m (%d)", args.m) - - # Calculate 'm' (parity size) - min_m = min_paritysize(k) - if (args.m < min_m): - log.warning("given \'m\' argument is smaller than minimum requirement " + - "using calculated minimum") - m = min_m - else: - m = args.m - - n = m + k - log.info("n(%d), k(%d), m(%d)", n, k, m) - - random.seed(time.time()) - - # Error check code selection - codes = [] - name = '' - if (args.c == 'hsiao'): - codes = hsiao_code(k, m) - elif (args.c == 'hamming'): - name = '_hamming' - codes = hamming_code(n, k, m) - else: - log.error("Invalid code {} selected, use one of {}".format(args.c, CODE_OPTIONS)) - return - - # Print Encoder - enc_out = print_enc(n, k, m, codes) - #log.info(enc_out) - - module_name = "prim_secded%s_%d_%d" % (name, n, k) - - with open(args.outdir + "/" + module_name + "_enc.sv", "w") as f: - f.write(COPYRIGHT) - f.write("// SECDED Encoder generated by secded_gen.py\n\n") - - f.write("module " + module_name + "_enc (\n") - f.write(" input [%d:0] in,\n" % (k - 1)) - f.write(" output logic [%d:0] out\n" % (n - 1)) - f.write(");\n\n") - f.write(enc_out) - f.write("endmodule\n\n") - - dec_out = print_dec(n, k, m, codes) - - with open(args.outdir + "/" + module_name + "_dec.sv", "w") as f: - f.write(COPYRIGHT) - f.write("// SECDED Decoder generated by secded_gen.py\n\n") - - f.write("module " + module_name + "_dec (\n") - f.write(" input [%d:0] in,\n" % (n - 1)) - f.write(" output logic [%d:0] d_o,\n" % (k - 1)) - f.write(" output logic [%d:0] syndrome_o,\n" % (m - 1)) - f.write(" output logic [1:0] err_o\n") - f.write(");\n\n") - f.write(dec_out) - f.write("endmodule\n\n") - -if __name__ == "__main__": - main() diff --git a/vendor/lowrisc_ip/ip/prim/util/sparse-fsm-encode.py b/vendor/lowrisc_ip/ip/prim/util/sparse-fsm-encode.py deleted file mode 100755 index 7507fb8d..00000000 --- a/vendor/lowrisc_ip/ip/prim/util/sparse-fsm-encode.py +++ /dev/null @@ -1,334 +0,0 @@ -#!/usr/bin/env python3 -# Copyright lowRISC contributors. -# Licensed under the Apache License, Version 2.0, see LICENSE for details. -# SPDX-License-Identifier: Apache-2.0 -r"""This script generates sparse FSM encodings that fulfill a minimum -Hamming distance requirement. It uses a heuristic that incrementally -draws random state encodings until a solution has been found. - -Depending on the parameterization, the script may not find a solution right -away. In such cases, the script should be rerun after tweaking the d/m/n -parameters. E.g. in order to increase the chances for success, the state -space can be made more sparse by increasing n, or the Hamming distance -threshold d can be lowered. - -Note however that the Hamming distance d should be set to 3 at minimum. -It is recommended to set this value to 4-5 for security critical FSMs. - -The custom seed s can be used to make subsequent runs of the script -deterministic. If not specified, the script randomly picks a seed. - -""" -import argparse -import logging -import math -import random -import textwrap -import sys - -MAX_DRAWS = 10000 -MAX_RESTARTS = 10000 - - -SV_INSTRUCTIONS = """ ------------------------------------------------------- -| COPY PASTE THE CODE TEMPLATE BELOW INTO YOUR RTL | -| IMPLEMENTATION, INLUDING THE COMMENT AND PRIM_FLOP | -| IN ORDER TO EASE AUDITABILITY AND REPRODUCIBILITY. | ------------------------------------------------------- -""" - -C_INSTRUCTIONS = """ ------------------------------------------------- -| COPY PASTE THE CODE TEMPLATE BELOW INTO YOUR | -| C HEADER, INLUDING THE COMMENT IN ORDER TO | -| EASE AUDITABILITY AND REPRODUCIBILITY. | ------------------------------------------------- -""" - -RUST_INSTRUCTIONS = """ ------------------------------------------------- -| COPY PASTE THE CODE TEMPLATE BELOW INTO YOUR | -| RUST FILE, INLUDING THE COMMENT IN ORDER TO | -| EASE AUDITABILITY AND REPRODUCIBILITY. | ------------------------------------------------- -""" - - -# TODO: Consolidate the subfunctions below in a shared utility package. -def _wrapped_docstring(): - '''Return a text-wrapped version of the module docstring''' - paras = [] - para = [] - for line in __doc__.strip().split('\n'): - line = line.strip() - if not line: - if para: - paras.append('\n'.join(para)) - para = [] - else: - para.append(line) - if para: - paras.append('\n'.join(para)) - - return '\n\n'.join(textwrap.fill(p) for p in paras) - - -def _hist_to_bars(hist, m): - '''Convert histogramm list into ASCII bar plot''' - bars = [] - for i, j in enumerate(hist): - bar_prefix = "{:2}: ".format(i) - spaces = len(str(m)) - len(bar_prefix) - hist_bar = bar_prefix + (" " * spaces) - for k in range(j * 20 // max(hist)): - hist_bar += "|" - hist_bar += " ({:.2f}%)".format(100.0 * j / sum(hist)) if j else "--" - bars += [hist_bar] - return bars - - -def main(): - logging.basicConfig(level=logging.INFO, - format="%(asctime)s - %(message)s", - datefmt="%Y-%m-%d %H:%M") - - parser = argparse.ArgumentParser( - prog="sparse-fsm-encode", - description=_wrapped_docstring(), - formatter_class=argparse.RawDescriptionHelpFormatter) - parser.add_argument('-d', - type=int, - default=5, - metavar='', - help='Minimum Hamming distance between encoded states.') - parser.add_argument('-m', - type=int, - default=7, - metavar='<#states>', - help='Number of states to encode.') - parser.add_argument('-n', - type=int, - default=10, - metavar='<#nbits>', - help='Encoding length [bit].') - parser.add_argument('-s', - type=int, - metavar='', - help='Custom seed for RNG.') - parser.add_argument('--language', - choices=['sv', 'c', 'rust'], - default='sv', - help='Choose the language of the generated enum.') - - args = parser.parse_args() - - if args.language in ['c', 'rust']: - if args.n not in [8, 16, 32]: - logging.error("When using C or Rust, widths must be a power-of-two " - "at least a byte (8 bits) wide. You chose %d." % (args.n,)) - sys.exit(1) - - if args.m > 2**args.n: - logging.error( - 'Statespace 2^%d not large enough to accommodate %d states.' % - (args.n, args.m)) - sys.exit(1) - - if args.d >= args.n: - logging.error( - 'State is only %d bits wide, which is not enough to fulfill a ' - 'minimum Hamming distance constraint of %d. ' % - (args.n, args.d)) - sys.exit(1) - - if args.d <= 0: - logging.error( - 'Hamming distance must be > 0.') - sys.exit(1) - - if args.d < 3: - logging.warning( - 'A value of 4-5 is recommended for the minimum Hamming distance ' - 'constraint. At a minimum, this should be set to 3.') - - # If no seed has been provided, we choose a seed and print it - # into the generated output later on such that this run can be - # reproduced. - if args.s is None: - random.seed() - args.s = random.getrandbits(32) - - random.seed(args.s) - - # This is a heuristic that opportunistically draws random - # state encodings and check whether they fulfill the minimum - # Hamming distance constraint. - # Other solutions that use a brute-force approach would be - # possible as well (see e.g. https://math.stackexchange.com/ - # questions/891528/generating-a-binary-code-with-maximized-hamming-distance). - # However, due to the sparse nature of the state space, this - # probabilistic heuristic works pretty well for most practical - # cases, and it scales favorably to large N. - num_draws = 0 - num_restarts = 0 - encodings = [random.getrandbits(args.n)] - while len(encodings) < args.m: - # if we iterate for too long, start over. - if num_draws >= MAX_DRAWS: - num_draws = 0 - num_restarts += 1 - encodings = [random.getrandbits(args.n)] - # if we restarted for too many times, abort. - if num_restarts >= MAX_RESTARTS: - logging.error( - 'Did not find a solution after restarting {} times. This is ' - 'an indicator that not many (or even no) solutions exist for ' - 'the current parameterization. Rerun the script and/or adjust ' - 'the d/m/n parameters. E.g. make the state space more sparse by ' - 'increasing n, or lower the minimum Hamming distance threshold d.' - .format(num_restarts)) - sys.exit(1) - num_draws += 1 - # draw a candidate and check whether it fulfills the minimum - # distance requirement with respect to other encodings. - c = random.getrandbits(args.n) - # disallow all-zero and all-one states - pop_cnt = bin(c).count('1') - if pop_cnt < args.n and pop_cnt > 0: - for k in encodings: - # disallow candidates that are the complement of other states - if c == ~k: - break - # disallow candidates that are too close to other states - if bin(c ^ k).count('1') < args.d: - break - else: - encodings.append(c) - - # build Hamming distance histogram - minimum = args.n - maximum = 0 - hist = [0] * (args.n + 1) - for i, j in enumerate(encodings): - if i < len(encodings) - 1: - for k in encodings[i + 1:]: - dist = bin(j ^ k).count('1') - hist[dist] += 1 - minimum = min(dist, minimum) - maximum = max(dist, maximum) - - bars = _hist_to_bars(hist, args.m) - - if args.language == "sv": - print(SV_INSTRUCTIONS) - print( - "// Encoding generated with:\n" - "// $ ./sparse-fsm-encode.py -d {} -m {} -n {} \\\n" - "// -s {} --language=sv\n" - "//\n" - "// Hamming distance histogram:\n" - "//".format(args.d, args.m, args.n, args.s)) - for bar in _hist_to_bars(hist, args.m): - print('// ' + bar) - print("//\n" - "// Minimum Hamming distance: {}\n" - "// Maximum Hamming distance: {}\n" - "//\n" - "localparam int StateWidth = {};\n" - "typedef enum logic [StateWidth-1:0] {{".format(minimum, maximum, args.n)) - fmt_str = " State{0:} {1:}= {2:}'b{3:0" + str(args.n) + "b}" - state_str = "" - for j, k in enumerate(encodings): - pad = "" - for i in range(len(str(args.m)) - len(str(j))): - pad += " " - comma = "," if j < len(encodings) - 1 else "" - print(fmt_str.format(j, pad, args.n, k) + comma) - state_str += " State{}: ;\n".format(j) - - # print FSM template - print('''}} state_e; - -state_e state_d, state_q; - -always_comb begin : p_fsm - // Default assignments - state_d = state_q; - - unique case (state_q) -{} default: ; // Consider triggering an error or alert in this case. - endcase -end - -// This primitive is used to place a size-only constraint on the -// flops in order to prevent FSM state encoding optimizations. -logic [StateWidth-1:0] state_raw_q; -assign state_q = state_e'(state_raw_q); -prim_flop #( - .Width(StateWidth), - .ResetValue(StateWidth'(State0)) -) u_state_regs ( - .clk_i, - .rst_ni, - .d_i ( state_d ), - .q_o ( state_raw_q ) -); -'''.format(state_str)) - - elif args.language == "c": - print(C_INSTRUCTIONS) - print("/*\n" - " * Encoding generated with\n" - " * $ ./sparse-fsm-encode.py -d {} -m {} -n {} \\\n" - " * -s {} --language=c\n" - " *\n" - " * Hamming distance histogram:\n" - " *".format(args.d, args.m, args.n, args.s)) - for hist_bar in bars: - print(" * " + hist_bar) - print(" *\n" - " * Minimum Hamming distance: {}\n" - " * Maximum Hamming distance: {}\n" - " */\n" - "typedef enum my_state {{".format(minimum, maximum)) - fmt_str = " kMyState{0:} {1:}= 0x{3:0" + str(math.ceil(args.n / 4)) + "x}" - for j, k in enumerate(encodings): - pad = "" - for i in range(len(str(args.m)) - len(str(j))): - pad += " " - print(fmt_str.format(j, pad, args.n, k) + ",") - - # print FSM template - print("} my_state_t;") - elif args.language == 'rust': - print(RUST_INSTRUCTIONS) - print("///```text\n" - "/// Encoding generated with\n" - "/// $ ./sparse-fsm-encode.py -d {} -m {} -n {} \\\n" - "/// -s {} --language=rust\n" - "///\n" - "/// Hamming distance histogram:\n" - "///".format(args.d, args.m, args.n, args.s)) - for hist_bar in bars: - print("/// " + hist_bar) - print("///\n" - "/// Minimum Hamming distance: {}\n" - "/// Maximum Hamming distance: {}\n" - "///```\n" - "#[derive(Clone,Copy,Eq,PartialEq,Ord,ParitalOrd,Hash,Debug)]\n" - "#[repr(transparent)]\n" - "struct MyState(u{});\n" - "\n" - "impl MyState {{".format(minimum, maximum, args.n)) - fmt_str = " const MY_STATE{0:}: MyState {1:}= MyState(0x{3:0" + str(math.ceil(args.n / 4)) + "x})" - for j, k in enumerate(encodings): - pad = "" - for i in range(len(str(args.m)) - len(str(j))): - pad += " " - print(fmt_str.format(j, pad, args.n, k) + ";") - print("}") - - -if __name__ == "__main__": - main() diff --git a/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_gating.waiver b/vendor/lowrisc_ip/ip/prim_generic/lint/prim_generic_clock_gating.waiver index 8cc0fa55..b73c7e49 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 @@ -7,3 +7,5 @@ waive -rules LATCH -location {prim_generic_clock_gating.sv} -rege -comment "clock gating cell creates a latch" waive -rules COMBO_NBA -location {prim_generic_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} \ + -comment "parameter unused but required to maintain uniform interface" 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 f67d3394..142bc8db 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_buf.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_buf.core @@ -29,7 +29,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: 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 e51f32a4..8c042abc 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 @@ -29,7 +29,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: 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 6a5423d5..d083e867 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 @@ -31,7 +31,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: 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 b606644e..19920df8 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 @@ -34,7 +34,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: 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 f84fbfc7..6e8ed693 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 @@ -33,7 +33,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: 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 5dbbeabb..9077b684 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flash.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flash.core @@ -36,7 +36,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: 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 e44b7b4c..6209a7bc 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flop.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flop.core @@ -29,7 +29,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: diff --git a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flop_2sync.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flop_2sync.core index d9c3b932..77e42dbc 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flop_2sync.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flop_2sync.core @@ -29,7 +29,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: 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 aca1790f..d15c759d 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 @@ -33,7 +33,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: 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 7e96d4b9..5ea59f79 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 @@ -34,7 +34,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: 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 0db36d51..302a86cc 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 @@ -34,7 +34,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: 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 aee093ab..9f1b671c 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_rom.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_rom.core @@ -34,7 +34,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: 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 36c8f91c..3155941b 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 @@ -31,7 +31,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash.sv index 12d21a6c..8483fbdc 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash.sv @@ -14,7 +14,7 @@ module prim_generic_flash #( parameter int WordsPerPage = 256,// words per page parameter int DataWidth = 32, // bits per word parameter int MetaDataWidth = 12, // metadata such as ECC - parameter int TestModeWidth = 2 + parameter int TestModeWidth = 4 ) ( input clk_i, input rst_ni, @@ -26,20 +26,30 @@ module prim_generic_flash #( input tdi_i, input tms_i, output logic tdo_o, - input bist_enable_i, - input scanmode_i, + input lc_ctrl_pkg::lc_tx_t bist_enable_i, + input lc_ctrl_pkg::lc_tx_t scanmode_i, + input scan_en_i, input scan_rst_ni, input flash_power_ready_h_i, input flash_power_down_h_i, input [TestModeWidth-1:0] flash_test_mode_a_i, input flash_test_voltage_h_i, + output logic flash_err_o, + output logic flash_alert_po, + output logic flash_alert_no, + input flash_alert_ack_i, + input flash_alert_trig_i, input tlul_pkg::tl_h2d_t tl_i, - output tlul_pkg::tl_d2h_t tl_o + output tlul_pkg::tl_d2h_t tl_o, + input devmode_i ); localparam int CfgRegs = 21; localparam int CfgAddrWidth = $clog2(CfgRegs); + logic unused_devmode; + assign unused_devmode = devmode_i; + // convert this into a tlul write later logic init; assign init = 1'b1; @@ -89,7 +99,8 @@ module prim_generic_flash #( ); end - logic unused_scanmode; + lc_ctrl_pkg::lc_tx_t unused_scanmode; + logic unused_scan_en; logic unused_scan_rst_n; logic [TestModeWidth-1:0] unused_flash_test_mode; logic unused_flash_test_voltage; @@ -98,6 +109,7 @@ module prim_generic_flash #( logic unused_tms; assign unused_scanmode = scanmode_i; + assign unused_scan_en = scan_en_i; assign unused_scan_rst_n = scan_rst_ni; assign unused_flash_test_mode = flash_test_mode_a_i; assign unused_flash_test_voltage = flash_test_voltage_h_i; @@ -126,12 +138,13 @@ module prim_generic_flash #( .SramAw(CfgAddrWidth), .SramDw(32), .Outstanding(2), - .ErrOnWrite(1) + .ErrOnWrite(0) ) u_cfg ( .clk_i, .rst_ni, .tl_i, .tl_o, + .en_ifetch_i(tlul_pkg::InstrDis), .req_o(cfg_req), .gnt_i(1'b1), .we_o(cfg_we), @@ -156,7 +169,28 @@ module prim_generic_flash #( .rdata_o(cfg_rdata) ); - logic unused_bist_enable; + lc_ctrl_pkg::lc_tx_t unused_bist_enable; assign unused_bist_enable = bist_enable_i; + // open source model has no error response at the moment + assign flash_err_o = 1'b0; + + logic alerts_active; + assign alerts_active = flash_alert_po | ~flash_alert_no; + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + flash_alert_po <= 1'b0; + flash_alert_no <= 1'b1; + end else if (flash_alert_trig_i) begin + flash_alert_po <= 1'b1; + flash_alert_no <= 1'b0; + end else if (alerts_active && flash_alert_ack_i) begin + flash_alert_po <= 1'b0; + flash_alert_no <= 1'b1; + end + end + + + endmodule // prim_generic_flash diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash_bank.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash_bank.sv index 4f7ae452..05ea82c0 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 @@ -139,6 +139,7 @@ module prim_generic_flash_bank #( .wready_o(ack), .wdata_i (cmd_d), .depth_o (), + .full_o (), .rvalid_o(cmd_valid), .rready_i(pop_cmd), .rdata_o (cmd_q) diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_otp.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_otp.sv index 8710fd8e..149d6e7d 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_otp.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_otp.sv @@ -69,17 +69,18 @@ module prim_generic_otp ) u_tlul_adapter_sram ( .clk_i, .rst_ni, - .tl_i ( test_tl_i ), - .tl_o ( test_tl_o ), - .req_o ( tlul_req ), - .gnt_i ( tlul_req ), - .we_o ( tlul_wren ), - .addr_o ( tlul_addr ), - .wdata_o ( tlul_wdata ), - .wmask_o ( ), - .rdata_i ( tlul_rdata_q ), - .rvalid_i ( tlul_rvalid_q ), - .rerror_i ( '0 ) + .tl_i ( test_tl_i ), + .tl_o ( test_tl_o ), + .en_ifetch_i ( tlul_pkg::InstrDis ), + .req_o ( tlul_req ), + .gnt_i ( tlul_req ), + .we_o ( tlul_wren ), + .addr_o ( tlul_addr ), + .wdata_o ( tlul_wdata ), + .wmask_o ( ), + .rdata_i ( tlul_rdata_q ), + .rvalid_i ( tlul_rvalid_q ), + .rerror_i ( '0 ) ); always_ff @(posedge clk_i or negedge rst_ni) begin : p_tlul_testreg @@ -155,7 +156,7 @@ module prim_generic_otp state_d = state_q; ready_o = 1'b0; valid_d = 1'b0; - err_d = NoError; + err_d = err_q; req = 1'b0; wren = 1'b0; cnt_clr = 1'b0; @@ -164,6 +165,7 @@ module prim_generic_otp 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 @@ -179,10 +181,12 @@ module prim_generic_otp 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; @@ -280,7 +284,9 @@ module prim_generic_otp .MemInitFile (MemInitFile), .EnableECC (1'b1), .EnableInputPipeline (1), - .EnableOutputPipeline (1) + .EnableOutputPipeline (1), + // Use a standard Hamming ECC for OTP. + .HammingECC (1) ) u_prim_ram_1p_adv ( .clk_i, .rst_ni, 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 69ed5304..d1e24797 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_buf.core +++ b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_buf.core @@ -27,7 +27,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: 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 a94a86fb..7bd93e25 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 @@ -31,7 +31,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: 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 72058a63..1e1064fb 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 @@ -31,7 +31,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: 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 6f2dcb2a..0ea81cc9 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 @@ -31,7 +31,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: 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 ecd876b0..e37ee234 100644 --- a/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_flop.core +++ b/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_flop.core @@ -29,7 +29,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: 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 ce2cd7a1..5e6ff673 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 @@ -31,7 +31,6 @@ filesets: depend: # common waivers - lowrisc:lint:common - - lowrisc:lint:comportable targets: default: diff --git a/vendor/lowrisc_ip/lint/tools/ascentlint/ascentlint-config.tcl b/vendor/lowrisc_ip/lint/tools/ascentlint/ascentlint-config.tcl index 3e01524a..2d187511 100644 --- a/vendor/lowrisc_ip/lint/tools/ascentlint/ascentlint-config.tcl +++ b/vendor/lowrisc_ip/lint/tools/ascentlint/ascentlint-config.tcl @@ -7,3 +7,9 @@ set RI_INSTALL [file dirname [exec which ascentlint]] # source the policy file containing the lowrisc lint rules source "$RI_INSTALL/../Ascent/Lint/lib/policies/lowRISC/LRLR-v1.0.policy" + +# increase this from 8k (default) to 32k such that large arrays like +# regfiles can be analyzed and linted. +set ri_max_total_range_bits 32768 +set ri_max_single_range_bits 32768 + diff --git a/vendor/lowrisc_ip/lint/tools/ascentlint/common.waiver b/vendor/lowrisc_ip/lint/tools/ascentlint/common.waiver index 6276158c..d1502573 100644 --- a/vendor/lowrisc_ip/lint/tools/ascentlint/common.waiver +++ b/vendor/lowrisc_ip/lint/tools/ascentlint/common.waiver @@ -8,4 +8,5 @@ # similar exception list for rule NOT_READ) waive -rules {HIER_NET_NOT_READ HIER_BRANCH_NOT_READ} -regexp {unused_.*} waive -rules {HIER_NET_NOT_READ HIER_BRANCH_NOT_READ} -regexp {gen_.*\.unused_.*} +waive -rules {ONE_BRANCH} -regexp {unique case statement has only one branch} diff --git a/vendor/lowrisc_ip/lint/tools/ascentlint/parse-lint-report.py b/vendor/lowrisc_ip/lint/tools/ascentlint/parse-lint-report.py index b05884c9..21fe3928 100755 --- a/vendor/lowrisc_ip/lint/tools/ascentlint/parse-lint-report.py +++ b/vendor/lowrisc_ip/lint/tools/ascentlint/parse-lint-report.py @@ -32,38 +32,75 @@ def get_results(resdir): """ results = { "tool": "ascentlint", + "fusesoc-error": [], "errors": [], "warnings": [], "lint_errors": [], "lint_warnings": [], "lint_infos": [] } - try: - # check the log file for flow errors and warnings - with Path(resdir).joinpath('ascentlint.log').open() as f: - full_file = f.read() - err_warn_patterns = [("errors", r"^FlexNet Licensing error.*"), - ("errors", r"^Error: .*"), - ("errors", r"^ERROR.*"), - ("errors", r"^ ERR .*"), - ("warnings", r"^Warning: .*"), - # TODO: struct assignment labels within concatenation - # not supported. check with newer ascentlint version. - ("warnings", r"^ (?!WARN \[#39024\])WARN .*")] - extract_messages(full_file, err_warn_patterns, results) - except IOError as err: - results["errors"] += ["IOError: %s" % err] - try: - # check the report file for lint INFO, WARNING and ERRORs - with Path(resdir).joinpath('ascentlint.rpt').open() as f: - full_file = f.read() - err_warn_patterns = {("lint_errors", r"^E .*"), - ("lint_warnings", r"^W .*"), - ("lint_infos", r"^I .*")} - extract_messages(full_file, err_warn_patterns, results) - except IOError as err: - results["errors"] += ["IOError: %s" % err] + log_files = ['lint.log', + 'lint-ascentlint/ascentlint.log', + 'lint-ascentlint/ascentlint.rpt'] + log_file_contents = [] + # Open all log files + for name in log_files: + try: + with Path(resdir).joinpath(name).open() as f: + log_file_contents.append(f.read()) + except IOError as err: + results["errors"] += ["IOError: %s" % err] + + # Define warning/error patterns for each logfile + err_warn_patterns = [] + + # Patterns for lint.log + err_warn_patterns.append([ + # 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 ascentlint.log + err_warn_patterns.append([ + ("errors", r"^FlexNet Licensing error.*"), + ("errors", r"^Error: .*"), + ("errors", r"^ERROR.*"), + ("errors", r"^ ERR .*"), + ("warnings", r"^Warning: .*"), + # TODO: struct assignment labels within concatenation + # not supported. check with newer ascentlint version. + ("warnings", r"^ (?!WARN \[#39024\])WARN .*") + ]) + + # Patterns for ascentlint.rpt + err_warn_patterns.append([ + ("lint_errors", r"^E .*"), + ("lint_warnings", r"^W .*"), + ("lint_infos", r"^I .*") + ]) + + # Go parse the logs + for patterns, logs in zip(err_warn_patterns, log_file_contents): + extract_messages(logs, patterns, results) + + # If there are no errors or warnings, add the "fusesoc-error" field to + # "errors" (which will be reported as tooling errors). Remove the + # "fusesoc-error" field either way. + if not (results['errors'] or results['warnings']): + results['errors'] = results['fusesoc-error'] + del results['fusesoc-error'] return results diff --git a/vendor/lowrisc_ip/lint/tools/dvsim/ascentlint.hjson b/vendor/lowrisc_ip/lint/tools/dvsim/ascentlint.hjson index 632b91db..3ac71ada 100644 --- a/vendor/lowrisc_ip/lint/tools/dvsim/ascentlint.hjson +++ b/vendor/lowrisc_ip/lint/tools/dvsim/ascentlint.hjson @@ -6,6 +6,6 @@ // Ascentlint-specific results parsing script that is called after running lint report_cmd: "{lint_root}/tools/{tool}/parse-lint-report.py " - report_opts: ["--repdir={build_dir}/lint-{tool}", + report_opts: ["--repdir={build_dir}", "--outdir={build_dir}"] } diff --git a/vendor/lowrisc_ip/lint/tools/veriblelint/parse-lint-report.py b/vendor/lowrisc_ip/lint/tools/veriblelint/parse-lint-report.py index 2546b881..260403c1 100755 --- a/vendor/lowrisc_ip/lint/tools/veriblelint/parse-lint-report.py +++ b/vendor/lowrisc_ip/lint/tools/veriblelint/parse-lint-report.py @@ -32,6 +32,7 @@ def get_results(resdir): """ results = { "tool": "veriblelint", + "fusesoc-error": [], "errors": [], "warnings": [], "lint_errors": [], @@ -42,34 +43,47 @@ def get_results(resdir): # check the report file for lint INFO, WARNING and ERRORs with Path(resdir).joinpath('lint.log').open() as f: full_file = f.read() - err_warn_patterns = { - # The lint failed error can be ignored, since - # Fusesoc will always return this error if lint warnings have - # been found. We have a way of capturing the lint warnings - # explicitly in this parsing script, hence this error is redundant - # and we decided not to report it in the dashboard. - ("errors", - r"^(?!ERROR: Failed to run .* Lint failed)ERROR: .*"), - ("errors", r"^Error: .*"), - ("errors", r"^E .*"), - ("errors", r"^F .*"), - # TODO(https://github.com/olofk/edalize/issues/90): - # this is a workaround until we actually have native Edalize - # support for JasperGold and "formal" targets - ("warnings", - r"^(?!WARNING: Unknown item formal in section Target)WARNING: .*" - # TODO(https://github.com/lowRISC/ibex/issues/1033): - # remove once this has been fixed in Edalize or in the corefile. - r"^(?!WARNING: Unknown item symbiyosis in section Target)WARNING: .*" - ), - ("warnings", r"^Warning: .* "), - ("warnings", r"^W .*"), - ("lint_warnings", r"^.*\[Style:.*") - } - extract_messages(full_file, err_warn_patterns, results) except IOError as err: results["errors"] += ["IOError: %s" % err] + err_warn_patterns = [ + # 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 run ip:core:name:0.1 : Lint failed + # + # 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 run .*: Lint failed.*"), + ("errors", + r"^(?!ERROR: Failed to run .* Lint failed)ERROR: .*"), + ("errors", r"^.*Error: .*"), + ("errors", r"^E .*"), + ("errors", r"^F .*"), + ("errors", r".*: syntax error, rejected.*"), + # TODO(https://github.com/olofk/edalize/issues/90): + # this is a workaround until we actually have native Edalize + # support for JasperGold and "formal" targets + ("warnings", + r"^(?!WARNING: Unknown item formal in section Target)WARNING: .*"), + ("warnings", r"^.*Warning: .* "), + ("warnings", r"^W .*"), + ("lint_warnings", r"^.*\[Style:.*") + ] + extract_messages(full_file, err_warn_patterns, results) + + # If there are no errors or warnings, add the "fusesoc-error" field to + # "errors" (which will be reported as tooling errors). Remove the + # "fusesoc-error" field either way. + if not (results['errors'] or results['warnings']): + results['errors'] = results['fusesoc-error'] + del results['fusesoc-error'] + return results diff --git a/vendor/lowrisc_ip/lint/tools/verilator/parse-lint-report.py b/vendor/lowrisc_ip/lint/tools/verilator/parse-lint-report.py index 8dcadf62..48973c95 100755 --- a/vendor/lowrisc_ip/lint/tools/verilator/parse-lint-report.py +++ b/vendor/lowrisc_ip/lint/tools/verilator/parse-lint-report.py @@ -31,25 +31,30 @@ def extract_messages(str_buffer, patterns): def parse_lint_log(str_buffer): '''Parse error, warnings, and failed properties from the log file''' err_warn_patterns = { - # The lint failed error can be ignored, since - # Fusesoc will always return this error if lint warnings have - # been found. We have a way of capturing the lint warnings - # explicitly in this parsing script, hence this error is redundant - # and we decided not to report it in the dashboard. + # 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"), ("errors", r"^(?!ERROR: Failed to build .* 'make' exited with an error code)ERROR: .*"), ("errors", - # This is a redundant Verilator error that we ignore for the same reason as above. + # This is a redundant Verilator error that we ignore, since we + # already parse out each individual error. r"^(?!%Error: Exiting due to .* warning.*)%Error: .*"), # TODO(https://github.com/olofk/edalize/issues/90): # this is a workaround until we actually have native Edalize # support for JasperGold and "formal" targets ("warnings", - r"^(?!WARNING: Unknown item formal in section Target)WARNING: .*" - # TODO(https://github.com/lowRISC/ibex/issues/1033): - # remove once this has been fixed in Edalize or in the corefile. - r"^(?!WARNING: Unknown item symbiyosis in section Target)WARNING: .*" - ), + r"^(?!WARNING: Unknown item formal in section Target)WARNING: .*"), ("warnings", r"^%Warning: .* "), ("lint_errors", r"^%Error-.*"), ("lint_warnings", r"^%Warning-.*"), @@ -61,6 +66,7 @@ def get_results(logpath): '''Parse Lint log file and extract info to a dictionary''' results = { "tool": "verilator", + "fusesoc-error": [], "errors": [], "warnings": [], "lint_errors": [], @@ -74,6 +80,13 @@ def get_results(logpath): except IOError as err: results["errors"] += ["IOError: %s" % err] + # If there are no errors or warnings, add the "fusesoc-error" field to + # "errors" (which will be reported as tooling errors). Remove the + # "fusesoc-error" field either way. + if not (results['errors'] or results['warnings']): + results['errors'] = results['fusesoc-error'] + del results['fusesoc-error'] + return results diff --git a/vendor/lowrisc_ip/util/dvsim/Deploy.py b/vendor/lowrisc_ip/util/dvsim/Deploy.py index e43d8547..0d2b55a6 100644 --- a/vendor/lowrisc_ip/util/dvsim/Deploy.py +++ b/vendor/lowrisc_ip/util/dvsim/Deploy.py @@ -8,14 +8,20 @@ import pprint import random import re import shlex +import shutil import subprocess import sys -import time -from collections import OrderedDict +from datetime import datetime +from pathlib import Path from sim_utils import get_cov_summary_table from tabulate import tabulate -from utils import VERBOSE, find_and_substitute_wildcards, run_cmd +from utils import VERBOSE, find_and_substitute_wildcards, rm_path + + +class DeployError(Exception): + def __init__(self, msg): + self.msg = msg class Deploy(): @@ -23,41 +29,17 @@ class Deploy(): Abstraction for deploying builds and runs. """ - # Timer in hours, minutes and seconds. - hh = 0 - mm = 0 - ss = 0 - - # Maintain a list of dispatched items. - dispatch_counter = 0 - # Misc common deploy settings. - print_legend = True - print_interval = 5 - max_parallel = 16 max_odirs = 5 - # Max jobs dispatched in one go. - slot_limit = 20 # List of variable names that are to be treated as "list of commands". # This tells `construct_cmd` that these vars are lists that need to # be joined with '&&' instead of a space. cmds_list_vars = [] - def __self_str__(self): - if log.getLogger().isEnabledFor(VERBOSE): - return pprint.pformat(self.__dict__) - else: - ret = self.cmd - if self.sub != []: - ret += "\nSub:\n" + str(self.sub) - return ret - def __str__(self): - return self.__self_str__() - - def __repr__(self): - return self.__self_str__() + return (pprint.pformat(self.__dict__) + if log.getLogger().isEnabledFor(VERBOSE) else self.cmd) def __init__(self, sim_cfg): '''Initialize common class members.''' @@ -82,13 +64,17 @@ class Deploy(): # List of vars required to be exported to sub-shell self.exports = None - # Deploy sub commands - self.sub = [] + # A list of jobs on which this job depends + self.dependencies = [] + + # Indicates whether running this job requires all dependencies to pass. + # If this flag is set to False, any passing dependency will trigger + # this current job to run + self.needs_all_dependencies_passing = True # Process self.process = None self.log_fd = None - self.status = None # These are mandatory class attributes that need to be extracted and # set from the sim_cfg object. These are explicitly used to construct @@ -211,9 +197,6 @@ class Deploy(): if type(value) is str: value = value.strip() cmd += " " + attr + "=\"" + str(value) + "\"" - - # TODO: If not running locally, redirect stdout and err to the log file - # self.cmd += " > " + self.log + " 2>&1 &" return cmd def is_equivalent_job(self, item): @@ -269,7 +252,7 @@ class Deploy(): # If renew_odir flag is True - then move it. if self.renew_odir: self.odir_limiter(odir=self.odir) - os.system("mkdir -p " + self.odir) + os.makedirs(self.odir, exist_ok=True) # Dump all env variables for ease of debug. with open(self.odir + "/env_vars", "w", @@ -278,8 +261,7 @@ class Deploy(): for var in sorted(exports.keys()): f.write("{}={}\n".format(var, exports[var])) f.close() - os.system("ln -s " + self.odir + " " + self.sim_cfg.links['D'] + - '/' + self.odir_ln) + self._link_odir("D") f = open(self.log, "w", encoding="UTF-8", errors="surrogateescape") f.write("[Executing]:\n{}\n\n".format(self.cmd)) f.flush() @@ -290,164 +272,201 @@ class Deploy(): stderr=f, env=exports) self.log_fd = f - self.status = "D" - Deploy.dispatch_counter += 1 except IOError: - log.error('IO Error: See %s', self.log) if self.log_fd: self.log_fd.close() - self.status = "K" + raise DeployError('IO Error: See {}'.format(self.log)) - def odir_limiter(self, odir, max_odirs=-1): - '''Function to backup previously run output directory to maintain a - history of a limited number of output directories. It deletes the output - directory with the oldest timestamps, if the limit is reached. It returns - a list of directories that remain after deletion. - Arguments: - odir: The output directory to backup - max_odirs: Maximum output directories to maintain as history. + def odir_limiter(self, odir): + """Clean previous output directories. - Returns: - dirs: Space-separated list of directories that remain after deletion. - ''' - try: + When running jobs, we may want to maintain a limited history of + previous invocations. This method finds and deletes the output + directories at the base of input arg 'odir' with the oldest timestamps, + if that limit is reached. It returns a list of directories that + remain after deletion. + """ + + if os.path.exists(odir): # If output directory exists, back it up. - if os.path.exists(odir): - ts = run_cmd("date '+" + self.sim_cfg.ts_format + "' -d \"" + - "$(stat -c '%y' " + odir + ")\"") - os.system('mv ' + odir + " " + odir + "_" + ts) - except IOError: - log.error('Failed to back up existing output directory %s', odir) + ts = datetime.fromtimestamp(os.stat(odir).st_ctime) + ts = ts.strftime(self.sim_cfg.ts_format) + shutil.move(odir, odir + "_" + ts) + + # Get list of past output directories sorted by creation time. + pdir = Path(odir).resolve().parent + if not pdir.exists(): + return [] + + dirs = sorted([old for old in pdir.iterdir() if old.is_dir()], + key=os.path.getctime, + reverse=True) + + for old in dirs[self.max_odirs - 1:]: + rm_path(old) + + return dirs[0:self.max_odirs - 2] + + def _test_passed(self): + """Determine the outcome of the job (P/F if it ran to completion). + + Return True if the job passed, False otherwise. This is called by + poll() just after the job finishes. + + """ + def log_fail_msg(msg): + '''Logs the fail msg to the final report.''' + self.fail_msg += msg + log.log(VERBOSE, msg) + + def _find_patterns(patterns, line): + '''Helper function that returns true if all or any of the given + patterns is found, else False.''' + + assert patterns + for pattern in patterns: + match = re.search(r"{}".format(pattern), line) + if match: + return pattern + return None + + def _get_n_lines(pos, num): + "Helper function that returns next N lines starting at pos index." + + return ''.join(lines[pos:pos + num - 1]).strip() + + if self.dry_run: + return True + + # Only one fail pattern needs to be seen. + failed = False + chk_failed = bool(self.fail_patterns) + + # All pass patterns need to be seen, so we replicate the list and remove + # patterns as we encounter them. + pass_patterns = self.pass_patterns.copy() + chk_passed = bool(pass_patterns) and (self.process.returncode == 0) - dirs = "" - # Delete older directories. try: - pdir = os.path.realpath(odir + "/..") - # Fatal out if pdir got set to root. - if pdir == "/": - log.fatal( - "Something went wrong while processing \"%s\": odir = \"%s\"", - self.name, odir) - sys.exit(1) + with open(self.log, "r", encoding="UTF-8") as f: + lines = f.readlines() + except OSError as e: + log_fail_msg("Error opening file {!r}:\n{}".format(self.log, e)) + return False - if os.path.exists(pdir): - find_cmd = "find " + pdir + " -mindepth 1 -maxdepth 1 -type d " - dirs = run_cmd(find_cmd) - dirs = dirs.replace('\n', ' ') - list_dirs = dirs.split() - num_dirs = len(list_dirs) - if max_odirs == -1: - max_odirs = self.max_odirs - num_rm_dirs = num_dirs - max_odirs - if num_rm_dirs > -1: - rm_dirs = run_cmd(find_cmd + - "-printf '%T+ %p\n' | sort | head -n " + - str(num_rm_dirs + 1) + - " | awk '{print $2}'") - rm_dirs = rm_dirs.replace('\n', ' ') - dirs = dirs.replace(rm_dirs, "") - os.system("/bin/rm -rf " + rm_dirs) - except IOError: - log.error("Failed to delete old run directories!") - return dirs + if chk_failed or chk_passed: + for cnt, line in enumerate(lines): + if chk_failed: + if _find_patterns(self.fail_patterns, line) is not None: + # Print 4 additional lines to help debug more easily. + log_fail_msg("```\n{}\n```\n".format( + _get_n_lines(cnt, 5))) + failed = True + chk_failed = False + chk_passed = False - def set_status(self): - self.status = 'P' - if self.dry_run is False: - seen_fail_pattern = False - for fail_pattern in self.fail_patterns: - # Return error message with the following 4 lines. - grep_cmd = "grep -m 1 -A 4 -E \'" + fail_pattern + "\' " + self.log - (status, rslt) = subprocess.getstatusoutput(grep_cmd) - if rslt: - msg = "```\n{}\n```\n".format(rslt) - self.fail_msg += msg - log.log(VERBOSE, msg) - self.status = 'F' - seen_fail_pattern = True - break + if chk_passed: + pattern = _find_patterns(pass_patterns, line) + if pattern is not None: + pass_patterns.remove(pattern) + chk_passed = bool(pass_patterns) - # If fail patterns were not encountered, but the job returned with non-zero 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.process.returncode != 0 and not seen_fail_pattern: - msg = "Last 10 lines of the log:
\n" - self.fail_msg += msg - log.log(VERBOSE, msg) - get_fail_msg_cmd = "tail -n 10 " + self.log - msg = run_cmd(get_fail_msg_cmd) - msg = "```\n{}\n```\n".format(msg) - self.fail_msg += msg - log.log(VERBOSE, msg) - self.status = "F" + # If failed, then nothing else to do. Just return. + if failed: + return False - # Return if status is fail - no need to look for pass patterns. - if self.status == 'F': - return + # If no fail patterns were seen, but the job returned with non-zero + # 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.process.returncode != 0: + msg = ''.join(lines[-10:]).strip() + log_fail_msg("Process returned non-zero exit code. " + "Last 10 lines:\n```\n{}\n```\n".format(msg)) + return False - # If fail patterns were not found, ensure pass patterns indeed were. - for pass_pattern in self.pass_patterns: - grep_cmd = "grep -c -m 1 -E \'" + pass_pattern + "\' " + self.log - (status, rslt) = subprocess.getstatusoutput(grep_cmd) - if rslt == "0": - msg = "Pass pattern \"{}\" not found.
\n".format( - pass_pattern) - self.fail_msg += msg - log.log(VERBOSE, msg) - self.status = 'F' - break + # Ensure all pass patterns were seen. + if chk_passed: + msg = ''.join(lines[-10:]).strip() + log_fail_msg("One or more pass patterns not found:\n{}\n" + "Last 10 lines:\n```\n{}\n```\n".format( + pass_patterns, msg)) + return False - # Recursively set sub-item's status if parent item fails - def set_sub_status(self, status): - for sub_item in self.sub: - sub_item.status = status - sub_item.set_sub_status(status) + return True - def link_odir(self): - if self.status == '.': - log.error("Method unexpectedly called!") - else: - old_link = self.sim_cfg.links['D'] + "/" + self.odir_ln - new_link = self.sim_cfg.links[self.status] + "/" + self.odir_ln - cmd = "ln -s " + self.odir + " " + new_link + "; " - cmd += "rm " + old_link - if os.system(cmd): - log.error("Cmd \"%s\" could not be run", cmd) + def _link_odir(self, status): + '''Soft-links the job's directory based on job's status, into + dispatched, running, passed, failed or killed directories in the + scratch area.''' - def get_status(self): - if self.status != "D": - return - if self.process.poll() is not None: - self.log_fd.close() - self.set_status() + dest = Path(self.sim_cfg.links[status], self.odir_ln) - log.debug("Item %s has completed execution: %s", self.name, - self.status) - Deploy.dispatch_counter -= 1 - self.link_odir() - del self.process + # If dest exists, then atomically remove it and link the odir again. + while True: + try: + os.symlink(self.odir, dest) + break + except FileExistsError: + rm_path(dest) + + # Delete the symlink from dispatched directory if it exists. + if status != "D": + old = Path(self.sim_cfg.links['D'], self.odir_ln) + rm_path(old) + + def _on_finish(self, status): + '''Called when the process finishes or is killed''' + assert status in ['P', 'F', 'K'] + if status in ['P', 'F']: + self._link_odir(status) + + 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' + self.log_fd.close() + + status = 'P' if self._test_passed() else 'F' + + log.debug("Item %s has completed execution: %s", self.name, status) + self._on_finish(status) + + del self.process + self.process = None + + return status def kill(self): - '''Kill running processes. + '''Kill the running process. + + This must be called between dispatching and reaping the process (the + same window as poll()). + ''' - if self.status == "D" and self.process.poll() is None: - self.kill_remote_job() + assert self.process is not None + self.kill_remote_job() - # 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() + # Try to kill the running process. Send SIGTERM first, wait a bit, + # and then send SIGKILL if it didn't work. + self.process.terminate() + try: + self.process.wait(timeout=2) + except subprocess.TimeoutExpired: + self.process.kill() - if self.log_fd: - self.log_fd.close() - self.status = "K" - # recurisvely kill sub target - elif len(self.sub): - for item in self.sub: - item.kill() + if self.log_fd: + self.log_fd.close() + self.process = None + self._on_finish('K') def kill_remote_job(self): ''' @@ -468,171 +487,6 @@ class Deploy(): except Exception as e: log.error("%s: Failed to run bkill\n", e) - @staticmethod - def increment_timer(): - # sub function that increments with overflow = 60 - def _incr_ovf_60(val): - if val >= 59: - val = 0 - return val, True - else: - val += 1 - return val, False - - incr_hh = False - Deploy.ss, incr_mm = _incr_ovf_60(Deploy.ss) - if incr_mm: - Deploy.mm, incr_hh = _incr_ovf_60(Deploy.mm) - if incr_hh: - Deploy.hh += 1 - - @staticmethod - def deploy(items): - dispatched_items = [] - queued_items = [] - - # Print timer val in hh:mm:ss. - def get_timer_val(): - return "%02i:%02i:%02i" % (Deploy.hh, Deploy.mm, Deploy.ss) - - # Check if elapsed time has reached the next print interval. - def has_print_interval_reached(): - # Deploy.print_interval is expected to be < 1 hour. - return (((Deploy.mm * 60 + Deploy.ss) % - Deploy.print_interval) == 0) - - def dispatch_items(items): - item_names = OrderedDict() - for item in items: - if item.target not in item_names.keys(): - item_names[item.target] = "" - if item.status is None: - item_names[item.target] += item.identifier + ", " - item.dispatch_cmd() - - for target in item_names.keys(): - if item_names[target] != "": - item_names[target] = " [" + item_names[target][:-2] + "]" - log.log(VERBOSE, "[%s]: [%s]: [dispatch]:\n%s", - get_timer_val(), target, item_names[target]) - - # Initialize status for a target, add '_stats_' for the said target - # and initialize counters for queued, dispatched, passed, failed, - # killed and total to 0. Also adds a boolean key to indicate if all - # items in a given target are done. - def init_status_target_stats(status, target): - status[target] = OrderedDict() - status[target]['_stats_'] = OrderedDict() - status[target]['_stats_']['Q'] = 0 - status[target]['_stats_']['D'] = 0 - status[target]['_stats_']['P'] = 0 - status[target]['_stats_']['F'] = 0 - status[target]['_stats_']['K'] = 0 - status[target]['_stats_']['T'] = 0 - status[target]['_done_'] = False - - # Update status counter for a newly queued item. - def add_status_target_queued(status, item): - if item.target not in status.keys(): - init_status_target_stats(status, item.target) - status[item.target][item] = "Q" - status[item.target]['_stats_']['Q'] += 1 - status[item.target]['_stats_']['T'] += 1 - - # Update status counters for a target. - def update_status_target_stats(status, item): - old_status = status[item.target][item] - status[item.target]['_stats_'][old_status] -= 1 - status[item.target]['_stats_'][item.status] += 1 - status[item.target][item] = item.status - - def check_if_done_and_print_status(status, print_status_flag): - all_done = True - for target in status.keys(): - target_done_prev = status[target]['_done_'] - target_done_curr = ((status[target]['_stats_']["Q"] == 0) and - (status[target]['_stats_']["D"] == 0)) - status[target]['_done_'] = target_done_curr - all_done &= target_done_curr - - # Print if flag is set and target_done is not True for two - # consecutive times. - if not (target_done_prev and - target_done_curr) and print_status_flag: - stats = status[target]['_stats_'] - width = "0{}d".format(len(str(stats["T"]))) - msg = "[" - for s in stats.keys(): - msg += s + ": {:{}}, ".format(stats[s], width) - msg = msg[:-2] + "]" - log.info("[%s]: [%s]: %s", get_timer_val(), target, msg) - return all_done - - # Print legend once at the start of the run. - if Deploy.print_legend: - log.info("[legend]: [Q: queued, D: dispatched, " - "P: passed, F: failed, K: killed, T: total]") - Deploy.print_legend = False - - status = OrderedDict() - print_status_flag = True - - # Queue all items - queued_items = items - for item in queued_items: - add_status_target_queued(status, item) - - all_done = False - while not all_done: - # Get status of dispatched items. - for item in dispatched_items: - if item.status == "D": - item.get_status() - if item.status != status[item.target][item]: - print_status_flag = True - if item.status != "D": - if item.status != "P": - # Kill its sub items if item did not pass. - item.set_sub_status("K") - log.error("[%s]: [%s]: [status] [%s: %s]", - get_timer_val(), item.target, - item.identifier, item.status) - else: - log.log(VERBOSE, "[%s]: [%s]: [status] [%s: %s]", - get_timer_val(), item.target, - item.identifier, item.status) - # Queue items' sub-items if it is done. - queued_items.extend(item.sub) - for sub_item in item.sub: - add_status_target_queued(status, sub_item) - update_status_target_stats(status, item) - - # Dispatch items from the queue as slots free up. - all_done = (len(queued_items) == 0) - if not all_done: - num_slots = Deploy.max_parallel - Deploy.dispatch_counter - if num_slots > Deploy.slot_limit: - num_slots = Deploy.slot_limit - if num_slots > 0: - if len(queued_items) > num_slots: - dispatch_items(queued_items[0:num_slots]) - dispatched_items.extend(queued_items[0:num_slots]) - queued_items = queued_items[num_slots:] - else: - dispatch_items(queued_items) - dispatched_items.extend(queued_items) - queued_items = [] - - # Check if we are done and print the status periodically. - all_done &= check_if_done_and_print_status(status, - print_status_flag) - - # Advance time by 1s if there is more work to do. - if not all_done: - time.sleep(1) - Deploy.increment_timer() - print_status_flag = has_print_interval_reached() - class CompileSim(Deploy): """ @@ -692,9 +546,9 @@ class CompileSim(Deploy): CompileSim.items.append(self) def dispatch_cmd(self): - # Delete previous cov_db_dir if it exists before dispatching new build. - if os.path.exists(self.cov_db_dir): - os.system("rm -rf " + self.cov_db_dir) + # Delete old coverage database directories before building again. We + # need to do this becuase build directory is not 'renewed'. + rm_path(self.cov_db_dir) super().dispatch_cmd() @@ -765,7 +619,7 @@ class RunTest(Deploy): cmds_list_vars = ["pre_run_cmds", "post_run_cmds"] - def __init__(self, index, test, sim_cfg): + def __init__(self, index, test, build_job, sim_cfg): # Initialize common vars. super().__init__(sim_cfg) @@ -790,11 +644,15 @@ class RunTest(Deploy): self.mandatory_misc_attrs.update({ "run_dir_name": False, + "cov_db_dir": False, "cov_db_test_dir": False, "run_pass_patterns": False, "run_fail_patterns": False }) + if build_job is not None: + self.dependencies.append(build_job) + self.index = index self.seed = RunTest.get_seed() @@ -824,16 +682,11 @@ class RunTest(Deploy): # Set identifier. self.identifier = self.sim_cfg.name + ":" + self.run_dir_name - def get_status(self): - '''Override base class get_status implementation for additional post-status - actions.''' - super().get_status() - if self.status not in ["D", "P"]: + def _on_finish(self, status): + super()._on_finish(status) + if status != 'P': # Delete the coverage data if available. - if os.path.exists(self.cov_db_test_dir): - log.log(VERBOSE, "Deleting coverage data of failing test:\n%s", - self.cov_db_test_dir) - os.system("/bin/rm -rf " + self.cov_db_test_dir) + rm_path(self.cov_db_test_dir) @staticmethod def get_seed(): @@ -906,10 +759,13 @@ class CovMerge(Deploy): # Register all builds with the class items = [] - def __init__(self, sim_cfg): + def __init__(self, run_items, sim_cfg): # Initialize common vars. super().__init__(sim_cfg) + self.dependencies += run_items + self.needs_all_dependencies_passing = False + self.target = "cov_merge" self.pass_patterns = [] self.fail_patterns = [] @@ -943,9 +799,11 @@ class CovMerge(Deploy): CovMerge.items.append(self) def __post_init__(self): - # Add cov db dirs from all the builds that were kicked off. - for bld in self.sim_cfg.builds: - self.cov_db_dirs += bld.cov_db_dir + " " + # Extract cov db dirs from all the sim runs. + for item in self.dependencies: + if item.target == "run": + if item.cov_db_dir not in self.cov_db_dirs: + self.cov_db_dirs += item.cov_db_dir + " " # Recursively search and replace wildcards, ignoring cov_db_dirs. # We need to resolve it later based on cov_db_dirs value set below. @@ -975,7 +833,8 @@ class CovMerge(Deploy): # that as well for merging, if the --cov-merge-previous command line # switch is passed. if self.sim_cfg.cov_merge_previous: - self.cov_db_dirs += prev_cov_db_dirs + self.cov_db_dirs += " ".join( + [str(item) for item in prev_cov_db_dirs]) # Append cov_db_dirs to the list of exports. self.exports["cov_db_dirs"] = "\"{}\"".format(self.cov_db_dirs) @@ -990,10 +849,12 @@ class CovReport(Deploy): # Register all builds with the class items = [] - def __init__(self, sim_cfg): + def __init__(self, merge_job, sim_cfg): # Initialize common vars. super().__init__(sim_cfg) + self.dependencies.append(merge_job) + self.target = "cov_report" self.pass_patterns = [] self.fail_patterns = [] @@ -1021,28 +882,31 @@ class CovReport(Deploy): CovReport.items.append(self) - def get_status(self): - super().get_status() - # Once passed, extract the cov results summary from the dashboard. - if self.status == "P": - results, self.cov_total, ex_msg = get_cov_summary_table( - self.cov_report_txt, self.sim_cfg.tool) + def _test_passed(self): + # Add an extra check to Deploy._test_passed where we extract the + # coverage results summary for the dashboard (and fail the job if + # something goes wrong). + if not super()._test_passed(): + return False - if not ex_msg: - # Succeeded in obtaining the coverage data. - colalign = (("center", ) * len(results[0])) - self.cov_results = tabulate(results, - headers="firstrow", - tablefmt="pipe", - colalign=colalign) - else: - self.fail_msg += ex_msg - log.error(ex_msg) - self.status = "F" + results, self.cov_total, ex_msg = get_cov_summary_table( + self.cov_report_txt, self.sim_cfg.tool) - if self.status == "P": - # Delete the cov report - not needed. - os.system("rm -rf " + self.log) + if ex_msg: + self.fail_msg += ex_msg + log.error(ex_msg) + return False + + # Succeeded in obtaining the coverage data. + colalign = (("center", ) * len(results[0])) + self.cov_results = tabulate(results, + headers="firstrow", + tablefmt="pipe", + colalign=colalign) + + # Delete the cov report - not needed. + rm_path(self.log) + return True class CovAnalyze(Deploy): diff --git a/vendor/lowrisc_ip/util/dvsim/FlowCfg.py b/vendor/lowrisc_ip/util/dvsim/FlowCfg.py index b23da234..199db9bb 100644 --- a/vendor/lowrisc_ip/util/dvsim/FlowCfg.py +++ b/vendor/lowrisc_ip/util/dvsim/FlowCfg.py @@ -6,16 +6,15 @@ import datetime import logging as log import os import pprint -from shutil import which import subprocess import sys +from shutil import which import hjson - from CfgJson import set_target_attribute -from Deploy import Deploy -from utils import (VERBOSE, md_results_to_html, - subst_wildcards, find_and_substitute_wildcards) +from Scheduler import Scheduler +from utils import (VERBOSE, find_and_substitute_wildcards, md_results_to_html, + rm_path, subst_wildcards) # Interface class for extensions. @@ -25,7 +24,6 @@ class FlowCfg(): The constructor expects some parsed hjson data. Create these objects with the factory function in CfgFactory.py, which loads the hjson data and picks a subclass of FlowCfg based on its contents. - ''' # Set in subclasses. This is the key that must be used in an hjson file to @@ -69,8 +67,9 @@ class FlowCfg(): # a special key 'use_cfgs' within the hjson cfg. self.is_primary_cfg = False - # For a primary cfg, it is the aggregated list of all deploy objects under self.cfgs. - # For a non-primary cfg, it is the list of items slated for dispatch. + # For a primary cfg, it is the aggregated list of all deploy objects + # under self.cfgs. For a non-primary cfg, it is the list of items + # slated for dispatch. self.deploy = [] # Timestamp @@ -87,7 +86,8 @@ class FlowCfg(): self.results_server_prefix = "" self.results_server_url_prefix = "" self.results_server_cmd = "" - self.css_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), "style.css") + self.css_file = os.path.join( + os.path.dirname(os.path.realpath(__file__)), "style.css") self.results_server_path = "" self.results_server_dir = "" self.results_server_html = "" @@ -147,10 +147,7 @@ class FlowCfg(): ''' for key, value in hjson_data.items(): - set_target_attribute(self.flow_cfg_file, - self.__dict__, - key, - value) + set_target_attribute(self.flow_cfg_file, self.__dict__, key, value) def _expand(self): '''Called to expand wildcards after merging hjson @@ -188,29 +185,20 @@ class FlowCfg(): # don't yet support heterogeneous primary configurations. if type(self) is not type(new_instance): log.error("{}: Loading child configuration at {!r}, but the " - "resulting flow types don't match: ({} vs. {})." - .format(self.flow_cfg_file, - flow_cfg_file, - type(self).__name__, - type(new_instance).__name__)) + "resulting flow types don't match: ({} vs. {}).".format( + self.flow_cfg_file, flow_cfg_file, + type(self).__name__, + type(new_instance).__name__)) sys.exit(1) return new_instance - def kill(self): - '''kill running processes and jobs gracefully - ''' - for item in self.deploy: - item.kill() - def _load_child_cfg(self, entry, mk_config): '''Load a child configuration for a primary cfg''' if type(entry) is str: # Treat this as a file entry. Substitute wildcards in cfg_file # files since we need to process them right away. - cfg_file = subst_wildcards(entry, - self.__dict__, - ignore_error=True) + cfg_file = subst_wildcards(entry, self.__dict__, ignore_error=True) self.cfgs.append(self.create_instance(mk_config, cfg_file)) elif type(entry) is dict: @@ -221,13 +209,8 @@ class FlowCfg(): self.cfgs.append(self.create_instance(mk_config, temp_cfg_file)) # Delete the temp_cfg_file once the instance is created - try: - log.log(VERBOSE, "Deleting temp cfg file:\n%s", - temp_cfg_file) - os.system("/bin/rm -rf " + temp_cfg_file) - except IOError: - log.error("Failed to remove temp cfg file:\n%s", - temp_cfg_file) + log.log(VERBOSE, "Deleting temp cfg file:\n%s", temp_cfg_file) + rm_path(temp_cfg_file, ignore_error=True) else: log.error( @@ -245,14 +228,13 @@ class FlowCfg(): name = idict["name"] if "name" in idict.keys() else None if not name: - log.error("In-line entry in use_cfgs list does not contain " - "a \"name\" key (will be skipped!):\n%s", - idict) + log.error("In-line entry in use_cfgs list does not contain a " + "\"name\" key (will be skipped!):\n%s", idict) return None # Check if temp cfg file already exists - temp_cfg_file = (self.scratch_root + "/." + self.branch + "__" + - name + "_cfg.hjson") + temp_cfg_file = (self.scratch_root + "/." + self.branch + "__" + name + + "_cfg.hjson") # Create the file and dump the dict as hjson log.log(VERBOSE, "Dumping inline cfg \"%s\" in hjson to:\n%s", name, @@ -262,8 +244,7 @@ class FlowCfg(): f.write(hjson.dumps(idict, for_json=True)) except Exception as e: log.error("Failed to hjson-dump temp cfg file\"%s\" for \"%s\"" - "(will be skipped!) due to:\n%s", - temp_cfg_file, name, e) + "(will be skipped!) due to:\n%s", temp_cfg_file, name, e) return None # Return the temp cfg file created @@ -277,28 +258,28 @@ class FlowCfg(): if hasattr(self, "overrides"): overrides = getattr(self, "overrides") if type(overrides) is not list: - log.error( - "The type of key \"overrides\" is %s - it should be a list", - type(overrides)) + log.error("The type of key \"overrides\" is %s - it should be " + "a list", type(overrides)) sys.exit(1) # Process override one by one for item in overrides: - if type(item) is dict and set(item.keys()) == {"name", "value"}: + if type(item) is dict and set( + item.keys()) == {"name", "value"}: ov_name = item["name"] ov_value = item["value"] if ov_name not in overrides_dict.keys(): overrides_dict[ov_name] = ov_value self._do_override(ov_name, ov_value) else: - log.error( - "Override for key \"%s\" already exists!\nOld: %s\nNew: %s", - ov_name, overrides_dict[ov_name], ov_value) + log.error("Override for key \"%s\" already exists!\n" + "Old: %s\nNew: %s", ov_name, + overrides_dict[ov_name], ov_value) sys.exit(1) else: - log.error("\"overrides\" is a list of dicts with {\"name\": , " - "\"value\": } pairs. Found this instead:\n%s", - str(item)) + log.error("\"overrides\" is a list of dicts with " + "{\"name\": , \"value\": } pairs. " + "Found this instead:\n%s", str(item)) sys.exit(1) def _do_override(self, ov_name, ov_value): @@ -310,8 +291,8 @@ class FlowCfg(): 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\"", + log.error("The type of override value \"%s\" for \"%s\" " + "mismatches the type of original value \"%s\"", ov_value, ov_name, orig_value) sys.exit(1) else: @@ -323,24 +304,22 @@ class FlowCfg(): return def purge(self): - '''Public facing API for _purge(). - ''' + '''Public facing API for _purge().''' for item in self.cfgs: item._purge() def _print_list(self): - '''Print the list of available items that can be kicked off. - ''' + '''Print the list of available items that can be kicked off.''' return def print_list(self): - '''Public facing API for _print_list(). - ''' + '''Public facing API for _print_list().''' + for item in self.cfgs: item._print_list() def prune_selected_cfgs(self): - '''Prune the list of configs for a primary config file''' + '''Prune the list of configs for a primary config file.''' # This should run after self.cfgs has been set assert self.cfgs @@ -352,9 +331,9 @@ class FlowCfg(): # If the user passed --select-cfgs, but this isn't a primary config # file, we should probably complain. if not self.is_primary_cfg: - log.error('The configuration file at {!r} is not a primary config, ' - 'but --select-cfgs was passed on the command line.' - .format(self.flow_cfg_file)) + log.error('The configuration file at {!r} is not a primary ' + 'config, but --select-cfgs was passed on the command ' + 'line.'.format(self.flow_cfg_file)) sys.exit(1) # Filter configurations @@ -362,8 +341,8 @@ class FlowCfg(): def _create_deploy_objects(self): '''Create deploy objects from items that were passed on for being run. - The deploy objects for build and run are created from the objects that were - created from the create_objects() method. + The deploy objects for build and run are created from the objects that + were created from the create_objects() method. ''' return @@ -371,33 +350,39 @@ class FlowCfg(): '''Public facing API for _create_deploy_objects(). ''' self.prune_selected_cfgs() - if self.is_primary_cfg: - self.deploy = [] - for item in self.cfgs: - item._create_deploy_objects() - self.deploy.extend(item.deploy) - else: - self._create_deploy_objects() + for item in self.cfgs: + item._create_deploy_objects() def deploy_objects(self): - '''Public facing API for deploying all available objects.''' - Deploy.deploy(self.deploy) + '''Public facing API for deploying all available objects. - def _gen_results(self, fmt="md"): + Runs each job and returns a map from item to status. ''' - The function is called after the regression has completed. It collates the - status of all run targets and generates a dict. It parses the testplan and - maps the generated result to the testplan entries to generate a final table - (list). It also prints the full list of failures for debug / triage. The - final result is in markdown format. + deploy = [] + for item in self.cfgs: + deploy.extend(item.deploy) + return Scheduler(deploy).run() + + def _gen_results(self, results): + ''' + The function is called after the regression has completed. It collates + the status of all run targets and generates a dict. It parses the + testplan and maps the generated result to the testplan entries to + generate a final table (list). It also prints the full list of failures + for debug / triage. The final result is in markdown format. + + results should be a dictionary mapping deployed item to result. ''' return - def gen_results(self): + def gen_results(self, results): '''Public facing API for _gen_results(). + + results should be a dictionary mapping deployed item to result. + ''' for item in self.cfgs: - result = item._gen_results() + result = item._gen_results(results) log.info("[results]: [%s]:\n%s\n", item.name, result) log.info("[scratch_path]: [%s] [%s]", item.name, item.scratch_path) self.errors_seen |= item.errors_seen @@ -425,7 +410,8 @@ class FlowCfg(): gen_results = self.email_summary_md or self.results_summary_md else: gen_results = self.email_results_md or self.results_md - results_html = md_results_to_html(self.results_title, self.css_file, gen_results) + results_html = md_results_to_html(self.results_title, self.css_file, + gen_results) results_html_file = self.scratch_root + "/email.html" f = open(results_html_file, 'w') f.write(results_html) @@ -434,15 +420,16 @@ class FlowCfg(): def _publish_results(self): '''Publish results to the opentitan web server. + Results are uploaded to {results_server_path}/latest/results. - If the 'latest' directory exists, then it is renamed to its 'timestamp' directory. - If the list of directories in this area is > 14, then the oldest entry is removed. - Links to the last 7 regression results are appended at the end if the results page. + If the 'latest' directory exists, then it is renamed to its 'timestamp' + directory. If the list of directories in this area is > 14, then the + oldest entry is removed. Links to the last 7 regression results are + appended at the end if the results page. ''' if which('gsutil') is None or which('gcloud') is None: - log.error( - "Google cloud SDK not installed! Cannot access the results server" - ) + log.error("Google cloud SDK not installed! Cannot access the " + "results server") return # Construct the paths @@ -552,16 +539,17 @@ class FlowCfg(): # Publish the results page. # First, write the results html file temporarily to the scratch area. - results_html_file = self.scratch_path + "/results_" + self.timestamp + ".html" + results_html_file = self.scratch_path + "/results_" + self.timestamp + \ + ".html" f = open(results_html_file, 'w') f.write( - md_results_to_html(self.results_title, self.css_file, publish_results_md)) + md_results_to_html(self.results_title, self.css_file, + publish_results_md)) f.close() - rm_cmd += "/bin/rm -rf " + results_html_file + "; " log.info("Publishing results to %s", results_page_url) cmd = (self.results_server_cmd + " cp " + results_html_file + " " + - self.results_server_page + "; " + rm_cmd) + self.results_server_page) log.log(VERBOSE, cmd) try: cmd_output = subprocess.run(args=cmd, @@ -571,9 +559,11 @@ class FlowCfg(): log.log(VERBOSE, cmd_output.stdout.decode("utf-8")) except Exception as e: log.error("%s: Failed to publish results:\n\"%s\"", e, str(cmd)) + rm_path(results_html_file) def publish_results(self): - '''Public facing API for publishing results to the opentitan web server. + '''Public facing API for publishing results to the opentitan web + server. ''' for item in self.cfgs: item._publish_results() @@ -582,7 +572,8 @@ class FlowCfg(): self.publish_results_summary() def publish_results_summary(self): - '''Public facing API for publishing md format results to the opentitan web server. + '''Public facing API for publishing md format results to the opentitan + web server. ''' results_html_file = "summary_" + self.timestamp + ".html" results_page_url = self.results_summary_server_page.replace( @@ -592,13 +583,13 @@ class FlowCfg(): # First, write the results html file temporarily to the scratch area. f = open(results_html_file, 'w') f.write( - md_results_to_html(self.results_title, self.css_file, self.results_summary_md)) + md_results_to_html(self.results_title, self.css_file, + self.results_summary_md)) f.close() - rm_cmd = "/bin/rm -rf " + results_html_file + "; " log.info("Publishing results summary to %s", results_page_url) cmd = (self.results_server_cmd + " cp " + results_html_file + " " + - self.results_summary_server_page + "; " + rm_cmd) + self.results_summary_server_page) log.log(VERBOSE, cmd) try: cmd_output = subprocess.run(args=cmd, @@ -608,6 +599,7 @@ class FlowCfg(): log.log(VERBOSE, cmd_output.stdout.decode("utf-8")) except Exception as e: log.error("%s: Failed to publish results:\n\"%s\"", e, str(cmd)) + rm_path(results_html_file) def has_errors(self): return self.errors_seen diff --git a/vendor/lowrisc_ip/util/dvsim/FpvCfg.py b/vendor/lowrisc_ip/util/dvsim/FpvCfg.py index 1add68ac..c191abf6 100644 --- a/vendor/lowrisc_ip/util/dvsim/FpvCfg.py +++ b/vendor/lowrisc_ip/util/dvsim/FpvCfg.py @@ -183,7 +183,7 @@ class FpvCfg(OneShotCfg): return self.results_summary_md - def _gen_results(self): + def _gen_results(self, results): # This function is called after the regression and looks for # results.hjson file with aggregated results from the FPV run. # The hjson file is required to follow this format: diff --git a/vendor/lowrisc_ip/util/dvsim/LintCfg.py b/vendor/lowrisc_ip/util/dvsim/LintCfg.py index 7854bb4e..f1f460c3 100644 --- a/vendor/lowrisc_ip/util/dvsim/LintCfg.py +++ b/vendor/lowrisc_ip/util/dvsim/LintCfg.py @@ -87,7 +87,7 @@ class LintCfg(OneShotCfg): # Return only the tables return self.results_summary_md - def _gen_results(self): + def _gen_results(self, results): # ''' # The function is called after the regression has completed. It looks # for a regr_results.hjson file with aggregated results from the lint run. diff --git a/vendor/lowrisc_ip/util/dvsim/OneShotCfg.py b/vendor/lowrisc_ip/util/dvsim/OneShotCfg.py index 1612734e..2dc3d5ac 100644 --- a/vendor/lowrisc_ip/util/dvsim/OneShotCfg.py +++ b/vendor/lowrisc_ip/util/dvsim/OneShotCfg.py @@ -7,12 +7,12 @@ Class describing a one-shot build configuration object import logging as log import os -import sys from collections import OrderedDict from Deploy import CompileOneShot from FlowCfg import FlowCfg from Modes import BuildModes, Modes +from utils import rm_path class OneShotCfg(FlowCfg): @@ -110,13 +110,9 @@ class OneShotCfg(FlowCfg): # Purge the output directories. This operates on self. def _purge(self): - if self.scratch_path: - try: - log.info("Purging scratch path %s", self.scratch_path) - os.system("/bin/rm -rf " + self.scratch_path) - except IOError: - log.error('Failed to purge scratch directory %s', - self.scratch_path) + assert self.scratch_path + log.info("Purging scratch path %s", self.scratch_path) + rm_path(self.scratch_path) def _create_objects(self): # Create build and run modes objects @@ -142,21 +138,9 @@ class OneShotCfg(FlowCfg): def _create_dirs(self): '''Create initial set of directories ''' - # Invoking system calls has a performance penalty. - # Construct a single command line chained with '&&' to invoke - # the system call only once, rather than multiple times. - create_link_dirs_cmd = "" for link in self.links.keys(): - create_link_dirs_cmd += "/bin/rm -rf " + self.links[link] + " && " - create_link_dirs_cmd += "mkdir -p " + self.links[link] + " && " - create_link_dirs_cmd += " true" - - try: - os.system(create_link_dirs_cmd) - except IOError: - log.error("Error running when running the cmd \"%s\"", - create_link_dirs_cmd) - sys.exit(1) + rm_path(self.links[link]) + os.makedirs(self.links[link]) def _create_deploy_objects(self): '''Create deploy objects from build modes diff --git a/vendor/lowrisc_ip/util/dvsim/Scheduler.py b/vendor/lowrisc_ip/util/dvsim/Scheduler.py new file mode 100644 index 00000000..92c79979 --- /dev/null +++ b/vendor/lowrisc_ip/util/dvsim/Scheduler.py @@ -0,0 +1,283 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +import logging as log +import threading +from collections import OrderedDict +from signal import SIGINT, signal + +from Deploy import DeployError +from Timer import Timer +from utils import VERBOSE + + +class TargetScheduler: + '''A scheduler for the jobs of a given target''' + def __init__(self, name): + self.name = name + + # Sets of items, split up by their current state. The sets are disjoint + # and their union equals the keys of self.item_to_status. _queued is a + # list so that we dispatch things in order (relevant for things like + # tests where we have ordered things cleverly to try to see failures + # early) + self._queued = [] + self._running = set() + self._passed = set() + self._failed = set() + self._killed = set() + + # A map from the Deploy objects tracked by this class to their current + # status. This status is 'Q', 'D', 'P', 'F' or 'K', corresponding to + # membership in the dicts above. + self.item_to_status = {} + + def add_item(self, item): + assert item not in self.item_to_status + assert item not in self._queued + self.item_to_status[item] = 'Q' + self._queued.append(item) + + def _kill_item(self, item): + '''Kill a running item''' + self._running.remove(item) + item.kill() + self._killed.add(item) + self.item_to_status[item] = 'K' + + def _poll(self, hms): + '''Check for running items that have finished + + Returns True if something changed. + + ''' + to_pass = [] + to_fail = [] + + for item in self._running: + status = item.poll() + assert status in ['D', 'P', 'F'] + if status == 'D': + # Still running + continue + elif status == 'P': + log.log(VERBOSE, "[%s]: [%s]: [status] [%s: P]", hms, + item.target, item.identifier) + to_pass.append(item) + else: + log.error("[%s]: [%s]: [status] [%s: F]", hms, item.target, + item.identifier) + to_fail.append(item) + + for item in to_pass: + self._running.remove(item) + self._passed.add(item) + self.item_to_status[item] = 'P' + for item in to_fail: + self._running.remove(item) + self._failed.add(item) + self.item_to_status[item] = 'F' + + return to_pass or to_fail + + def _dispatch(self, hms, old_results): + '''Dispatch some queued items if possible. + + See run() for the format of old_results. + + ''' + num_slots = min(Scheduler.slot_limit, + Scheduler.max_parallel - len(self._running), + len(self._queued)) + if num_slots <= 0: + return + + to_dispatch = [] + + while len(to_dispatch) < num_slots and self._queued: + next_item = self._queued.pop(0) + # Does next_item have any dependencies? Since we dispatch jobs by + # target, we can assume that each of those dependencies appears + # in old_results. + has_failed_dep = False + for dep in next_item.dependencies: + dep_status = old_results[dep] + assert dep_status in ['P', 'F', 'K'] + + if next_item.needs_all_dependencies_passing: + if dep_status in ['F', 'K']: + has_failed_dep = True + break + else: + # Set has_failed_dep default value to True only if the + # next_item has dependencies, and next_item does not require + # all dependencies to pass + has_failed_dep = True + if dep_status in ['P']: + has_failed_dep = False + break + + # If has_failed_dep then at least one of the dependencies has been + # cancelled or has run and failed. Give up on this item too. + if has_failed_dep: + self._killed.add(next_item) + self.item_to_status[next_item] = 'K' + continue + + to_dispatch.append(next_item) + + if not to_dispatch: + return + + log.log(VERBOSE, "[%s]: [%s]: [dispatch]:\n%s", hms, self.name, + ", ".join(item.identifier for item in to_dispatch)) + + for item in to_dispatch: + self._running.add(item) + self.item_to_status[item] = 'D' + try: + item.dispatch_cmd() + except DeployError as err: + log.error('{}'.format(err)) + self._kill_item(item) + + 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 item in [item for item in self._queued]: + self._cancel(item) + + # Kill any running items. Again, take a copy of the set to avoid + # modifying it while iterating over it. + for item in [item for item in self._running]: + self._kill_item(item) + + def _cancel(self, item): + '''Cancel an item that is currently queued''' + assert item in self._queued + self._queued.remove(item) + self._killed.add(item) + self.item_to_status[item] = 'K' + + def _check_if_done(self, timer, hms, print_status): + '''Check whether we are finished. + + If print_status or we've reached a time interval then print current + status for those jobs that weren't known to be finished already. + + ''' + if timer.check_time(): + print_status = True + + if print_status: + total_cnt = len(self.item_to_status) + width = len(str(total_cnt)) + + field_fmt = '{{:0{}d}}'.format(width) + msg_fmt = ('[Q: {0}, D: {0}, P: {0}, F: {0}, K: {0}, T: {0}]'. + format(field_fmt)) + msg = msg_fmt.format(len(self._queued), len(self._running), + len(self._passed), len(self._failed), + len(self._killed), total_cnt) + log.info("[%s]: [%s]: %s", hms, self.name, msg) + + return not (self._queued or self._running) + + def run(self, timer, old_results): + '''Run the jobs for this target. + + timer is a Timer that was started at the start of the Runner's run. + + old_results is a dictionary mapping items (from previous targets) to + statuses. Every job that appears as a dependency will be in this list + (because it ran as part of a previous target). + + is_first_tgt is true if this is the first target to run. + + Returns the results from this target (in the same format). + + ''' + # Catch one SIGINT and tell the runner to quit. On a second, die. + stop_now = threading.Event() + old_handler = None + + def on_sigint(signal_received, frame): + log.info('Received SIGINT. Exiting gracefully. ' + 'Send another to force immediate quit ' + '(but you may need to manually kill child processes)') + + # Restore old handler to catch any second signal + assert old_handler is not None + signal(SIGINT, old_handler) + + stop_now.set() + + old_handler = signal(SIGINT, on_sigint) + + try: + while True: + if stop_now.is_set(): + # We've had an interrupt. Kill any jobs that are running, + # then exit. + self._kill() + exit(1) + + hms = timer.hms() + changed = self._poll(hms) + self._dispatch(hms, old_results) + if self._check_if_done(timer, hms, changed): + break + + # This is essentially sleep(1) to wait a second between each + # polling loop. But we do it with a bounded wait on stop_now so + # that we jump back to the polling loop immediately on a + # signal. + stop_now.wait(timeout=1) + finally: + signal(SIGINT, old_handler) + + # We got to the end without anything exploding. Return the results for our jobs. + return self.item_to_status + + +class Scheduler: + '''An object to run one or more Deploy items''' + + # Max jobs running at one time + max_parallel = 16 + + # Max jobs dispatched in one go. + slot_limit = 20 + + def __init__(self, items): + # An ordered dictionary keyed by target ('build', 'run' or similar). + # The value for each target is a TargetScheduler object. + self.schedulers = OrderedDict() + + for item in items: + # This works like setdefault, but doesn't construct a TargetScheduler + # object unnecessarily. + tgt_scheduler = self.schedulers.get(item.target) + if tgt_scheduler is None: + tgt_scheduler = TargetScheduler(item.target) + self.schedulers[item.target] = tgt_scheduler + + tgt_scheduler.add_item(item) + + def run(self): + '''Run all items + + Returns a map from item to status. + + ''' + timer = Timer() + + log.info("[legend]: [Q: queued, D: dispatched, " + "P: passed, F: failed, K: killed, T: total]") + results = {} + for scheduler in self.schedulers.values(): + results.update(scheduler.run(timer, results)) + return results diff --git a/vendor/lowrisc_ip/util/dvsim/SimCfg.py b/vendor/lowrisc_ip/util/dvsim/SimCfg.py index bad908da..89b16beb 100644 --- a/vendor/lowrisc_ip/util/dvsim/SimCfg.py +++ b/vendor/lowrisc_ip/util/dvsim/SimCfg.py @@ -12,14 +12,13 @@ import subprocess import sys from collections import OrderedDict -from Deploy import (CompileSim, CovAnalyze, CovMerge, CovReport, CovUnr, - Deploy, RunTest) +from Deploy import CompileSim, CovAnalyze, CovMerge, CovReport, CovUnr, RunTest from FlowCfg import FlowCfg from Modes import BuildModes, Modes, Regressions, RunModes, Tests from tabulate import tabulate -from utils import VERBOSE - -from testplanner import class_defs, testplan_utils +from testplanner.class_defs import Testplan, TestResult +from testplanner.testplan_utils import parse_testplan +from utils import VERBOSE, rm_path def pick_wave_format(fmts): @@ -42,6 +41,46 @@ def pick_wave_format(fmts): return fmt +class Results: + '''An object wrapping up a table of results for some tests + + self.table is a list of TestResult objects, each of which + corresponds to one or more runs of the test with a given name. + + self.fail_msgs is a list of error messages, one per failing run. + + ''' + def __init__(self, items, results): + self.table = [] + self.fail_msgs = [] + + self._name_to_row = {} + for item in items: + self._add_item(item, results) + + def _add_item(self, item, results): + '''Recursively add a single item to the table of results''' + status = results[item] + if status == "F": + self.fail_msgs.append(item.fail_msg) + + # Runs get added to the table directly + if item.target == "run": + self._add_run(item, status) + + def _add_run(self, item, status): + '''Add an entry to table for item''' + row = self._name_to_row.get(item.name) + if row is None: + row = TestResult(item.name) + self.table.append(row) + self._name_to_row[item.name] = row + + if status == 'P': + row.passing += 1 + row.total += 1 + + class SimCfg(FlowCfg): """Simulation configuration object @@ -86,10 +125,6 @@ class SimCfg(FlowCfg): self.dry_run = args.dry_run self.map_full_testplan = args.map_full_testplan - # Disable cov if --build-only is passed. - if self.build_only: - self.cov = False - # Set default sim modes for unpacking if args.waves is not None: self.en_build_modes.append("waves") @@ -140,10 +175,6 @@ class SimCfg(FlowCfg): self.cov_report_deploy = None self.results_summary = OrderedDict() - # If is_primary_cfg is set, then each cfg will have its own cov_deploy. - # Maintain an array of those in cov_deploys. - self.cov_deploys = [] - super().__init__(flow_cfg_file, hjson_data, args, mk_config) def _expand(self): @@ -244,22 +275,11 @@ class SimCfg(FlowCfg): return self.waves - def kill(self): - '''kill running processes and jobs gracefully - ''' - super().kill() - for item in self.cov_deploys: - item.kill() - # Purge the output directories. This operates on self. def _purge(self): - if self.scratch_path: - try: - log.info("Purging scratch path %s", self.scratch_path) - os.system("/bin/rm -rf " + self.scratch_path) - except IOError: - log.error('Failed to purge scratch directory %s', - self.scratch_path) + assert self.scratch_path + log.info("Purging scratch path %s", self.scratch_path) + rm_path(self.scratch_path) def _create_objects(self): # Create build and run modes objects @@ -303,12 +323,12 @@ class SimCfg(FlowCfg): # Regressions # Parse testplan if provided. if self.testplan != "": - self.testplan = testplan_utils.parse_testplan(self.testplan) + self.testplan = parse_testplan(self.testplan) # Extract tests in each milestone and add them as regression target. self.regressions.extend(self.testplan.get_milestone_regressions()) else: # Create a dummy testplan with no entries. - self.testplan = class_defs.Testplan(name=self.name) + self.testplan = Testplan(name=self.name) # Create regressions self.regressions = Regressions.create_regressions( @@ -415,21 +435,9 @@ class SimCfg(FlowCfg): def _create_dirs(self): '''Create initial set of directories ''' - # Invoking system calls has a performance penalty. - # Construct a single command line chained with '&&' to invoke - # the system call only once, rather than multiple times. - create_link_dirs_cmd = "" for link in self.links.keys(): - create_link_dirs_cmd += "/bin/rm -rf " + self.links[link] + " && " - create_link_dirs_cmd += "mkdir -p " + self.links[link] + " && " - create_link_dirs_cmd += " true" - - try: - os.system(create_link_dirs_cmd) - except IOError: - log.error("Error running when running the cmd \"%s\"", - create_link_dirs_cmd) - sys.exit(1) + rm_path(self.links[link]) + os.makedirs(self.links[link]) def _expand_run_list(self, build_map): '''Generate a list of tests to be run @@ -441,27 +449,27 @@ class SimCfg(FlowCfg): tests A, B with reseed values of 5 and 2, respectively, then the list will be ABABAAA). - build_map is a dictionary from build name to a CompileSim object. Each - test is added to the CompileSim item that it depends on (signifying - that the test should be built once the build on which it depends is - done). + build_map is either None or a dictionary from build name to a + CompileSim object. If None, this means that we're in "run only" mode, + so there are no builds involved at all. Otherwise, the build_mode of + each appears in the map to signify the test's dependency on its + corresponding CompileSim item (test cannot run until it has been + compiled). + ''' tagged = [] for test in self.run_list: + build_job = (build_map[test.build_mode] + if build_map is not None else None) for idx in range(test.reseed): - tagged.append((idx, test, RunTest(idx, test, self))) + tagged.append((idx, RunTest(idx, test, build_job, self))) # Stably sort the tagged list by the 1st coordinate tagged.sort(key=lambda x: x[0]) - # Now iterate over it again, adding tests to build_map (in the - # interleaved order) and collecting up the RunTest objects. - runs = [] - for _, test, run in tagged: - build_map[test.build_mode].sub.append(run) - runs.append(run) - - return runs + # Return the sorted list of RunTest objects, discarding the indices by + # which we sorted it. + return [run for _, run in tagged] def _create_deploy_objects(self): '''Create deploy objects from the build and run lists. @@ -476,11 +484,12 @@ class SimCfg(FlowCfg): new_build = CompileSim(build_mode_obj, self) # It is possible for tests to supply different build modes, but - # those builds may differ only under specific circumstances, such - # as coverage being enabled. If coverage is not enabled, then they - # may be completely identical. In that case, we can save compute - # resources by removing the extra duplicated builds. We discard the - # new_build if it is equivalent to an existing one. + # those builds may differ only under specific circumstances, + # such as coverage being enabled. If coverage is not enabled, + # then they may be completely identical. In that case, we can + # save compute resources by removing the extra duplicated + # builds. We discard the new_build if it is equivalent to an + # existing one. is_unique = True for build in self.builds: if build.is_equivalent_job(new_build): @@ -498,43 +507,25 @@ class SimCfg(FlowCfg): test.build_mode = Modes.find_mode( build_map[test.build_mode].name, self.build_modes) + if self.run_only: + self.builds = [] + build_map = None + self.runs = ([] if self.build_only else self._expand_run_list(build_map)) - self.deploy = self.runs if self.run_only else self.builds + self.deploy = self.builds + self.runs - # Create cov_merge and cov_report objects - if self.cov: - self.cov_merge_deploy = CovMerge(self) - self.cov_report_deploy = CovReport(self) - self.cov_merge_deploy.sub.append(self.cov_report_deploy) + # Create cov_merge and cov_report objects, so long as we've got at + # least one run to do. + if self.cov and self.runs: + self.cov_merge_deploy = CovMerge(self.runs, self) + self.cov_report_deploy = CovReport(self.cov_merge_deploy, self) + self.deploy += [self.cov_merge_deploy, self.cov_report_deploy] # Create initial set of directories before kicking off the regression. self._create_dirs() - def create_deploy_objects(self): - '''Public facing API for _create_deploy_objects(). - ''' - super().create_deploy_objects() - - # Also, create cov_deploys - if self.cov: - for item in self.cfgs: - if item.cov: - self.cov_deploys.append(item.cov_merge_deploy) - - # deploy additional commands as needed. We do this separated for coverage - # since that needs to happen at the end. - def deploy_objects(self): - '''This is a public facing API, so we use "self.cfgs" instead of self. - ''' - # Invoke the base class method to run the regression. - super().deploy_objects() - - # If coverage is enabled, then deploy the coverage tasks. - if self.cov: - Deploy.deploy(self.cov_deploys) - def _cov_analyze(self): '''Use the last regression coverage data to open up the GUI tool to analyze the coverage. @@ -571,7 +562,7 @@ class SimCfg(FlowCfg): for item in self.cfgs: item._cov_unr() - def _gen_results(self): + def _gen_results(self, run_results): ''' The function is called after the regression has completed. It collates the status of all run targets and generates a dict. It parses the testplan and @@ -581,50 +572,11 @@ class SimCfg(FlowCfg): result is in markdown format. ''' - # TODO: add support for html - def retrieve_result(name, results): - for item in results: - if name == item["name"]: - return item - return None - - def gen_results_sub(items, results, fail_msgs): - ''' - Generate the results table from the test runs (builds are ignored). - The table has 3 columns - name, passing and total as a list of dicts. - This is populated for all tests. The number of passing and total is - in reference to the number of iterations or reseeds for that test. - This list of dicts is directly consumed by the Testplan::results_table - method for testplan mapping / annotation. - ''' - for item in items: - if item.status == "F": - fail_msgs += item.fail_msg - - # Generate results table for runs. - if item.target == "run": - result = retrieve_result(item.name, results) - if result is None: - result = {"name": item.name, "passing": 0, "total": 0} - results.append(result) - if item.status == "P": - result["passing"] += 1 - result["total"] += 1 - (results, fail_msgs) = gen_results_sub(item.sub, results, - fail_msgs) - return (results, fail_msgs) - - regr_results = [] - fail_msgs = "" deployed_items = self.deploy - if self.cov: - deployed_items.append(self.cov_merge_deploy) - (regr_results, fail_msgs) = gen_results_sub(deployed_items, - regr_results, fail_msgs) + results = Results(deployed_items, run_results) - # Add title if there are indeed failures - if fail_msgs != "": - fail_msgs = "\n## List of Failures\n" + fail_msgs + # Set a flag if anything failed + if results.fail_msgs: self.errors_seen = True # Generate results table for runs. @@ -648,20 +600,21 @@ class SimCfg(FlowCfg): results_str += "### Simulator: " + self.tool.upper() + "\n\n" - if regr_results == []: + if not results.table: results_str += "No results to display.\n" else: # Map regr results to the testplan entries. results_str += self.testplan.results_table( - regr_results=regr_results, + test_results=results.table, map_full_testplan=self.map_full_testplan) results_str += "\n" self.results_summary = self.testplan.results_summary # Append coverage results of coverage was enabled. - if self.cov: - if self.cov_report_deploy.status == "P": + if self.cov_report_deploy is not None: + report_status = run_results[self.cov_report_deploy] + if report_status == "P": results_str += "\n## Coverage Results\n" # Link the dashboard page using "cov_report_page" value. if hasattr(self, "cov_report_page"): @@ -683,41 +636,48 @@ class SimCfg(FlowCfg): self.results_summary["Name"]) # Append failures for triage - self.results_md = results_str + fail_msgs - results_str += fail_msgs + if results.fail_msgs: + fail_msgs = "\n## List of Failures\n" + ''.join(results.fail_msgs) + results_str += fail_msgs + + self.results_md = results_str # Write results to the scratch area - results_file = self.scratch_path + "/results_" + self.timestamp + ".md" - with open(results_file, 'w') as f: - f.write(self.results_md) + results_path = self.scratch_path + "/results_" + self.timestamp + ".md" + with open(results_path, 'w') as results_file: + results_file.write(self.results_md) - log.log(VERBOSE, "[results page]: [%s] [%s]", self.name, results_file) + # Return only the tables + log.log(VERBOSE, "[results page]: [%s] [%s]", self.name, results_path) return results_str def gen_results_summary(self): # sim summary result has 5 columns from each SimCfg.results_summary header = ["Name", "Passing", "Total", "Pass Rate"] - if self.cov: + if self.cov_report_deploy is not None: header.append('Coverage') - table = [header] + table = [] colalign = ("center", ) * len(header) for item in self.cfgs: row = [] for title in item.results_summary: row.append(item.results_summary[title]) - if row == []: - continue - table.append(row) + if row: + table.append(row) self.results_summary_md = "## " + self.results_title + " (Summary)\n" self.results_summary_md += "### " + self.timestamp_long + "\n" if self.revision: self.results_summary_md += "### " + self.revision + "\n" self.results_summary_md += "### Branch: " + self.branch + "\n" - self.results_summary_md += tabulate(table, - headers="firstrow", - tablefmt="pipe", - colalign=colalign) + if table: + self.results_summary_md += tabulate(table, + headers=header, + tablefmt="pipe", + colalign=colalign) + else: + self.results_summary_md += "\nNo results to display.\n" + print(self.results_summary_md) return self.results_summary_md @@ -725,7 +685,7 @@ class SimCfg(FlowCfg): '''Publish coverage results to the opentitan web server.''' super()._publish_results() - if self.cov: + if self.cov_report_deploy is not None: results_server_dir_url = self.results_server_dir.replace( self.results_server_prefix, self.results_server_url_prefix) diff --git a/vendor/lowrisc_ip/util/dvsim/SynCfg.py b/vendor/lowrisc_ip/util/dvsim/SynCfg.py index 9a118417..719e0fe9 100644 --- a/vendor/lowrisc_ip/util/dvsim/SynCfg.py +++ b/vendor/lowrisc_ip/util/dvsim/SynCfg.py @@ -48,7 +48,7 @@ class SynCfg(OneShotCfg): # Return only the tables return self.results_summary_md - def _gen_results(self): + def _gen_results(self, results): # ''' # The function is called after the regression has completed. It looks # for a regr_results.hjson file with aggregated results from the @@ -135,7 +135,11 @@ class SynCfg(OneShotCfg): entry = "%2.1f %s" % (perc, perctag) else: value = float(val) / norm - entry = "%2.1f" % (value) + if value < 1.0: + entry = "%2.2f" % (value) + else: + entry = "%2.1f" % (value) + else: entry = "--" @@ -219,45 +223,43 @@ class SynCfg(OneShotCfg): if "area" in self.result: header = [ - "Instance", "Comb ", "Buf/Inv", "Regs", "Macros", "Total", - "Total [%]" + "Instance", "Comb ", "Buf/Inv", "Regs", "Logic", "Macros", "Total", + "Logic [%]", "Macro [%]", "Total [%]" ] colalign = ("left", ) + ("center", ) * (len(header) - 1) table = [header] - # print top-level summary first - row = ["**" + self.result["top"] + "**"] try: kge = float(self.result["area"]["ge"]) * 1000.0 - for field in ["comb", "buf", "reg", "macro", "total"]: - row += [ - "**" + - _create_entry(self.result["area"][field], kge) + - "**" - ] - - row += ["**--**"] - table.append(row) - - # go through submodules + # go through submodules. this assumes that the top-level + # is listed before any other modules + totals = [0] * 3 for name in self.result["area"]["instances"].keys(): - if name == self.result["top"]: - continue - row = [name] - for field in ["comb", "buf", "reg", "macro", "total"]: - row += [ + row = [] + is_top = (self.result["area"]["instances"][name]["depth"] == 0) + if is_top: + row = ["**" + name + "**"] + else: + row = [name] + + for field in ["comb", "buf", "reg", "logic", "macro", "total"]: + row.append( _create_entry( self.result["area"]["instances"][name] [field], kge) - ] + ) - # add percentage of total - row += [ - _create_entry( - self.result["area"]["instances"][name][field], - kge, self.result["area"]["total"], "%u") - ] + for k, field in enumerate(["logic", "macro", "total"]): + if is_top: + row.append("**--**") + totals[k] = self.result["area"]["instances"][name][field] + else: + row.append( + _create_entry( + self.result["area"]["instances"][name][field], + kge, totals[k], "%u") + ) table.append(row) @@ -278,7 +280,7 @@ class SynCfg(OneShotCfg): results_str += "### Timing in [ns]\n\n" if "timing" in self.result and "units" in self.result: - header = ["Clock", "Period", "WNS", "TNS"] + header = ["Path Group", "Period", "WNS", "TNS"] colalign = ("left", ) + ("center", ) * (len(header) - 1) table = [header] diff --git a/vendor/lowrisc_ip/util/dvsim/Timer.py b/vendor/lowrisc_ip/util/dvsim/Timer.py new file mode 100644 index 00000000..7447ceb1 --- /dev/null +++ b/vendor/lowrisc_ip/util/dvsim/Timer.py @@ -0,0 +1,56 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +import time + + +class Timer: + '''A timer to keep track of how long jobs have been running + + This has a notion of start time (the time when the object was constructed), + together with a time when the results should next be printed. + + ''' + + print_interval = 5 + + def __init__(self): + self.start = time.monotonic() + self.next_print = self.start + Timer.print_interval + self.first_print = True + + def period(self): + '''Return the float time in seconds since start''' + return time.monotonic() - self.start + + def hms(self): + '''Get the time since start in hh:mm:ss''' + period = self.period() + secs = int(period + 0.5) + mins = secs // 60 + hours = mins // 60 + return '{:02}:{:02}:{:02}'.format(hours, mins % 60, secs % 60) + + def check_time(self): + '''Return true if we have passed next_print. + + If so, increment next_print by print_interval unless the result would + be in the past, in which case set it to the current time plus + print_interval. + + ''' + now = time.monotonic() + + if self.first_print: + self.first_print = False + return True + + if now < self.next_print: + return False + + self.next_print += Timer.print_interval + if self.next_print <= now: + self.next_print = now + Timer.print_interval + + return True diff --git a/vendor/lowrisc_ip/util/dvsim/dvsim.py b/vendor/lowrisc_ip/util/dvsim/dvsim.py index 753d6ffc..8385aed6 100755 --- a/vendor/lowrisc_ip/util/dvsim/dvsim.py +++ b/vendor/lowrisc_ip/util/dvsim/dvsim.py @@ -23,16 +23,17 @@ import argparse import datetime import logging as log import os -import shutil import shlex import subprocess import sys import textwrap -from signal import SIGINT, signal +from pathlib import Path -import Deploy -import utils from CfgFactory import make_cfg +from Deploy import Deploy, RunTest +from Scheduler import Scheduler +from Timer import Timer +from utils import VERBOSE, rm_path, run_cmd_with_timeout # TODO: add dvsim_cfg.hjson to retrieve this info version = 0.1 @@ -58,10 +59,9 @@ def resolve_scratch_root(arg_scratch_root): # Scratch space could be mounted in a filesystem (such as NFS) on a network drive. # If the network is down, it could cause the access access check to hang. So run a # simple ls command with a timeout to prevent the hang. - (out, - status) = utils.run_cmd_with_timeout(cmd="ls -d " + scratch_root, - timeout=1, - exit_on_failure=0) + (out, status) = run_cmd_with_timeout(cmd="ls -d " + scratch_root, + timeout=1, + exit_on_failure=0) if status == 0 and out != "": arg_scratch_root = scratch_root else: @@ -74,13 +74,17 @@ def resolve_scratch_root(arg_scratch_root): arg_scratch_root = os.path.realpath(arg_scratch_root) try: - os.system("mkdir -p " + arg_scratch_root) - except OSError: - log.fatal( - "Invalid --scratch-root=\"%s\" switch - failed to create directory!", - arg_scratch_root) + os.makedirs(arg_scratch_root, exist_ok=True) + except PermissionError as e: + log.fatal("Failed to create scratch root {}:\n{}.".format( + arg_scratch_root, e)) sys.exit(1) - return (arg_scratch_root) + + if not os.access(arg_scratch_root, os.W_OK): + log.fatal("Scratch root {} is not writable!".format(arg_scratch_root)) + sys.exit(1) + + return arg_scratch_root def read_max_parallel(arg): @@ -176,7 +180,7 @@ def resolve_proj_root(args): proj_root_dest = os.path.join(args.scratch_root, args.branch, "repo_top") if args.purge: - shutil.rmtree(proj_root_dest, ignore_errors=True) + rm_path(proj_root_dest) copy_repo(proj_root_src, proj_root_dest, args.dry_run) else: proj_root_dest = proj_root_src @@ -184,14 +188,6 @@ def resolve_proj_root(args): return proj_root_src, proj_root_dest -def sigint_handler(signal_received, frame): - # Kill processes and background jobs. - log.debug('SIGINT or CTRL-C detected. Exiting gracefully') - cfg.kill() - log.info('Exit due to SIGINT or CTRL-C ') - exit(1) - - def copy_repo(src, dest, dry_run): '''Copy over the repo to a new location. @@ -200,17 +196,19 @@ def copy_repo(src, dest, dry_run): exclude patterns to skip certain things from being copied over. With GitHub repos, an existing `.gitignore` serves this purpose pretty well. ''' - rsync_cmd = ["rsync", - "--recursive", "--links", "--checksum", "--update", - "--inplace", "--no-group"] + rsync_cmd = [ + "rsync", "--recursive", "--links", "--checksum", "--update", + "--inplace", "--no-group" + ] # Supply `.gitignore` from the src area to skip temp files. ignore_patterns_file = os.path.join(src, ".gitignore") if os.path.exists(ignore_patterns_file): # TODO: hack - include hw/foundry since it is excluded in .gitignore. - rsync_cmd += ["--include=hw/foundry", - "--exclude-from={}".format(ignore_patterns_file), - "--exclude=.*"] + rsync_cmd += [ + "--include=hw/foundry", + "--exclude-from={}".format(ignore_patterns_file), "--exclude=.*" + ] rsync_cmd += [src + "/.", dest] rsync_str = ' '.join([shlex.quote(w) for w in rsync_cmd]) @@ -218,7 +216,7 @@ def copy_repo(src, dest, dry_run): cmd = ["flock", "--timeout", "600", dest, "--command", rsync_str] log.info("[copy_repo] [dest]: %s", dest) - log.log(utils.VERBOSE, "[copy_repo] [cmd]: \n%s", ' '.join(cmd)) + log.log(VERBOSE, "[copy_repo] [cmd]: \n%s", ' '.join(cmd)) if not dry_run: # Make sure the dest exists first. os.makedirs(dest, exist_ok=True) @@ -588,12 +586,12 @@ def main(): args = parse_args() # Add log level 'VERBOSE' between INFO and DEBUG - log.addLevelName(utils.VERBOSE, 'VERBOSE') + log.addLevelName(VERBOSE, 'VERBOSE') log_format = '%(levelname)s: [%(module)s] %(message)s' log_level = log.INFO if args.verbose == "default": - log_level = utils.VERBOSE + log_level = VERBOSE elif args.verbose == "debug": log_level = log.DEBUG log.basicConfig(format=log_format, level=log_level) @@ -611,6 +609,11 @@ def main(): proj_root_src, proj_root = resolve_proj_root(args) log.info("[proj_root]: %s", proj_root) + # Create an empty FUSESOC_IGNORE file in scratch_root. This ensures that + # any fusesoc invocation from a job won't search within scratch_root for + # core files. + (Path(args.scratch_root) / 'FUSESOC_IGNORE').touch() + args.cfg = os.path.abspath(args.cfg) if args.remote: cfg_path = args.cfg.replace(proj_root_src + "/", "") @@ -629,25 +632,22 @@ def main(): setattr(args, "timestamp", timestamp) # Register the seeds from command line with RunTest class. - Deploy.RunTest.seeds = args.seeds + RunTest.seeds = args.seeds # If we are fixing a seed value, no point in tests having multiple reseeds. if args.fixed_seed: args.reseed = 1 - Deploy.RunTest.fixed_seed = args.fixed_seed + RunTest.fixed_seed = args.fixed_seed # Register the common deploy settings. - Deploy.Deploy.print_interval = args.print_interval - Deploy.Deploy.max_parallel = args.max_parallel - Deploy.Deploy.max_odirs = args.max_odirs + Timer.print_interval = args.print_interval + Scheduler.max_parallel = args.max_parallel + Deploy.max_odirs = args.max_odirs # Build infrastructure from hjson file and create the list of items to # be deployed. global cfg cfg = make_cfg(args.cfg, args, proj_root) - # Handle Ctrl-C exit. - signal(SIGINT, sigint_handler) - # List items available for run if --list switch is passed, and exit. if args.list is not None: cfg.print_list() @@ -675,10 +675,10 @@ def main(): if args.items != []: # Create deploy objects. cfg.create_deploy_objects() - cfg.deploy_objects() + results = cfg.deploy_objects() # Generate results. - cfg.gen_results() + cfg.gen_results(results) # Publish results if args.publish: diff --git a/vendor/lowrisc_ip/util/dvsim/testplanner/class_defs.py b/vendor/lowrisc_ip/util/dvsim/testplanner/class_defs.py index 1c2011ae..c2e38f7a 100644 --- a/vendor/lowrisc_ip/util/dvsim/testplanner/class_defs.py +++ b/vendor/lowrisc_ip/util/dvsim/testplanner/class_defs.py @@ -12,6 +12,14 @@ import mistletoe from tabulate import tabulate +class TestResult: + '''The results for a single test''' + def __init__(self, name): + self.name = name + self.passing = 0 + self.total = 0 + + class TestplanEntry(): """An entry in the testplan @@ -312,10 +320,19 @@ class Testplan(): result = result.replace(">", ">") return result - def results_table(self, regr_results, map_full_testplan=True, fmt="pipe"): + def results_table(self, test_results, map_full_testplan=True, fmt="pipe"): '''Print the mapped regression results into a table in the format specified by the 'fmt' arg. + + test_results should be a list of TestResult objects, one for each named + test. + ''' + # Generate a list of dictionaries as expected by map_regr_results. In + # future, that code could be tightened up to use proper classes too, + # but let's put a shim here for now. + regr_results = [{"name": tr.name, "passing": tr.passing, "total": tr.total} + for tr in test_results] self.map_regr_results(regr_results, map_full_testplan) table = [[ "Milestone", "Name", "Tests", "Passing", "Total", "Pass Rate" diff --git a/vendor/lowrisc_ip/util/dvsim/utils.py b/vendor/lowrisc_ip/util/dvsim/utils.py index d18dd53f..241b3220 100644 --- a/vendor/lowrisc_ip/util/dvsim/utils.py +++ b/vendor/lowrisc_ip/util/dvsim/utils.py @@ -9,6 +9,7 @@ import logging as log import os import re import shlex +import shutil import subprocess import sys import time @@ -103,7 +104,8 @@ def _stringify_wildcard_value(value): try: return ' '.join(_stringify_wildcard_value(x) for x in value) except TypeError: - raise ValueError('Wildcard had value {!r} which is not of a supported type.') + raise ValueError('Wildcard had value {!r} which is not of a supported ' + 'type.'.format(value)) def _subst_wildcards(var, mdict, ignored, ignore_error, seen): @@ -144,13 +146,12 @@ def _subst_wildcards(var, mdict, ignored, ignore_error, seen): # That's not allowed! if name in seen: raise ValueError('String contains circular expansion of ' - 'wildcard {!r}.' - .format(match.group(0))) + 'wildcard {!r}.'.format(match.group(0))) # Treat eval_cmd specially if name == 'eval_cmd': - cmd = _subst_wildcards(right_str[match.end():], - mdict, ignored, ignore_error, seen)[0] + cmd = _subst_wildcards(right_str[match.end():], mdict, ignored, + ignore_error, seen)[0] # Are there any wildcards left in cmd? If not, we can run the # command and we're done. @@ -170,8 +171,7 @@ def _subst_wildcards(var, mdict, ignored, ignore_error, seen): if bad_names: raise ValueError('Cannot run eval_cmd because the command ' 'expands to {!r}, which still contains a ' - 'wildcard.' - .format(cmd)) + 'wildcard.'.format(cmd)) # We can't run the command (because it still has wildcards), but we # don't want to report an error either because ignore_error is true @@ -193,20 +193,19 @@ def _subst_wildcards(var, mdict, ignored, ignore_error, seen): continue raise ValueError('String to be expanded contains ' - 'unknown wildcard, {!r}.' - .format(match.group(0))) + 'unknown wildcard, {!r}.'.format(match.group(0))) value = _stringify_wildcard_value(value) # Do any recursive expansion of value, adding name to seen (to avoid # circular recursion). - value, saw_err = _subst_wildcards(value, mdict, - ignored, ignore_error, seen + [name]) + value, saw_err = _subst_wildcards(value, mdict, ignored, ignore_error, + seen + [name]) # Replace the original match with the result and go around again. If # saw_err, increment idx past what we just inserted. - var = (var[:idx] + - right_str[:match.start()] + value + right_str[match.end():]) + var = (var[:idx] + right_str[:match.start()] + value + + right_str[match.end():]) if saw_err: any_err = True idx += match.start() + len(value) @@ -279,7 +278,8 @@ def subst_wildcards(var, mdict, ignored_wildcards=[], ignore_error=False): ''' try: - return _subst_wildcards(var, mdict, ignored_wildcards, ignore_error, [])[0] + return _subst_wildcards(var, mdict, ignored_wildcards, ignore_error, + [])[0] except ValueError as err: log.error(str(err)) sys.exit(1) @@ -518,3 +518,26 @@ def print_msg_list(msg_list_title, msg_list, max_msg_count=-1): break md_results += "```\n" return md_results + + +def rm_path(path, ignore_error=False): + '''Removes the specified path if it exists. + + 'path' is a Path-like object. If it does not exist, the function simply + returns. If 'ignore_error' is set, then exception caught by the remove + operation is raised, else it is ignored. + ''' + + try: + if os.path.islink(path): + os.remove(path) + elif os.path.isdir(path): + shutil.rmtree(path) + else: + os.remove(path) + except FileNotFoundError: + pass + except OSError as e: + log.error("Failed to remove {}:\n{}.".format(path, e)) + if not ignore_error: + raise e diff --git a/vendor/lowrisc_ip/util/uvmdvgen/env.sv.tpl b/vendor/lowrisc_ip/util/uvmdvgen/env.sv.tpl index 230a6123..cb2f1853 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/env.sv.tpl +++ b/vendor/lowrisc_ip/util/uvmdvgen/env.sv.tpl @@ -28,6 +28,7 @@ class ${name}_env extends dv_base_env #( // create components m_${agent}_agent = ${agent}_agent::type_id::create("m_${agent}_agent", this); uvm_config_db#(${agent}_agent_cfg)::set(this, "m_${agent}_agent*", "cfg", cfg.m_${agent}_agent_cfg); + cfg.m_${agent}_agent_cfg.en_cov = cfg.en_cov; % endfor endfunction diff --git a/vendor/lowrisc_ip/util/uvmdvgen/env_pkg.sv.tpl b/vendor/lowrisc_ip/util/uvmdvgen/env_pkg.sv.tpl index d03af31c..af451a33 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/env_pkg.sv.tpl +++ b/vendor/lowrisc_ip/util/uvmdvgen/env_pkg.sv.tpl @@ -16,6 +16,7 @@ package ${name}_env_pkg; import cip_base_pkg::*; % endif % if has_ral: + import dv_base_reg_pkg::*; import csr_utils_pkg::*; import ${name}_ral_pkg::*; % endif diff --git a/vendor/lowrisc_ip/util/uvmdvgen/tb.sv.tpl b/vendor/lowrisc_ip/util/uvmdvgen/tb.sv.tpl index 9e0f0bf8..7eab5ea2 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/tb.sv.tpl +++ b/vendor/lowrisc_ip/util/uvmdvgen/tb.sv.tpl @@ -33,13 +33,14 @@ module tb; % for agent in env_agents: ${agent}_if ${agent}_if(); % endfor -% if has_edn: - push_pull_if #(.DeviceDataWidth(cip_base_pkg::EDN_DATA_WIDTH)) edn_if(.clk(clk), .rst_n(rst_n)); -% endif % if has_alerts: `DV_ALERT_IF_CONNECT % endif +% if has_edn: + // edn_clk, edn_rst_n and edn_if are defined and driven in below macro + `DV_EDN_IF_CONNECT +% endif // dut ${name} dut ( @@ -48,12 +49,14 @@ module tb; .rst_ni (rst_n )${"," if is_cip else ""} .tl_i (tl_if.h2d), - .tl_o (tl_if.d2h)${"," if has_alert or has_edn else ""} + .tl_o (tl_if.d2h)${"," if has_alerts or has_edn else ""} % if has_alerts: .alert_rx_i (alert_rx ), .alert_tx_o (alert_tx )${"," if has_edn else ""} % endif % if has_edn: + .clk_edn_i (edn_clk ), + .rst_edn_ni (edn_rst_n ), .edn_o (edn_if.req), .edn_i ({edn_if.ack, edn_if.d_data}) % endif @@ -75,10 +78,6 @@ module tb; % for agent in env_agents: uvm_config_db#(virtual ${agent}_if)::set(null, "*.env.m_${agent}_agent*", "vif", ${agent}_if); % endfor -% if has_edn: - uvm_config_db#(virtual push_pull_if#(.DeviceDataWidth(cip_base_pkg::EDN_DATA_WIDTH)))::set - (null, "*env.m_edn_pull_agent*", "vif", edn_if); -% endif $timeformat(-12, 0, " ps", 12); run_test(); end