Update code from upstream repository
https://github.com/lowRISC/opentitan to revision
1ae03937f0bb4b146bb6e736bccb4821bfda556b

* [prim/fifo_async] Add assertions on pointers (Tom Roberts)
* [prim/fifo_async] Add support for Depth <= 2 (Tom Roberts)
* [prim/fifo_async] Code tidy-up (Tom Roberts)
* [top / ast] Continued ast integration (Timothy Chen)
* [dvsim] Use bash when running make underneath (Srikrishna Iyer)
* [prim] Increase maximum width for prim_util_memload to 312 (Greg
  Chadwick)
* [sram_ctrl] Fix potential back-to-back partial write bug (Michael
  Schaffner)
* [dvsim] Fix for lowRISC/opentitan#5527 (Srikrishna Iyer)
* [lint] Waive Verilator UNUSED warnings for packages (Rupert
  Swarbrick)
* [uvmdvgen] Update DV doc path and terminology (Srikrishna Iyer)
* [clkmgr] Fix dft issues (Timothy Chen)
* [util] add `dec` types to prim_secded_pkg (Udi Jonnalagadda)
* [util] minor updates to secded_gen (Udi Jonnalagadda)
* [lint] Fix a bunch of lint warnings related to long lines (>100
  chars) (Michael Schaffner)
* [dv] Update common intr_test seq (Weicai Yang)
* [util] Slight refactor of secded_gen.py (Timothy Chen)
* [tlul] Add memory transmission integrity checks (Timothy Chen)
* [dvsim] Move clean_odirs to `util.py` (Srikrishna Iyer)
* [dvsim] Split Deploy into Deploy and Launcher (Srikrishna Iyer)
* [dvsim] Add utils.TS_FORMAT* vars (Srikrishna Iyer)
* [dv/lock_reg] Update IPs to adopt the lock_reg changes (Cindy Chen)
* [dv/enable_regs] Support enable registers have more than one field
  (Cindy Chen)
* [dv/base_reg] use m_field instead of accessing field (Cindy Chen)
* [dv/sram] add SRAM scrambling model for DV (Udi Jonnalagadda)
* [dv/tools] Updated Coverage flow for xcelium (Rasmus Madsen)

Signed-off-by: Tom Roberts <tomroberts@lowrisc.org>
This commit is contained in:
Tom Roberts 2021-03-12 13:19:17 +00:00 committed by Tom Roberts
parent 50f09b71a9
commit 2c75c2b2ec
86 changed files with 2471 additions and 1178 deletions

View file

@ -33,6 +33,7 @@ Instantiation Template
.clk_i (),
.rst_ni (),
.test_en_i (),
.ram_cfg_i (),
// Configuration
.hart_id_i (),
@ -158,6 +159,9 @@ Interfaces
+-------------------------+-------------------------+-----+----------------------------------------+
| ``test_en_i`` | 1 | in | Test input, enables clock |
+-------------------------+-------------------------+-----+----------------------------------------+
| ``ram_cfg_i`` | 10 | in | RAM configuration inputs, routed to |
| | | | the icache RAMs |
+-------------------------+-------------------------+-----+----------------------------------------+
| ``hart_id_i`` | 32 | in | Hart ID, usually static, can be read |
| | | | from :ref:`csr-mhartid` CSR |
+-------------------------+-------------------------+-----+----------------------------------------+

View file

@ -132,6 +132,7 @@ module ibex_riscv_compliance (
.rst_ni (rst_sys_n ),
.test_en_i ('b0 ),
.ram_cfg_i ('b0 ),
.hart_id_i (32'b0 ),
// First instruction executed is at 0x0 + 0x80

View file

@ -8,7 +8,7 @@
// Its contents are taken from the file which would be generated by FuseSoC.
// https://github.com/lowRISC/ibex/issues/893
module prim_ram_1p
module prim_ram_1p import prim_ram_1p_pkg::*;
#(
@ -21,6 +21,7 @@ module prim_ram_1p
) (
input logic clk_i,
input ram_1p_cfg_t cfg_i,
input logic req_i,
input logic write_i,

View file

@ -28,6 +28,7 @@ ${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_72_64_dec.sv
// wrappers around the prim_* modules to instantiate the prim_generic_* ones,
// see https://github.com/lowRISC/ibex/issues/893.
${PRJ_DIR}/dv/uvm/core_ibex/common/prim/prim_pkg.sv
${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1p_pkg.sv
${PRJ_DIR}/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_ram_1p.sv
${PRJ_DIR}/dv/uvm/core_ibex/common/prim/prim_ram_1p.sv
${PRJ_DIR}/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_gating.sv

View file

@ -78,6 +78,7 @@ module core_ibex_tb_top;
.rst_ni (rst_n ),
.test_en_i (1'b0 ),
.ram_cfg_i (1'b0 ),
.hart_id_i (32'b0 ),
.boot_addr_i (32'h`BOOT_ADDR ), // align with spike boot address

View file

@ -38,6 +38,7 @@ module prim_badbit_ram_1p #(
) u_mem (
.clk_i (clk_i),
.cfg_i ('0),
.req_i (req_i),
.write_i (write_i),
.addr_i (addr_i),

View file

@ -41,6 +41,7 @@ module tb #(parameter bit ICacheECC = 1'b0);
.addr_o (core_if.addr),
.err_o (core_if.err),
.err_plus2_o (core_if.err_plus2),
.ram_cfg_i ('0),
.icache_enable_i (core_if.enable),
.icache_inval_i (core_if.invalidate),
.busy_o (core_if.busy),

View file

@ -51,6 +51,7 @@ module top_artya7 (
.rst_ni (rst_sys_n),
.test_en_i ('b0),
.ram_cfg_i ('b0),
.hart_id_i (32'b0),
// First instruction executed is at 0x0 + 0x80

View file

@ -183,6 +183,7 @@ module ibex_simple_system (
.rst_ni (rst_sys_n),
.test_en_i ('b0),
.ram_cfg_i ('b0),
.hart_id_i (32'b0),
// First instruction executed is at 0x0 + 0x80

View file

@ -34,78 +34,79 @@ module ibex_core #(
parameter int unsigned DmExceptionAddr = 32'h1A110808
) (
// Clock and Reset
input logic clk_i,
input logic rst_ni,
input logic clk_i,
input logic rst_ni,
input logic test_en_i, // enable all clock gates for testing
input logic test_en_i, // enable all clock gates for testing
input prim_ram_1p_pkg::ram_1p_cfg_t ram_cfg_i,
input logic [31:0] hart_id_i,
input logic [31:0] boot_addr_i,
input logic [31:0] hart_id_i,
input logic [31:0] boot_addr_i,
// Instruction memory interface
output logic instr_req_o,
input logic instr_gnt_i,
input logic instr_rvalid_i,
output logic [31:0] instr_addr_o,
input logic [31:0] instr_rdata_i,
input logic instr_err_i,
output logic instr_req_o,
input logic instr_gnt_i,
input logic instr_rvalid_i,
output logic [31:0] instr_addr_o,
input logic [31:0] instr_rdata_i,
input logic instr_err_i,
// Data memory interface
output logic data_req_o,
input logic data_gnt_i,
input logic data_rvalid_i,
output logic data_we_o,
output logic [3:0] data_be_o,
output logic [31:0] data_addr_o,
output logic [31:0] data_wdata_o,
input logic [31:0] data_rdata_i,
input logic data_err_i,
output logic data_req_o,
input logic data_gnt_i,
input logic data_rvalid_i,
output logic data_we_o,
output logic [3:0] data_be_o,
output logic [31:0] data_addr_o,
output logic [31:0] data_wdata_o,
input logic [31:0] data_rdata_i,
input logic data_err_i,
// Interrupt inputs
input logic irq_software_i,
input logic irq_timer_i,
input logic irq_external_i,
input logic [14:0] irq_fast_i,
input logic irq_nm_i, // non-maskeable interrupt
input logic irq_software_i,
input logic irq_timer_i,
input logic irq_external_i,
input logic [14:0] irq_fast_i,
input logic irq_nm_i, // non-maskeable interrupt
// Debug Interface
input logic debug_req_i,
output ibex_pkg::crash_dump_t crash_dump_o,
input logic debug_req_i,
output ibex_pkg::crash_dump_t crash_dump_o,
// RISC-V Formal Interface
// Does not comply with the coding standards of _i/_o suffixes, but follows
// the convention of RISC-V Formal Interface Specification.
`ifdef RVFI
output logic rvfi_valid,
output logic [63:0] rvfi_order,
output logic [31:0] rvfi_insn,
output logic rvfi_trap,
output logic rvfi_halt,
output logic rvfi_intr,
output logic [ 1:0] rvfi_mode,
output logic [ 1:0] rvfi_ixl,
output logic [ 4:0] rvfi_rs1_addr,
output logic [ 4:0] rvfi_rs2_addr,
output logic [ 4:0] rvfi_rs3_addr,
output logic [31:0] rvfi_rs1_rdata,
output logic [31:0] rvfi_rs2_rdata,
output logic [31:0] rvfi_rs3_rdata,
output logic [ 4:0] rvfi_rd_addr,
output logic [31:0] rvfi_rd_wdata,
output logic [31:0] rvfi_pc_rdata,
output logic [31:0] rvfi_pc_wdata,
output logic [31:0] rvfi_mem_addr,
output logic [ 3:0] rvfi_mem_rmask,
output logic [ 3:0] rvfi_mem_wmask,
output logic [31:0] rvfi_mem_rdata,
output logic [31:0] rvfi_mem_wdata,
output logic rvfi_valid,
output logic [63:0] rvfi_order,
output logic [31:0] rvfi_insn,
output logic rvfi_trap,
output logic rvfi_halt,
output logic rvfi_intr,
output logic [ 1:0] rvfi_mode,
output logic [ 1:0] rvfi_ixl,
output logic [ 4:0] rvfi_rs1_addr,
output logic [ 4:0] rvfi_rs2_addr,
output logic [ 4:0] rvfi_rs3_addr,
output logic [31:0] rvfi_rs1_rdata,
output logic [31:0] rvfi_rs2_rdata,
output logic [31:0] rvfi_rs3_rdata,
output logic [ 4:0] rvfi_rd_addr,
output logic [31:0] rvfi_rd_wdata,
output logic [31:0] rvfi_pc_rdata,
output logic [31:0] rvfi_pc_wdata,
output logic [31:0] rvfi_mem_addr,
output logic [ 3:0] rvfi_mem_rmask,
output logic [ 3:0] rvfi_mem_wmask,
output logic [31:0] rvfi_mem_rdata,
output logic [31:0] rvfi_mem_wdata,
`endif
// CPU Control Signals
input logic fetch_enable_i,
output logic alert_minor_o,
output logic alert_major_o,
output logic core_sleep_o
input logic fetch_enable_i,
output logic alert_minor_o,
output logic alert_major_o,
output logic core_sleep_o
);
import ibex_pkg::*;
@ -411,6 +412,7 @@ module ibex_core #(
.clk_i ( clk ),
.rst_ni ( rst_ni ),
.ram_cfg_i ( ram_cfg_i ),
.boot_addr_i ( boot_addr_i ),
.req_i ( instr_req_int ), // instruction request control

View file

@ -28,49 +28,51 @@ module ibex_core_tracing #(
parameter int unsigned DmExceptionAddr = 32'h1A110808
) (
// Clock and Reset
input logic clk_i,
input logic rst_ni,
input logic clk_i,
input logic rst_ni,
input logic test_en_i, // enable all clock gates for testing
input logic test_en_i, // enable all clock gates for testing
input prim_ram_1p_pkg::ram_1p_cfg_t ram_cfg_i,
input logic [31:0] hart_id_i,
input logic [31:0] boot_addr_i,
input logic [31:0] hart_id_i,
input logic [31:0] boot_addr_i,
// Instruction memory interface
output logic instr_req_o,
input logic instr_gnt_i,
input logic instr_rvalid_i,
output logic [31:0] instr_addr_o,
input logic [31:0] instr_rdata_i,
input logic instr_err_i,
output logic instr_req_o,
input logic instr_gnt_i,
input logic instr_rvalid_i,
output logic [31:0] instr_addr_o,
input logic [31:0] instr_rdata_i,
input logic instr_err_i,
// Data memory interface
output logic data_req_o,
input logic data_gnt_i,
input logic data_rvalid_i,
output logic data_we_o,
output logic [3:0] data_be_o,
output logic [31:0] data_addr_o,
output logic [31:0] data_wdata_o,
input logic [31:0] data_rdata_i,
input logic data_err_i,
output logic data_req_o,
input logic data_gnt_i,
input logic data_rvalid_i,
output logic data_we_o,
output logic [3:0] data_be_o,
output logic [31:0] data_addr_o,
output logic [31:0] data_wdata_o,
input logic [31:0] data_rdata_i,
input logic data_err_i,
// Interrupt inputs
input logic irq_software_i,
input logic irq_timer_i,
input logic irq_external_i,
input logic [14:0] irq_fast_i,
input logic irq_nm_i, // non-maskeable interrupt
input logic irq_software_i,
input logic irq_timer_i,
input logic irq_external_i,
input logic [14:0] irq_fast_i,
input logic irq_nm_i, // non-maskeable interrupt
// Debug Interface
input logic debug_req_i,
output ibex_pkg::crash_dump_t crash_dump_o,
input logic debug_req_i,
output ibex_pkg::crash_dump_t crash_dump_o,
// CPU Control Signals
input logic fetch_enable_i,
output logic alert_minor_o,
output logic alert_major_o,
output logic core_sleep_o
input logic fetch_enable_i,
output logic alert_minor_o,
output logic alert_major_o,
output logic core_sleep_o
);
@ -130,6 +132,7 @@ module ibex_core_tracing #(
.rst_ni,
.test_en_i,
.ram_cfg_i,
.hart_id_i,
.boot_addr_i,

View file

@ -22,40 +22,41 @@ module ibex_icache #(
parameter bit BranchCache = 1'b0
) (
// Clock and reset
input logic clk_i,
input logic rst_ni,
input logic clk_i,
input logic rst_ni,
// Signal that the core would like instructions
input logic req_i,
input logic req_i,
// Set the cache's address counter
input logic branch_i,
input logic branch_spec_i,
input logic predicted_branch_i,
input logic branch_mispredict_i,
input logic [31:0] addr_i,
input logic branch_i,
input logic branch_spec_i,
input logic predicted_branch_i,
input logic branch_mispredict_i,
input logic [31:0] addr_i,
// IF stage interface: Pass fetched instructions to the core
input logic ready_i,
output logic valid_o,
output logic [31:0] rdata_o,
output logic [31:0] addr_o,
output logic err_o,
output logic err_plus2_o,
input logic ready_i,
output logic valid_o,
output logic [31:0] rdata_o,
output logic [31:0] addr_o,
output logic err_o,
output logic err_plus2_o,
// Instruction memory / interconnect interface: Fetch instruction data from memory
output logic instr_req_o,
input logic instr_gnt_i,
output logic [31:0] instr_addr_o,
input logic [BusWidth-1:0] instr_rdata_i,
input logic instr_err_i,
input logic instr_pmp_err_i,
input logic instr_rvalid_i,
output logic instr_req_o,
input logic instr_gnt_i,
output logic [31:0] instr_addr_o,
input logic [BusWidth-1:0] instr_rdata_i,
input logic instr_err_i,
input logic instr_pmp_err_i,
input logic instr_rvalid_i,
// Cache status
input logic icache_enable_i,
input logic icache_inval_i,
output logic busy_o
input prim_ram_1p_pkg::ram_1p_cfg_t ram_cfg_i,
input logic icache_enable_i,
input logic icache_inval_i,
output logic busy_o
);
// Local constants
localparam int unsigned ADDR_W = 32;
@ -338,6 +339,7 @@ module ibex_icache #(
) tag_bank (
.clk_i (clk_i),
.req_i (tag_req_ic0 & tag_banks_ic0[way]),
.cfg_i (ram_cfg_i),
.write_i (tag_write_ic0),
.wmask_i ({TAG_SIZE_ECC{1'b1}}),
.addr_i (tag_index_ic0),
@ -352,6 +354,7 @@ module ibex_icache #(
) data_bank (
.clk_i (clk_i),
.req_i (data_req_ic0 & data_banks_ic0[way]),
.cfg_i (ram_cfg_i),
.write_i (data_write_ic0),
.wmask_i ({LINE_SIZE_ECC{1'b1}}),
.addr_i (data_index_ic0),

View file

@ -21,76 +21,77 @@ module ibex_if_stage #(
parameter bit PCIncrCheck = 1'b0,
parameter bit BranchPredictor = 1'b0
) (
input logic clk_i,
input logic rst_ni,
input logic clk_i,
input logic rst_ni,
input logic [31:0] boot_addr_i, // also used for mtvec
input logic req_i, // instruction request control
input prim_ram_1p_pkg::ram_1p_cfg_t ram_cfg_i,
input logic [31:0] boot_addr_i, // also used for mtvec
input logic req_i, // instruction request control
// instruction cache interface
output logic instr_req_o,
output logic [31:0] instr_addr_o,
input logic instr_gnt_i,
input logic instr_rvalid_i,
input logic [31:0] instr_rdata_i,
input logic instr_err_i,
input logic instr_pmp_err_i,
output logic instr_req_o,
output logic [31:0] instr_addr_o,
input logic instr_gnt_i,
input logic instr_rvalid_i,
input logic [31:0] instr_rdata_i,
input logic instr_err_i,
input logic instr_pmp_err_i,
// output of ID stage
output logic instr_valid_id_o, // instr in IF-ID is valid
output logic instr_new_id_o, // instr in IF-ID is new
output logic [31:0] instr_rdata_id_o, // instr for ID stage
output logic [31:0] instr_rdata_alu_id_o, // replicated instr for ID stage
// to reduce fan-out
output logic [15:0] instr_rdata_c_id_o, // compressed instr for ID stage
// (mtval), meaningful only if
// instr_is_compressed_id_o = 1'b1
output logic instr_is_compressed_id_o, // compressed decoder thinks this
// is a compressed instr
output logic instr_bp_taken_o, // instruction was predicted to be
// a taken branch
output logic instr_fetch_err_o, // bus error on fetch
output logic instr_fetch_err_plus2_o, // bus error misaligned
output logic illegal_c_insn_id_o, // compressed decoder thinks this
// is an invalid instr
output logic dummy_instr_id_o, // Instruction is a dummy
output logic [31:0] pc_if_o,
output logic [31:0] pc_id_o,
output logic instr_valid_id_o, // instr in IF-ID is valid
output logic instr_new_id_o, // instr in IF-ID is new
output logic [31:0] instr_rdata_id_o, // instr for ID stage
output logic [31:0] instr_rdata_alu_id_o, // replicated instr for ID stage
// to reduce fan-out
output logic [15:0] instr_rdata_c_id_o, // compressed instr for ID stage
// (mtval), meaningful only if
// instr_is_compressed_id_o = 1'b1
output logic instr_is_compressed_id_o, // compressed decoder thinks this
// is a compressed instr
output logic instr_bp_taken_o, // instruction was predicted to be
// a taken branch
output logic instr_fetch_err_o, // bus error on fetch
output logic instr_fetch_err_plus2_o, // bus error misaligned
output logic illegal_c_insn_id_o, // compressed decoder thinks this
// is an invalid instr
output logic dummy_instr_id_o, // Instruction is a dummy
output logic [31:0] pc_if_o,
output logic [31:0] pc_id_o,
// control signals
input logic instr_valid_clear_i, // clear instr valid bit in IF-ID
input logic pc_set_i, // set the PC to a new value
input logic pc_set_spec_i,
input ibex_pkg::pc_sel_e pc_mux_i, // selector for PC multiplexer
input logic nt_branch_mispredict_i, // Not-taken branch in ID/EX was
// mispredicted (predicted taken)
input ibex_pkg::exc_pc_sel_e exc_pc_mux_i, // selects ISR address
input ibex_pkg::exc_cause_e exc_cause, // selects ISR address for
// vectorized interrupt lines
input logic dummy_instr_en_i,
input logic [2:0] dummy_instr_mask_i,
input logic dummy_instr_seed_en_i,
input logic [31:0] dummy_instr_seed_i,
input logic icache_enable_i,
input logic icache_inval_i,
input logic instr_valid_clear_i, // clear instr valid bit in IF-ID
input logic pc_set_i, // set the PC to a new value
input logic pc_set_spec_i,
input ibex_pkg::pc_sel_e pc_mux_i, // selector for PC multiplexer
input logic nt_branch_mispredict_i, // Not-taken branch in ID/EX was
// mispredicted (predicted taken)
input ibex_pkg::exc_pc_sel_e exc_pc_mux_i, // selects ISR address
input ibex_pkg::exc_cause_e exc_cause, // selects ISR address for
// vectorized interrupt lines
input logic dummy_instr_en_i,
input logic [2:0] dummy_instr_mask_i,
input logic dummy_instr_seed_en_i,
input logic [31:0] dummy_instr_seed_i,
input logic icache_enable_i,
input logic icache_inval_i,
// jump and branch target
input logic [31:0] branch_target_ex_i, // branch/jump target address
input logic [31:0] branch_target_ex_i, // branch/jump target address
// CSRs
input logic [31:0] csr_mepc_i, // PC to restore after handling
// the interrupt/exception
input logic [31:0] csr_depc_i, // PC to restore after handling
// the debug request
input logic [31:0] csr_mtvec_i, // base PC to jump to on exception
output logic csr_mtvec_init_o, // tell CS regfile to init mtvec
input logic [31:0] csr_mepc_i, // PC to restore after handling
// the interrupt/exception
input logic [31:0] csr_depc_i, // PC to restore after handling
// the debug request
input logic [31:0] csr_mtvec_i, // base PC to jump to on exception
output logic csr_mtvec_init_o, // tell CS regfile to init mtvec
// pipeline stall
input logic id_in_ready_i, // ID stage is ready for new instr
input logic id_in_ready_i, // ID stage is ready for new instr
// misc signals
output logic pc_mismatch_alert_o,
output logic if_busy_o // IF stage is busy fetching instr
output logic pc_mismatch_alert_o,
output logic if_busy_o // IF stage is busy fetching instr
);
import ibex_pkg::*;
@ -213,6 +214,7 @@ module ibex_if_stage #(
.instr_err_i ( instr_err_i ),
.instr_pmp_err_i ( instr_pmp_err_i ),
.ram_cfg_i ( ram_cfg_i ),
.icache_enable_i ( icache_enable_i ),
.icache_inval_i ( icache_inval_i ),
.busy_o ( prefetch_busy )
@ -252,8 +254,10 @@ module ibex_if_stage #(
);
// ICache tieoffs
logic unused_icen, unused_icinv;
assign unused_icen = icache_enable_i;
assign unused_icinv = icache_inval_i;
prim_ram_1p_pkg::ram_1p_cfg_t unused_ram_cfg;
assign unused_icen = icache_enable_i;
assign unused_icinv = icache_inval_i;
assign unused_ram_cfg = ram_cfg_i;
end
assign unused_fetch_addr_n0 = fetch_addr_n[0];

View file

@ -58,6 +58,7 @@ module ram_1p #(
.MemInitFile(MemInitFile)
) u_ram (
.clk_i (clk_i),
.cfg_i ('0),
.req_i (req_i),
.write_i (we_i),
.wmask_i (wmask),

View file

@ -72,6 +72,7 @@ module ram_2p #(
) u_ram (
.clk_a_i (clk_i),
.clk_b_i (clk_i),
.cfg_i ('0),
.a_req_i (a_req_i),
.a_write_i (a_we_i),
.a_addr_i (a_addr_idx),

View file

@ -9,6 +9,6 @@
upstream:
{
url: https://github.com/lowRISC/opentitan
rev: 6cc5c164ba96d339f06cbcede0d17d2c96ce3c05
rev: 1ae03937f0bb4b146bb6e736bccb4821bfda556b
}
}

View file

@ -8,7 +8,6 @@ class dv_base_reg extends uvm_reg;
// hence, backdoor write isn't available
local bit is_ext_reg;
local dv_base_reg locked_regs[$];
local uvm_reg_data_t staged_shadow_val, committed_val, shadowed_val;
local bit is_shadowed;
local bit shadow_wr_staged; // stage the first shadow reg write
@ -36,61 +35,103 @@ class dv_base_reg extends uvm_reg;
endfunction : new
function void get_dv_base_reg_fields(ref dv_base_reg_field dv_fields[$]);
uvm_reg_field ral_fields[$];
get_fields(ral_fields);
foreach (ral_fields[i]) `downcast(dv_fields[i], ral_fields[i])
foreach (m_fields[i]) `downcast(dv_fields[i], m_fields[i])
endfunction
// get_n_bits will return number of all the bits in the csr
// while this function will return actual number of bits used in reg field
function uint get_n_used_bits();
uvm_reg_field fields[$];
get_fields(fields);
foreach (fields[i]) get_n_used_bits += fields[i].get_n_bits();
foreach (m_fields[i]) get_n_used_bits += m_fields[i].get_n_bits();
endfunction
// loop all the fields to find the msb position of this reg
function uint get_msb_pos();
uvm_reg_field fields[$];
get_fields(fields);
foreach (fields[i]) begin
uint field_msb_pos = fields[i].get_lsb_pos() + fields[i].get_n_bits() - 1;
foreach (m_fields[i]) begin
uint field_msb_pos = m_fields[i].get_lsb_pos() + m_fields[i].get_n_bits() - 1;
if (field_msb_pos > get_msb_pos) get_msb_pos = field_msb_pos;
end
endfunction
// if the register is an enable reg, it will add controlled registers in the queue
function void add_locked_reg(dv_base_reg locked_reg);
locked_regs.push_back(locked_reg);
virtual function dv_base_reg_field get_dv_base_reg_field_by_name(string fld_name,
bit check_fld_exist = 1'b1);
uvm_reg_field fld = get_field_by_name(fld_name);
dv_base_reg_field dv_fld;
`downcast(dv_fld, fld)
if (check_fld_exist) begin
`DV_CHECK_NE_FATAL(dv_fld, null,
$sformatf("%0s does not exist in reg %0s", fld_name, get_full_name()))
end
return dv_fld;
endfunction
function bit is_inside_locked_regs(dv_base_reg csr);
if (csr inside {locked_regs}) return 1;
else return 0;
// this function can only be called when this reg is intr_state reg
// Example: ral.intr_state.get_intr_pins_exp_value(). And it returns value of
// intr_state & intr_enable, which represents value of interrupt pins
virtual function uvm_reg_data_t get_intr_pins_exp_value();
uvm_reg_block blk = get_parent();
uvm_reg intr_enable_csr;
string intr_enable_csr_name;
bit is_intr_state_csr = !(uvm_re_match("intr_state*", get_name()));
`DV_CHECK_EQ_FATAL(is_intr_state_csr, 1)
// intr_enable and intr_state have the same suffix
intr_enable_csr_name = str_utils_pkg::str_replace(get_name(), "state", "enable");
intr_enable_csr = blk.get_reg_by_name(intr_enable_csr_name);
// some interrupts may not have intr_enable
if (intr_enable_csr != null) begin
return get_mirrored_value() & intr_enable_csr.get_mirrored_value();
end else begin
return get_mirrored_value();
end
endfunction
function bit is_enable_reg();
return (locked_regs.size() > 0);
// Wen reg/fld can lock specific groups of fields' write acces. The lockable fields are called
// lockable flds.
function void add_lockable_reg_or_fld(uvm_object lockable_obj);
dv_base_reg_field wen_fld;
`DV_CHECK_FATAL(m_fields.size(), 1, "This register has more than one field.\
Please use register field's add_lockable_reg_or_fld() method instead.")
`downcast(wen_fld, m_fields[0])
wen_fld.add_lockable_reg_or_fld(lockable_obj);
endfunction
// Returns true if this register/field can lock the specified register/field, else return false.
function bit locks_reg_or_fld(uvm_object obj);
dv_base_reg_field wen_fld;
`DV_CHECK_FATAL(m_fields.size(), 1, "This register has more than one field.\
Please use register field's locks_reg_or_fld() method instead.")
`downcast(wen_fld, m_fields[0])
return wen_fld.locks_reg_or_fld(obj);
endfunction
// Even though user can add lockable register or field via `add_lockable_reg_or_fld` method, the
// get_lockable_flds function will always return a queue of lockable fields.
function void get_lockable_flds(ref dv_base_reg_field lockable_flds_q[$]);
dv_base_reg_field wen_fld;
`DV_CHECK_FATAL(m_fields.size(), 1, "This register has more than one field.\
Please use register field's get_lockable_flds() method instead.")
`downcast(wen_fld, m_fields[0])
wen_fld.get_lockable_flds(lockable_flds_q);
endfunction
// The register is a write enable register (wen_reg) if its fields are wen_flds.
function bit is_wen_reg();
foreach (m_fields[i]) begin
dv_base_reg_field fld;
`downcast(fld, m_fields[i])
if (fld.is_wen_fld()) return 1;
end
return 0;
endfunction
function bit is_staged();
return shadow_wr_staged;
endfunction
// if enable register is set to 1, the locked registers will be set to RO access
// once enable register is reset to 0, the locked registers will be set back to original access
function void set_locked_regs_access(string access = "original_access");
foreach (locked_regs[i]) begin
dv_base_reg_field locked_fields[$];
locked_regs[i].get_dv_base_reg_fields(locked_fields);
foreach (locked_fields[i]) locked_fields[i].set_locked_fields_access(access);
end
endfunction
function void get_locked_regs(ref dv_base_reg locked_regs_q[$]);
locked_regs_q = locked_regs;
endfunction
// is_shadowed bit is only one-time programmable
// once this function is called in RAL auto-generated class, it cannot be changed
function void set_is_shadowed();
@ -134,8 +175,8 @@ class dv_base_reg extends uvm_reg;
endfunction
// post_write callback to handle special regs:
// - shadow register, enable reg won't be updated until the second write has no error
// - enable register, if enable_reg is disabled, change access policy to all the locked_regs
// - shadow register: shadow reg won't be updated until the second write has no error
// - lock register: if wen_fld is set to 0, change access policy to all the lockable_flds
// TODO: create an `enable_field_access_policy` variable and set the template code during
// automation.
virtual task post_write(uvm_reg_item rw);
@ -162,17 +203,23 @@ class dv_base_reg extends uvm_reg;
shadowed_val = ~committed_val;
end
end
if (is_enable_reg()) begin
get_dv_base_reg_fields(fields);
field_access = fields[0].get_access();
case (field_access)
// rw.value is a dynamic array
// 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))
endcase
if (is_wen_reg()) begin
foreach (m_fields[i]) begin
dv_base_reg_field fld;
`downcast(fld, m_fields[i])
if (fld.is_wen_fld()) begin
// rw.value is a dynamic array
uvm_reg_data_t field_val = rw.value[0] & fld.get_field_mask();
field_access = fld.get_access();
case (field_access)
// discussed in issue #1922: enable register is standarized to W0C or RO (if HW has
// write access).
"W0C": if (field_val == 1'b0) fld.set_lockable_flds_access(1);
"RO": ; // if RO, it's updated by design, need to predict in scb
default:`uvm_fatal(`gfn, $sformatf("lock register invalid access %s", field_access))
endcase
end
end
end
endtask

View file

@ -48,14 +48,6 @@ class dv_base_reg_block extends uvm_reg_block;
end
endfunction
function void get_enable_regs(ref dv_base_reg 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);
@ -64,16 +56,6 @@ class dv_base_reg_block extends uvm_reg_block;
end
endfunction
// override RAL's reset function to support enable registers
// when reset issued - the locked registers' access will be reset to original access
virtual function void reset(string kind = "HARD");
dv_base_reg enable_regs[$];
`uvm_info(`gfn, "Resetting RAL reg block", UVM_MEDIUM)
super.reset(kind);
get_enable_regs(enable_regs);
foreach (enable_regs[i]) enable_regs[i].set_locked_regs_access();
endfunction
// Internal function, used to compute the address mask for this register block.
//
// This is quite an expensive computation, so we memoize the results in addr_mask[map].

View file

@ -5,6 +5,8 @@
// base register reg class which will be used to generate the reg field
class dv_base_reg_field extends uvm_reg_field;
local string m_original_access;
local dv_base_reg_field lockable_flds[$];
local bit is_intr_test_fld;
`uvm_object_utils(dv_base_reg_field)
`uvm_object_new
@ -30,8 +32,30 @@ class dv_base_reg_field extends uvm_reg_field;
.is_rand (is_rand),
.individually_accessible(individually_accessible));
value.rand_mode(is_rand);
is_intr_test_fld = !(uvm_re_match("intr_test*", get_parent().get_name()));
endfunction
virtual function dv_base_reg get_dv_base_reg_parent();
uvm_reg csr = get_parent();
`downcast(get_dv_base_reg_parent, csr)
endfunction
virtual function void do_predict (uvm_reg_item rw,
uvm_predict_e kind = UVM_PREDICT_DIRECT,
uvm_reg_byte_en_t be = -1);
uvm_reg_data_t field_val = rw.value[0] & ((1 << get_n_bits())-1);
// update intr_state mirrored value if this is an intr_test reg
if (is_intr_test_fld) begin
uvm_reg_field intr_state_fld = get_intr_state_field();
// use UVM_PREDICT_READ to avoid uvm_warning due to UVM_PREDICT_DIRECT
intr_state_fld.predict(field_val | `gmv(intr_state_fld), .kind(UVM_PREDICT_READ));
end
super.do_predict(rw, kind, be);
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,
@ -46,6 +70,11 @@ class dv_base_reg_field extends uvm_reg_field;
return m_original_access;
endfunction
virtual function uvm_reg_data_t get_field_mask();
get_field_mask = (1'b1 << this.get_n_bits()) - 1;
get_field_mask = get_field_mask << this.get_lsb_pos();
endfunction
virtual function void set_original_access(string access);
if (m_original_access == "") begin
m_original_access = access;
@ -54,12 +83,76 @@ class dv_base_reg_field extends uvm_reg_field;
end
endfunction
virtual function void set_locked_fields_access(string access = "original_access");
case (access)
"RO": void'(this.set_access(access));
"original_access": void'(this.set_access(m_original_access));
default: `uvm_fatal(`gfn, $sformatf("attempt to set access to %s", access))
endcase
// Lock the write access to this field.
// This only pertains to a lockable field. It is invoked in the `set_lockable_flds_access()`
// method of its corresponding lock (wen) field.
local function void set_fld_access(bit lock);
if (lock) void'(this.set_access("RO"));
else void'(this.set_access(m_original_access));
endfunction
// If input is a reg, add all fields under the reg; if input is a field, add the specific field.
function void add_lockable_reg_or_fld(uvm_object lockable_obj);
dv_base_reg_field flds[$];
uvm_reg_block ral = this.get_parent().get_parent();
`DV_CHECK_EQ_FATAL(ral.is_locked(), 0, "RAL is locked, cannot add lockable reg or fld!")
get_flds_from_uvm_object(lockable_obj, `gfn, flds);
foreach (flds[i]) lockable_flds.push_back(flds[i]);
endfunction
// Returns true if this field can lock the specified register/field, else return false.
// If lockable register is partially lockable (only certain field is lockable), this method will
// still return true.
function bit locks_reg_or_fld(uvm_object obj);
dv_base_reg_field flds[$];
get_flds_from_uvm_object(obj, `gfn, flds);
foreach (flds[i]) begin
if (flds[i] inside {lockable_flds}) return 1;
end
return 0;
endfunction
function bit is_wen_fld();
return (lockable_flds.size() > 0);
endfunction
// If lock is set to 1, lockable fields access policy will be set to RO access.
// If lock resets to 0, lockable fields will be set back to their original accesses.
function void set_lockable_flds_access(bit lock);
foreach (lockable_flds[i]) lockable_flds[i].set_fld_access(lock);
endfunction
function void get_lockable_flds(ref dv_base_reg_field lockable_flds_q[$]);
lockable_flds_q = lockable_flds;
endfunction
// override RAL's reset function to support enable registers
// when reset issued - the lockable field's access will be reset to original access
virtual function void reset(string kind = "HARD");
super.reset(kind);
set_fld_access(0);
endfunction
// this function can only be called when this reg is intr_test reg
// Example: ral.intr_test.get_intr_state_field()
local function uvm_reg_field get_intr_state_field();
uvm_reg_block blk = get_parent().get_parent();
uvm_reg intr_state_csr;
uvm_reg_field fields[$];
string intr_state_csr_name;
string intr_test_csr_name = get_parent().get_name();
bit is_intr_state_csr = !(uvm_re_match("intr_test*", intr_test_csr_name));
`DV_CHECK_EQ_FATAL(is_intr_state_csr, 1)
// intr_enable and intr_state have the same suffix
intr_state_csr_name = str_utils_pkg::str_replace(intr_test_csr_name, "test", "state");
intr_state_csr = blk.get_reg_by_name(intr_state_csr_name);
intr_state_csr.get_fields(fields);
// the field location for intr_state and intr_test should be the same
return fields[get_lsb_pos()];
endfunction
endclass

View file

@ -46,8 +46,9 @@ package dv_base_reg_pkg;
BkdrRegPathGlsShdow // backdoor path for shadow reg's shadow val in GLS
} bkdr_reg_path_e;
// package sources
// base ral
typedef class dv_base_reg_block;
typedef class dv_base_reg;
`include "csr_excl_item.sv"
`include "dv_base_reg_field.sv"
`include "dv_base_reg.sv"
@ -55,4 +56,21 @@ package dv_base_reg_pkg;
`include "dv_base_reg_block.sv"
`include "dv_base_reg_map.sv"
function automatic void get_flds_from_uvm_object(input uvm_object obj,
input string msg = "dv_base_reg_pkg",
ref dv_base_reg_field flds[$]);
dv_base_reg csr;
dv_base_reg_field fld;
flds.delete();
if ($cast(csr, obj)) begin
csr.get_dv_base_reg_fields(flds);
end else if ($cast(fld, obj)) begin
flds.push_back(fld);
end else begin
`uvm_fatal(msg, $sformatf("obj %0s is not of type uvm_reg or uvm_reg_field",
obj.get_full_name()))
end
endfunction
endpackage

View file

@ -5,6 +5,8 @@
package str_utils_pkg;
`include "dv_macros.svh"
string msg_id = "str_utils_pkg";
// Returns 1 if string 's' has substring 'sub' within the given index range. 0 Otherwise.
function automatic bit str_has_substr(string s, string sub, int range_lo = 0, int range_hi = -1);
if (range_hi < 0 || range_hi >= s.len()) range_hi = s.len() - 1;
@ -40,6 +42,22 @@ package str_utils_pkg;
return -1;
endfunction : str_rfind
// Find the first match string 'sub' in 's' and replace it with 'new_sub'.
// TODO: Add support for global replacement.
function automatic string str_replace(string s, string sub, string new_sub);
string str_before_sub, str_after_sub;
int lo_idx = str_find(s, sub);
// check sub string exists
`DV_CHECK_NE_FATAL(lo_idx, -1, $sformatf("sub string %s doesn't exist in %s", sub, s), msg_id)
// the new_str contains 3 portions {str_before_sub, new_sub, str_after_sub}
if (lo_idx > 0) str_before_sub = s.substr(0, lo_idx - 1);
if (lo_idx + sub.len() < s.len()) str_after_sub = s.substr(lo_idx + sub.len(), s.len() - 1);
return {str_before_sub, new_sub, str_after_sub};
endfunction : str_replace
// Strips a given set of characters in string 's'.
//
// The set of characters to strip is provided as a string. If not set, all whitespace characters

View file

@ -140,8 +140,9 @@
cover_reg_top_vcs_cov_cfg_file: "-cm_hier {dv_root}/tools/vcs/cover_reg_top.cfg"
// Project defaults for Xcelium
// xcelium_cov_cfg_file: "{{build_mode}_xcelium_cov_cfg_file}"
// xcelium_cov_refine_files: ["{dv_root}/tools/xcelium/common_cov.vRefine"]
xcelium_cov_cfg_file: "{dv_root}/tools/xcelium/xcelium.ccf"
xcelium_cov_refine_files: []
xcelium_common_excl_file: ["{dv_root}/tools/xcelium/exclude.tcl"]
// Build-specific coverage cfg files for Xcelium.
// default_xcelium_cov_cfg_file: "-covfile {dv_root}/tools/xcelium/cover.ccf"

View file

@ -2,6 +2,7 @@
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
export SHELL := /bin/bash
.DEFAULT_GOAL := all
LOCK_SW_BUILD_DIR ?= flock --timeout 3600 ${sw_build_dir} --command
@ -56,7 +57,7 @@ ifneq (${sw_images},)
mkdir -p ${sw_build_dir}
# Initialize meson build system.
${LOCK_SW_BUILD_DIR} "cd ${proj_root} && \
BUILD_ROOT=${sw_build_dir} ${proj_root}/meson_init.sh"
env BUILD_ROOT=${sw_build_dir} ${proj_root}/meson_init.sh"
# Loop through the list of sw_images and invoke meson on each item.
# `sw_images` is a space-separated list of tests to be built into an image.

View file

@ -116,7 +116,8 @@
"-64bit",
"-licqueue",
"-load {cov_merge_db_dir}",
"{xcelium_cov_refine_files}"]
"-init {xcelium_common_excl_file}",
" {eval_cmd} echo {xcelium_cov_refine_files} | sed -E 's/(\\S+)/-load_refinement \\1/g' "]
// pass and fail patterns
build_fail_patterns: ["\\*E.*$"]
@ -134,8 +135,8 @@
"-coverage {cov_metrics}",
// Limit the scope of coverage collection to the DUT.
"-covdut {dut}",
// Set the coverage configuration file.
"{xcelium_cov_cfg_file}"]
// Set the coverage configuration file
"-covfile {xcelium_cov_cfg_file}"]
run_opts: [// Coverage database output location.
"-covworkdir {cov_work_dir}",
// Set the scope to the build mode name.

View file

@ -0,0 +1,11 @@
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
exclude -inst $::env(DUT_TOP) -toggle 'tl_i.a_user.parity'
exclude -inst $::env(DUT_TOP) -toggle 'tl_i.a_user.parity_en'
exclude -inst $::env(DUT_TOP) -toggle 'tl_i.a_param'
exclude -inst $::env(DUT_TOP) -toggle 'tl_o.d_param'
exclude -inst $::env(DUT_TOP) -toggle 'tl_o.d_sink'
exclude -inst $::env(DUT_TOP) -toggle 'tl_o.d_user'
exclude -inst $::env(DUT_TOP) -toggle 'tl_i.a_user.rsvd1'

View file

@ -0,0 +1,18 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
// only collect toggle coverage on dut
deselect_coverage -toggle -instance tb.dut.*...
// only collect toggle coverage on ports
set_toggle_portsonly
// enable toggle scoring of structs and multidim arrays + MDA structs
set_toggle_scoring -sv_mda -sv_mda_of_struct
// filter glitches
set_toggle_strobe 0ps
// Filter unreachable/statically constant blocks
set_com -log

View file

@ -245,12 +245,13 @@ static void WriteSegment(const MemArea &m, uint32_t offset,
// be caught at this function's callsite.
SVScoped scoped(m.location.data());
// This "mini buffer" is used to transfer each write to SystemVerilog. It's
// not massively efficient, but doing so ensures that we pass 256 bits (32
// bytes) of initialised data each time. This is for simutil_set_mem (defined
// in prim_util_memload.svh), whose "val" argument has SystemVerilog type bit
// [255:0].
uint8_t minibuf[32];
// This "mini buffer" is used to transfer each write to SystemVerilog.
// `simutil_set_mem` takes a fixed 312 bit vector but it will only use the
// bits required for the RAM width. For example for a 32-bit wide RAM only
// elements 3 - 0 of `minibuf` will be written to memory. The simulator may
// still read bits from minibuf it does not use so we must use a fixed
// allocation of the full bit vector size to avoid out of bounds access.
uint8_t minibuf[39];
memset(minibuf, 0, sizeof minibuf);
assert(m.width_byte <= sizeof minibuf);

View file

@ -18,6 +18,7 @@ filesets:
- lowrisc:prim:buf
- lowrisc:prim:flop
- lowrisc:prim:flop_2sync
- lowrisc:prim:cipher_pkg:0.1
files:
- rtl/prim_clock_gating_sync.sv
- rtl/prim_alert_pkg.sv
@ -39,7 +40,6 @@ filesets:
- rtl/prim_keccak.sv
- rtl/prim_packer.sv
- rtl/prim_packer_fifo.sv
- rtl/prim_cipher_pkg.sv
- rtl/prim_present.sv
- rtl/prim_prince.sv
- rtl/prim_subst_perm.sv

View file

@ -0,0 +1,17 @@
CAPI=2:
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
name: "lowrisc:prim:cipher_pkg:0.1"
description: "PRINCE and PRESENT block cipher package"
filesets:
files_dv:
files:
- rtl/prim_cipher_pkg.sv
file_type: systemVerilogSource
targets:
default:
filesets:
- files_dv

View file

@ -9,6 +9,7 @@ filesets:
primgen_dep:
depend:
- lowrisc:prim:prim_pkg
- lowrisc:prim:ram_1p_pkg
- lowrisc:prim:primgen

View file

@ -0,0 +1,18 @@
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:ram_1p_pkg"
description: "Ram 1p package"
filesets:
files_rtl:
depend:
files:
- rtl/prim_ram_1p_pkg.sv
file_type: systemVerilogSource
targets:
default:
filesets:
- files_rtl

View file

@ -9,6 +9,7 @@ filesets:
primgen_dep:
depend:
- lowrisc:prim:prim_pkg
- lowrisc:prim:ram_2p_pkg
- lowrisc:prim:primgen

View file

@ -0,0 +1,18 @@
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:ram_2p_pkg"
description: "Ram 2p package"
filesets:
files_rtl:
depend:
files:
- rtl/prim_ram_2p_pkg.sv
file_type: systemVerilogSource
targets:
default:
filesets:
- files_rtl

View file

@ -9,6 +9,7 @@ filesets:
primgen_dep:
depend:
- lowrisc:prim:prim_pkg
- lowrisc:prim:rom_pkg
- lowrisc:prim:primgen

View file

@ -0,0 +1,18 @@
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:rom_pkg"
description: "Rom package"
filesets:
files_rtl:
depend:
files:
- rtl/prim_rom_pkg.sv
file_type: systemVerilogSource
targets:
default:
filesets:
- files_rtl

View file

@ -8,6 +8,7 @@ description: "SECDED ECC primitives"
filesets:
files_rtl:
files:
- rtl/prim_secded_pkg.sv
- rtl/prim_secded_22_16_dec.sv
- rtl/prim_secded_22_16_enc.sv
- rtl/prim_secded_28_22_dec.sv

View file

@ -21,6 +21,11 @@ module prim_clock_div #(
// For odd divide we need to introduce more parameters to control duty cycle
`ASSERT_INIT(DivEven_A, (Divisor % 2) == 0)
// It is assumed the flops in this module are NOT on the scan-chain, as a result only
// the input values are guarded
logic step_down_req;
assign step_down_req = test_en_i ? '0 : step_down_req_i;
logic clk_int;
if (Divisor == 2) begin : gen_div2
@ -49,7 +54,7 @@ module prim_clock_div #(
if (!rst_ni) begin
step_down_nq <= 1'b0;
end else begin
step_down_nq <= step_down_req_i;
step_down_nq <= step_down_req;
end
end
@ -72,7 +77,7 @@ module prim_clock_div #(
logic [CntWidth-1:0] cnt;
logic [CntWidth-1:0] limit;
assign limit = !step_down_req_i ? ToggleCnt - 1 :
assign limit = !step_down_req ? ToggleCnt - 1 :
(ToggleCnt / 2) == 2 ? '0 : (ToggleCnt / 2) - 1;
always_ff @(posedge clk_i or negedge rst_ni) begin
@ -91,25 +96,22 @@ module prim_clock_div #(
if (!rst_ni) begin
step_down_ack_o <= 1'b0;
end else begin
step_down_ack_o <= step_down_req_i;
step_down_ack_o <= step_down_req;
end
end
end
// when in scanmode, bypass the dividers completely
// also anchor point for constraints
// anchor points for constraints
logic clk_muxed;
prim_clock_mux2 #(
.NoFpgaBufG(1'b1)
) u_clk_mux (
.clk0_i(clk_int),
.clk1_i(clk_i),
.sel_i(test_en_i),
.sel_i('0),
.clk_o(clk_muxed)
);
// anchor point for constraints
prim_clock_buf u_clk_div_buf (
.clk_i(clk_muxed),
.clk_o

View file

@ -8,185 +8,259 @@
module prim_fifo_async #(
parameter int unsigned Width = 16,
parameter int unsigned Depth = 3,
parameter int unsigned Depth = 4,
localparam int unsigned DepthW = $clog2(Depth+1) // derived parameter representing [0..Depth]
) (
// write port
input clk_wr_i,
input rst_wr_ni,
input wvalid_i,
output wready_o,
input [Width-1:0] wdata_i,
output [DepthW-1:0] wdepth_o,
input logic clk_wr_i,
input logic rst_wr_ni,
input logic wvalid_i,
output logic wready_o,
input logic [Width-1:0] wdata_i,
output logic [DepthW-1:0] wdepth_o,
// read port
input clk_rd_i,
input rst_rd_ni,
output rvalid_o,
input rready_i,
output [Width-1:0] rdata_o,
output [DepthW-1:0] rdepth_o
input logic clk_rd_i,
input logic rst_rd_ni,
output logic rvalid_o,
input logic rready_i,
output logic [Width-1:0] rdata_o,
output logic [DepthW-1:0] rdepth_o
);
// Depth must be a power of 2 for the gray code pointers to work
`ASSERT_INIT(ParamCheckDepth_A, (Depth > 2) && (Depth == 2**$clog2(Depth)))
`ASSERT_INIT(ParamCheckDepth_A, (Depth == 2**$clog2(Depth)))
localparam int unsigned PTRV_W = $clog2(Depth);
localparam int unsigned PTR_WIDTH = PTRV_W+1;
localparam int unsigned PTRV_W = (Depth == 1) ? 1 : $clog2(Depth);
localparam int unsigned PTR_WIDTH = (Depth == 1) ? 1 : PTRV_W+1;
logic [PTR_WIDTH-1:0] fifo_wptr, fifo_rptr;
logic [PTR_WIDTH-1:0] fifo_wptr_sync_combi, fifo_rptr_sync;
logic [PTR_WIDTH-1:0] fifo_wptr_gray_sync, fifo_rptr_gray_sync;
logic [PTR_WIDTH-1:0] fifo_wptr_gray, fifo_rptr_gray;
logic fifo_incr_wptr, fifo_incr_rptr, empty;
logic [PTR_WIDTH-1:0] fifo_wptr_q, fifo_wptr_d;
logic [PTR_WIDTH-1:0] fifo_rptr_q, fifo_rptr_d;
logic [PTR_WIDTH-1:0] fifo_wptr_sync_combi, fifo_rptr_sync_combi;
logic [PTR_WIDTH-1:0] fifo_wptr_gray_sync, fifo_rptr_gray_sync, fifo_rptr_sync_q;
logic [PTR_WIDTH-1:0] fifo_wptr_gray_q, fifo_wptr_gray_d;
logic [PTR_WIDTH-1:0] fifo_rptr_gray_q, fifo_rptr_gray_d;
logic fifo_incr_wptr, fifo_incr_rptr;
logic full_wclk, full_rclk, empty_rclk;
logic [Width-1:0] storage [Depth];
logic full_wclk, full_rclk;
assign wready_o = !full_wclk;
assign rvalid_o = !empty;
// create the write and read pointers
///////////////////
// Write Pointer //
///////////////////
assign fifo_incr_wptr = wvalid_i & wready_o;
assign fifo_incr_rptr = rvalid_o & rready_i;
///////////////////
// write pointer //
///////////////////
// decimal version
assign fifo_wptr_d = fifo_wptr_q + PTR_WIDTH'(1);
always_ff @(posedge clk_wr_i or negedge rst_wr_ni)
always_ff @(posedge clk_wr_i or negedge rst_wr_ni) begin
if (!rst_wr_ni) begin
fifo_wptr <= {(PTR_WIDTH){1'b0}};
fifo_wptr_q <= '0;
end else if (fifo_incr_wptr) begin
fifo_wptr <= fifo_wptr + PTR_WIDTH'(1);
fifo_wptr_q <= fifo_wptr_d;
end
end
// gray-coded version
always_ff @(posedge clk_wr_i or negedge rst_wr_ni)
always_ff @(posedge clk_wr_i or negedge rst_wr_ni) begin
if (!rst_wr_ni) begin
fifo_wptr_gray <= {(PTR_WIDTH){1'b0}};
fifo_wptr_gray_q <= '0;
end else if (fifo_incr_wptr) begin
fifo_wptr_gray <= dec2gray(fifo_wptr + PTR_WIDTH'(1));
fifo_wptr_gray_q <= fifo_wptr_gray_d;
end
end
// sync gray-coded pointer to read clk
prim_flop_2sync #(.Width(PTR_WIDTH)) sync_wptr (
.clk_i (clk_rd_i),
.rst_ni (rst_rd_ni),
.d_i (fifo_wptr_gray),
.d_i (fifo_wptr_gray_q),
.q_o (fifo_wptr_gray_sync));
assign fifo_wptr_sync_combi = gray2dec(fifo_wptr_gray_sync);
//////////////////
// read pointer //
// Read Pointer //
//////////////////
always_ff @(posedge clk_rd_i or negedge rst_rd_ni)
assign fifo_incr_rptr = rvalid_o & rready_i;
// decimal version
assign fifo_rptr_d = fifo_rptr_q + PTR_WIDTH'(1);
always_ff @(posedge clk_rd_i or negedge rst_rd_ni) begin
if (!rst_rd_ni) begin
fifo_rptr <= {(PTR_WIDTH){1'b0}};
fifo_rptr_q <= '0;
end else if (fifo_incr_rptr) begin
fifo_rptr <= fifo_rptr + PTR_WIDTH'(1);
fifo_rptr_q <= fifo_rptr_d;
end
end
// gray-coded version
always_ff @(posedge clk_rd_i or negedge rst_rd_ni)
always_ff @(posedge clk_rd_i or negedge rst_rd_ni) begin
if (!rst_rd_ni) begin
fifo_rptr_gray <= {(PTR_WIDTH){1'b0}};
fifo_rptr_gray_q <= '0;
end else if (fifo_incr_rptr) begin
fifo_rptr_gray <= dec2gray(fifo_rptr + PTR_WIDTH'(1));
fifo_rptr_gray_q <= fifo_rptr_gray_d;
end
end
// sync gray-coded pointer to write clk
prim_flop_2sync #(.Width(PTR_WIDTH)) sync_rptr (
.clk_i (clk_wr_i),
.rst_ni (rst_wr_ni),
.d_i (fifo_rptr_gray),
.d_i (fifo_rptr_gray_q),
.q_o (fifo_rptr_gray_sync));
always_ff @(posedge clk_wr_i or negedge rst_wr_ni)
// Registered version of synced read pointer
always_ff @(posedge clk_wr_i or negedge rst_wr_ni) begin
if (!rst_wr_ni) begin
fifo_rptr_sync <= {PTR_WIDTH{1'b0}};
fifo_rptr_sync_q <= '0;
end else begin
fifo_rptr_sync <= gray2dec(fifo_rptr_gray_sync);
fifo_rptr_sync_q <= fifo_rptr_sync_combi;
end
end
//////////////////
// empty / full //
// Empty / Full //
//////////////////
assign full_wclk = (fifo_wptr == (fifo_rptr_sync ^ {1'b1,{(PTR_WIDTH-1){1'b0}}}));
assign full_rclk = (fifo_wptr_sync_combi == (fifo_rptr ^ {1'b1,{(PTR_WIDTH-1){1'b0}}}));
assign full_wclk = (fifo_wptr_q == (fifo_rptr_sync_q ^ {1'b1,{(PTR_WIDTH-1){1'b0}}}));
assign full_rclk = (fifo_wptr_sync_combi == (fifo_rptr_q ^ {1'b1,{(PTR_WIDTH-1){1'b0}}}));
assign empty_rclk = (fifo_wptr_sync_combi == fifo_rptr_q);
// Current depth in the write clock side
logic wptr_msb;
logic rptr_sync_msb;
logic [PTRV_W-1:0] wptr_value;
logic [PTRV_W-1:0] rptr_sync_value;
assign wptr_msb = fifo_wptr[PTR_WIDTH-1];
assign rptr_sync_msb = fifo_rptr_sync[PTR_WIDTH-1];
assign wptr_value = fifo_wptr[0+:PTRV_W];
assign rptr_sync_value = fifo_rptr_sync[0+:PTRV_W];
assign wdepth_o = (full_wclk) ? DepthW'(Depth) :
(wptr_msb == rptr_sync_msb) ? DepthW'(wptr_value) - DepthW'(rptr_sync_value) :
(DepthW'(Depth) - DepthW'(rptr_sync_value) + DepthW'(wptr_value)) ;
if (Depth > 1) begin : g_depth_calc
// Same again in the read clock side
assign empty = (fifo_wptr_sync_combi == fifo_rptr);
logic rptr_msb;
logic wptr_sync_msb;
logic [PTRV_W-1:0] rptr_value;
logic [PTRV_W-1:0] wptr_sync_value;
assign wptr_sync_msb = fifo_wptr_sync_combi[PTR_WIDTH-1];
assign rptr_msb = fifo_rptr[PTR_WIDTH-1];
assign wptr_sync_value = fifo_wptr_sync_combi[0+:PTRV_W];
assign rptr_value = fifo_rptr[0+:PTRV_W];
assign rdepth_o = (full_rclk) ? DepthW'(Depth) :
(wptr_sync_msb == rptr_msb) ? DepthW'(wptr_sync_value) - DepthW'(rptr_value) :
(DepthW'(Depth) - DepthW'(rptr_value) + DepthW'(wptr_sync_value)) ;
// Current depth in the write clock side
logic wptr_msb;
logic rptr_sync_msb;
logic [PTRV_W-1:0] wptr_value;
logic [PTRV_W-1:0] rptr_sync_value;
assign wptr_msb = fifo_wptr_q[PTR_WIDTH-1];
assign rptr_sync_msb = fifo_rptr_sync_q[PTR_WIDTH-1];
assign wptr_value = fifo_wptr_q[0+:PTRV_W];
assign rptr_sync_value = fifo_rptr_sync_q[0+:PTRV_W];
assign wdepth_o = (full_wclk) ? DepthW'(Depth) :
(wptr_msb == rptr_sync_msb) ? DepthW'(wptr_value) - DepthW'(rptr_sync_value) :
(DepthW'(Depth) - DepthW'(rptr_sync_value) + DepthW'(wptr_value)) ;
// Current depth in the read clock side
logic rptr_msb;
logic wptr_sync_msb;
logic [PTRV_W-1:0] rptr_value;
logic [PTRV_W-1:0] wptr_sync_value;
assign wptr_sync_msb = fifo_wptr_sync_combi[PTR_WIDTH-1];
assign rptr_msb = fifo_rptr_q[PTR_WIDTH-1];
assign wptr_sync_value = fifo_wptr_sync_combi[0+:PTRV_W];
assign rptr_value = fifo_rptr_q[0+:PTRV_W];
assign rdepth_o = (full_rclk) ? DepthW'(Depth) :
(wptr_sync_msb == rptr_msb) ? DepthW'(wptr_sync_value) - DepthW'(rptr_value) :
(DepthW'(Depth) - DepthW'(rptr_value) + DepthW'(wptr_sync_value)) ;
end else begin : g_no_depth_calc
assign rdepth_o = full_rclk;
assign wdepth_o = full_wclk;
end
assign wready_o = !full_wclk;
assign rvalid_o = !empty_rclk;
/////////////
// storage //
// Storage //
/////////////
logic [Width-1:0] storage [Depth];
if (Depth > 1) begin : g_storage_mux
always_ff @(posedge clk_wr_i)
if (fifo_incr_wptr) begin
storage[fifo_wptr[PTR_WIDTH-2:0]] <= wdata_i;
always_ff @(posedge clk_wr_i) begin
if (fifo_incr_wptr) begin
storage[fifo_wptr_q[PTRV_W-1:0]] <= wdata_i;
end
end
assign rdata_o = storage[fifo_rptr[PTR_WIDTH-2:0]];
assign rdata_o = storage[fifo_rptr_q[PTRV_W-1:0]];
// gray code conversion functions. algorithm walks up from 0..N-1
// then flips the upper bit and walks down from N-1 to 0.
end else begin : g_storage_simple
function automatic [PTR_WIDTH-1:0] dec2gray(input logic [PTR_WIDTH-1:0] decval);
logic [PTR_WIDTH-1:0] decval_sub;
logic [PTR_WIDTH-2:0] decval_in;
logic unused_decval_msb;
always_ff @(posedge clk_wr_i) begin
if (fifo_incr_wptr) begin
storage[0] <= wdata_i;
end
end
decval_sub = (PTR_WIDTH)'(Depth) - {1'b0, decval[PTR_WIDTH-2:0]} - 1'b1;
assign rdata_o = storage[0];
{unused_decval_msb, decval_in} = decval[PTR_WIDTH-1] ? decval_sub : decval;
// Was done in two assigns for low bits and top bit
// but that generates a (bogus) verilator warning, so do in one assign
dec2gray = {decval[PTR_WIDTH-1],
{1'b0,decval_in[PTR_WIDTH-2:1]} ^ decval_in[PTR_WIDTH-2:0]};
endfunction
end
function automatic [PTR_WIDTH-1:0] gray2dec(input logic [PTR_WIDTH-1:0] grayval);
logic [PTR_WIDTH-2:0] dec_tmp, dec_tmp_sub;
logic unused_decsub_msb;
//////////////////////////////////////
// Decimal <-> Gray-code Conversion //
//////////////////////////////////////
dec_tmp[PTR_WIDTH-2] = grayval[PTR_WIDTH-2];
for (int i = PTR_WIDTH-3; i >= 0; i--)
dec_tmp[i] = dec_tmp[i+1]^grayval[i];
{unused_decsub_msb, dec_tmp_sub} = (PTR_WIDTH-1)'(Depth) - {1'b0, dec_tmp} - 1'b1;
if (grayval[PTR_WIDTH-1])
gray2dec = {1'b1,dec_tmp_sub};
else
gray2dec = {1'b0,dec_tmp};
endfunction
// This code is all in a generate context to avoid lint errors when Depth <= 2
if (Depth > 2) begin : g_full_gray_conversion
// TODO: assertions on full, empty, gray transitions
function automatic [PTR_WIDTH-1:0] dec2gray(input logic [PTR_WIDTH-1:0] decval);
logic [PTR_WIDTH-1:0] decval_sub;
logic [PTR_WIDTH-2:0] decval_in;
logic unused_decval_msb;
decval_sub = (PTR_WIDTH)'(Depth) - {1'b0, decval[PTR_WIDTH-2:0]} - 1'b1;
{unused_decval_msb, decval_in} = decval[PTR_WIDTH-1] ? decval_sub : decval;
// Was done in two assigns for low bits and top bit
// but that generates a (bogus) verilator warning, so do in one assign
dec2gray = {decval[PTR_WIDTH-1],
{1'b0,decval_in[PTR_WIDTH-2:1]} ^ decval_in[PTR_WIDTH-2:0]};
endfunction
// Algorithm walks up from 0..N-1 then flips the upper bit and walks down from N-1 to 0.
function automatic [PTR_WIDTH-1:0] gray2dec(input logic [PTR_WIDTH-1:0] grayval);
logic [PTR_WIDTH-2:0] dec_tmp, dec_tmp_sub;
logic unused_decsub_msb;
dec_tmp[PTR_WIDTH-2] = grayval[PTR_WIDTH-2];
for (int i = PTR_WIDTH-3; i >= 0; i--) begin
dec_tmp[i] = dec_tmp[i+1] ^ grayval[i];
end
{unused_decsub_msb, dec_tmp_sub} = (PTR_WIDTH-1)'(Depth) - {1'b0, dec_tmp} - 1'b1;
if (grayval[PTR_WIDTH-1]) begin
gray2dec = {1'b1, dec_tmp_sub};
end else begin
gray2dec = {1'b0, dec_tmp};
end
endfunction
// decimal version of read pointer in write domain
assign fifo_rptr_sync_combi = gray2dec(fifo_rptr_gray_sync);
// decimal version of write pointer in read domain
assign fifo_wptr_sync_combi = gray2dec(fifo_wptr_gray_sync);
assign fifo_rptr_gray_d = dec2gray(fifo_rptr_d);
assign fifo_wptr_gray_d = dec2gray(fifo_wptr_d);
end else if (Depth == 2) begin : g_simple_gray_conversion
assign fifo_rptr_sync_combi = {fifo_rptr_gray_sync[PTR_WIDTH-1], ^fifo_rptr_gray_sync};
assign fifo_wptr_sync_combi = {fifo_wptr_gray_sync[PTR_WIDTH-1], ^fifo_rptr_gray_sync};
assign fifo_rptr_gray_d = {fifo_rptr_d[PTR_WIDTH-1], ^fifo_rptr_d};
assign fifo_wptr_gray_d = {fifo_wptr_d[PTR_WIDTH-1], ^fifo_rptr_d};
end else begin : g_no_gray_conversion
assign fifo_rptr_sync_combi = fifo_rptr_gray_sync;
assign fifo_wptr_sync_combi = fifo_wptr_gray_sync;
assign fifo_rptr_gray_d = fifo_rptr_d;
assign fifo_wptr_gray_d = fifo_rptr_d;
end
// TODO: assertions on full, empty
`ASSERT(GrayWptr_A, $countones(fifo_wptr_gray_q ^ $past(fifo_wptr_gray_q)) <= 1,
clk_wr_i, !rst_wr_ni)
`ASSERT(GrayRptr_A, $countones(fifo_rptr_gray_q ^ $past(fifo_rptr_gray_q)) <= 1,
clk_rd_i, !rst_rd_ni)
endmodule

View file

@ -15,11 +15,10 @@
`include "prim_assert.sv"
module prim_ram_1p_adv #(
module prim_ram_1p_adv import prim_ram_1p_pkg::*; #(
parameter int Depth = 512,
parameter int Width = 32,
parameter int DataBitsPerMask = 1, // Number of data bits per bit of write mask
parameter int CfgW = 8, // WTC, RTC, etc
parameter MemInitFile = "", // VMEM file to initialize the memory with
// Configurations
@ -48,11 +47,9 @@ module prim_ram_1p_adv #(
output logic [1:0] rerror_o, // Bit1: Uncorrectable, Bit0: Correctable
// config
input [CfgW-1:0] cfg_i
input ram_1p_cfg_t cfg_i
);
logic [CfgW-1:0] unused_cfg;
assign unused_cfg = cfg_i;
`ASSERT_INIT(CannotHaveEccAndParity_A, !(EnableParity && EnableECC))
@ -101,7 +98,8 @@ module prim_ram_1p_adv #(
.addr_i (addr_q),
.wdata_i (wdata_q),
.wmask_i (wmask_q),
.rdata_o (rdata_sram)
.rdata_o (rdata_sram),
.cfg_i
);
always_ff @(posedge clk_i or negedge rst_ni) begin

View file

@ -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
//
package prim_ram_1p_pkg;
typedef struct packed {
logic cfg_en;
logic [3:0] cfg;
} cfg_t;
typedef struct packed {
cfg_t ram_cfg; // configuration for ram
cfg_t rf_cfg; // configuration for regfile
} ram_1p_cfg_t;
parameter ram_1p_cfg_t RAM_1P_CFG_DEFAULT = '0;
endpackage // prim_ram_1p_pkg

View file

@ -23,12 +23,11 @@
`include "prim_assert.sv"
module prim_ram_1p_scr #(
module prim_ram_1p_scr import prim_ram_1p_pkg::*; #(
parameter int Depth = 16*1024, // Needs to be a power of 2 if NumAddrScrRounds > 0.
parameter int 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
@ -75,13 +74,19 @@ module prim_ram_1p_scr #(
input [AddrWidth-1:0] addr_i,
input [Width-1:0] wdata_i,
input [Width-1:0] wmask_i, // Needs to be byte-aligned for parity
// The incoming transaction contains an integrity error and the module should alter
// its behavior appropriately.
// On integrity errors, the primitive reverses the bit-order of the nonce and surpresses
// any real transaction to the memory.
input intg_error_i,
output logic [Width-1:0] rdata_o,
output logic rvalid_o, // Read response (rdata_o) is valid
output logic [1:0] rerror_o, // Bit1: Uncorrectable, Bit0: Correctable
output logic [31:0] raddr_o, // Read address for error reporting.
output logic intg_error_o,
// config
input [CfgWidth-1:0] cfg_i
input ram_1p_cfg_t cfg_i
);
//////////////////////
@ -93,6 +98,24 @@ module prim_ram_1p_scr #(
`ASSERT_INIT(DiffWidthAligned_A, (DataBitsPerMask % DiffWidth) == 0)
`ASSERT_INIT(DiffWidthWithParity_A, EnableParity && (DiffWidth == 8) || !EnableParity)
//////////////////////////////
// Integrity error latching //
//////////////////////////////
logic intg_err_q;
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
intg_err_q <= '0;
end else if (intg_error_i) begin
intg_err_q <= 1'b1;
end
end
prim_buf u_intg_err_out (
.in_i(intg_error_i | intg_err_q),
.out_o(intg_error_o)
);
/////////////////////////////////////////
// Pending Write and Address Registers //
/////////////////////////////////////////
@ -118,8 +141,14 @@ module prim_ram_1p_scr #(
assign addr_collision_d = read_en & (write_en_q | write_pending_q) & (addr_i == waddr_q);
// Macro requests and write strobe
// The macro operation is silenced if an integrity error is seen
logic macro_req;
assign macro_req = read_en | write_en_q | write_pending_q;
logic intg_err_macro_req;
prim_buf u_intg_err_macro_req (
.in_i(intg_error_i | intg_err_q),
.out_o(intg_err_macro_req)
);
assign macro_req = ~intg_err_macro_req & (read_en | write_en_q | write_pending_q);
// We are allowed to write a pending write transaction to the memory if there is no incoming read
logic macro_write;
assign macro_write = (write_en_q | write_pending_q) & ~read_en;
@ -138,18 +167,34 @@ module prim_ram_1p_scr #(
// This creates a bijective address mapping using a substitution / permutation network.
logic [AddrWidth-1:0] addr_scr;
if (NumAddrScrRounds > 0) begin : gen_addr_scr
// TODO, expand this into copies with another primitive
logic intg_err_addr_scr;
prim_buf u_intg_err_addr_scr (
.in_i(intg_error_i | intg_err_q),
.out_o(intg_err_addr_scr)
);
// If there is an intergirty error, the nonce used is reversed
logic [AddrWidth-1:0] addr_scr_nonce;
for (genvar j = 0; j < AddrWidth; j++) begin : gen_addr_scr_nonce
assign addr_scr_nonce[j] = intg_err_addr_scr ?
nonce_i[NonceWidth - 1 - j] :
nonce_i[NonceWidth - AddrWidth + j];
end
prim_subst_perm #(
.DataWidth ( AddrWidth ),
.NumRounds ( NumAddrScrRounds ),
.Decrypt ( 0 )
) u_prim_subst_perm (
.data_i ( addr_mux ),
.data_i ( addr_mux ),
// Since the counter mode concatenates {nonce_i[NonceWidth-1-AddrWidth:0], addr_i} to form
// the IV, the upper AddrWidth bits of the nonce are not used and can be used for address
// scrambling. In cases where N parallel PRINCE blocks are used due to a data
// width > 64bit, N*AddrWidth nonce bits are left dangling.
.key_i ( nonce_i[NonceWidth - 1 : NonceWidth - AddrWidth] ),
.data_o ( addr_scr )
.key_i ( addr_scr_nonce ),
.data_o ( addr_scr )
);
end else begin : gen_no_addr_scr
assign addr_scr = addr_mux;
@ -166,8 +211,26 @@ module prim_ram_1p_scr #(
// This encrypts the IV consisting of the nonce and address using the key provided in order to
// generate the keystream for the data. Note that we instantiate a register halfway within this
// primitive to balance the delay between request and response side.
localparam int DataNonceWidth = 64 - AddrWidth;
logic [NumParScr*64-1:0] keystream;
logic [NumParScr-1:0][DataNonceWidth-1:0] data_scr_nonce;
// TODO, expand this into copies with another primitive
logic intg_err_data_scr;
prim_buf u_intg_err_data_scr (
.in_i(intg_error_i | intg_err_q),
.out_o(intg_err_data_scr)
);
for (genvar k = 0; k < NumParScr; k++) begin : gen_par_scr
for (genvar j = 0; j < DataNonceWidth; j++) begin : gen_data_nonce
assign data_scr_nonce[k][j] = intg_err_data_scr ?
nonce_i[(k + 1) * DataNonceWidth - j] :
nonce_i[k * DataNonceWidth + j];
end
prim_prince #(
.DataWidth (64),
.KeyWidth (128),
@ -180,7 +243,8 @@ module prim_ram_1p_scr #(
.rst_ni,
.valid_i ( gnt_o ),
// The IV is composed of a nonce and the row address
.data_i ( {nonce_i[k * (64 - AddrWidth) +: (64 - AddrWidth)], addr_i} ),
//.data_i ( {nonce_i[k * (64 - AddrWidth) +: (64 - AddrWidth)], addr_i} ),
.data_i ( {data_scr_nonce[k], addr_i} ),
// All parallel scramblers use the same key
.key_i,
// Since we operate in counter mode, this can always be set to encryption mode
@ -222,8 +286,8 @@ module prim_ram_1p_scr #(
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.
// 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] ^
@ -296,16 +360,28 @@ module prim_ram_1p_scr #(
logic rvalid_q;
assign rvalid_o = rvalid_q;
// In case of a collision, we forward the write data from the unscrambled holding register
assign rdata_o = (addr_collision_q) ? wdata_q : // forward pending (unscrambled) write data
(rvalid_q) ? rdata : // regular reads
'0; // tie to zero otherwise
logic [Width-1:0] wmask_q;
always_comb begin : p_forward_mux
rdata_o = '0;
// regular reads
if (rvalid_q) begin
rdata_o = rdata;
end
// In case of a collision, we forward the valid bytes of the write data from the unscrambled
// holding register.
if (addr_collision_q) begin
for (int k = 0; k < Width; k++) begin
if (wmask_q[k]) begin
rdata_o[k] = wdata_q[k];
end
end
end
end
///////////////
// Registers //
///////////////
logic [Width-1:0] wmask_q;
always_ff @(posedge clk_i or negedge rst_ni) begin : p_wdata_buf
if (!rst_ni) begin
write_pending_q <= 1'b0;
@ -345,7 +421,6 @@ module prim_ram_1p_scr #(
.Depth(Depth),
.Width(Width),
.DataBitsPerMask(DataBitsPerMask),
.CfgW(CfgWidth),
.EnableECC(1'b0),
.EnableParity(EnableParity),
.EnableInputPipeline(1'b0),

View file

@ -15,11 +15,10 @@
`include "prim_assert.sv"
module prim_ram_2p_adv #(
module prim_ram_2p_adv import prim_ram_2p_pkg::*; #(
parameter int Depth = 512,
parameter int Width = 32,
parameter int DataBitsPerMask = 1, // Number of data bits per bit of write mask
parameter int CfgW = 8, // WTC, RTC, etc
parameter MemInitFile = "", // VMEM file to initialize the memory with
// Configurations
@ -56,14 +55,13 @@ module prim_ram_2p_adv #(
output logic b_rvalid_o, // read response (b_rdata_o) is valid
output logic [1:0] b_rerror_o, // Bit1: Uncorrectable, Bit0: Correctable
input [CfgW-1:0] cfg_i
input ram_2p_cfg_t cfg_i
);
prim_ram_2p_async_adv #(
.Depth (Depth),
.Width (Width),
.DataBitsPerMask (DataBitsPerMask),
.CfgW (CfgW),
.MemInitFile (MemInitFile),
.EnableECC (EnableECC),
.EnableParity (EnableParity),

View file

@ -15,11 +15,10 @@
`include "prim_assert.sv"
module prim_ram_2p_async_adv #(
module prim_ram_2p_async_adv import prim_ram_2p_pkg::*; #(
parameter int Depth = 512,
parameter int Width = 32,
parameter int DataBitsPerMask = 1, // Number of data bits per bit of write mask
parameter int CfgW = 8, // WTC, RTC, etc
parameter MemInitFile = "", // VMEM file to initialize the memory with
// Configurations
@ -59,11 +58,9 @@ module prim_ram_2p_async_adv #(
output logic [1:0] b_rerror_o, // Bit1: Uncorrectable, Bit0: Correctable
// config
input [CfgW-1:0] cfg_i
input ram_2p_cfg_t cfg_i
);
logic [CfgW-1:0] unused_cfg;
assign unused_cfg = cfg_i;
`ASSERT_INIT(CannotHaveEccAndParity_A, !(EnableParity && EnableECC))
@ -130,7 +127,9 @@ module prim_ram_2p_async_adv #(
.b_addr_i (b_addr_q),
.b_wdata_i (b_wdata_q),
.b_wmask_i (b_wmask_q),
.b_rdata_o (b_rdata_sram)
.b_rdata_o (b_rdata_sram),
.cfg_i
);
always_ff @(posedge clk_a_i or negedge rst_a_ni) begin

View file

@ -0,0 +1,22 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
package prim_ram_2p_pkg;
typedef struct packed {
logic cfg_en;
logic [3:0] cfg;
} cfg_t;
typedef struct packed {
cfg_t a_ram_fcfg; // configuration for a port
cfg_t a_ram_lcfg; // configuration for a port
cfg_t b_ram_fcfg; // configuration for b port
cfg_t b_ram_lcfg; // configuration for b port
} ram_2p_cfg_t;
parameter ram_2p_cfg_t RAM_2P_CFG_DEFAULT = '0;
endpackage // prim_ram_2p_pkg

View file

@ -6,14 +6,12 @@
`include "prim_assert.sv"
module prim_rom_adv #(
module prim_rom_adv import prim_rom_pkg::*; #(
// Parameters passed on the the ROM primitive.
parameter int Width = 32,
parameter int Depth = 2048, // 8kB default
parameter MemInitFile = "", // VMEM file to initialize the memory with
parameter int CfgW = 8, // WTC, RTC, etc
localparam int Aw = $clog2(Depth)
) (
input logic clk_i,
@ -23,13 +21,9 @@ module prim_rom_adv #(
output logic rvalid_o,
output logic [Width-1:0] rdata_o,
input [CfgW-1:0] cfg_i
input rom_cfg_t cfg_i
);
// We will eventually use cfg_i for RTC/WTC or other memory parameters.
logic [CfgW-1:0] unused_cfg;
assign unused_cfg = cfg_i;
prim_rom #(
.Width(Width),
.Depth(Depth),
@ -38,7 +32,8 @@ module prim_rom_adv #(
.clk_i,
.req_i,
.addr_i,
.rdata_o
.rdata_o,
.cfg_i
);
always_ff @(posedge clk_i or negedge rst_ni) begin

View file

@ -0,0 +1,13 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
package prim_rom_pkg;
typedef struct packed {
logic cfg_en;
logic [3:0] cfg;
} rom_cfg_t;
endpackage // prim_rom_pkg

View file

@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
//
// SECDED Decoder generated by
// util/design/secded_gen.py -m 6 -k 16 -s 3741324996 -c hsiao
// util/design/secded_gen.py -m 6 -k 16 -s 1592631616 -c hsiao
module prim_secded_22_16_dec (
input [21:0] in,
@ -15,30 +15,30 @@ module prim_secded_22_16_dec (
logic single_error;
// Syndrome calculation
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);
assign syndrome_o[0] = ^(in & 22'h019F41);
assign syndrome_o[1] = ^(in & 22'h027A34);
assign syndrome_o[2] = ^(in & 22'h0429CD);
assign syndrome_o[3] = ^(in & 22'h08C0AF);
assign syndrome_o[4] = ^(in & 22'h1074D2);
assign syndrome_o[5] = ^(in & 22'h20873A);
// Corrected output calculation
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[0] = (syndrome_o == 6'hd) ^ in[0];
assign d_o[1] = (syndrome_o == 6'h38) ^ in[1];
assign d_o[2] = (syndrome_o == 6'he) ^ 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'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];
assign d_o[5] = (syndrome_o == 6'h2a) ^ in[5];
assign d_o[6] = (syndrome_o == 6'h15) ^ in[6];
assign d_o[7] = (syndrome_o == 6'h1c) ^ in[7];
assign d_o[8] = (syndrome_o == 6'h25) ^ in[8];
assign d_o[9] = (syndrome_o == 6'h23) ^ in[9];
assign d_o[10] = (syndrome_o == 6'h31) ^ in[10];
assign d_o[11] = (syndrome_o == 6'h7) ^ in[11];
assign d_o[12] = (syndrome_o == 6'h13) ^ in[12];
assign d_o[13] = (syndrome_o == 6'h16) ^ in[13];
assign d_o[14] = (syndrome_o == 6'h1a) ^ in[14];
assign d_o[15] = (syndrome_o == 6'h29) ^ in[15];
// err_o calc. bit0: single error, bit1: double error
assign single_error = ^syndrome_o;

View file

@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
//
// SECDED Encoder generated by
// util/design/secded_gen.py -m 6 -k 16 -s 3741324996 -c hsiao
// util/design/secded_gen.py -m 6 -k 16 -s 1592631616 -c hsiao
module prim_secded_22_16_enc (
input [15:0] in,
@ -12,12 +12,12 @@ module prim_secded_22_16_enc (
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);
out[16] = ^(out & 22'h009F41);
out[17] = ^(out & 22'h007A34);
out[18] = ^(out & 22'h0029CD);
out[19] = ^(out & 22'h00C0AF);
out[20] = ^(out & 22'h0074D2);
out[21] = ^(out & 22'h00873A);
end
endmodule : prim_secded_22_16_enc

View file

@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
//
// SECDED Decoder generated by
// util/design/secded_gen.py -m 6 -k 22 -s 4256260335 -c hsiao
// util/design/secded_gen.py -m 6 -k 22 -s 1592631616 -c hsiao
module prim_secded_28_22_dec (
input [27:0] in,
@ -16,11 +16,11 @@ module prim_secded_28_22_dec (
// Syndrome calculation
assign syndrome_o[0] = ^(in & 28'h07003FF);
assign syndrome_o[1] = ^(in & 28'h0B0FC0F);
assign syndrome_o[1] = ^(in & 28'h090FC0F);
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);
assign syndrome_o[4] = ^(in & 28'h43DAAA4);
assign syndrome_o[5] = ^(in & 28'h82ED348);
// Corrected output calculation
assign d_o[0] = (syndrome_o == 6'h7) ^ in[0];
@ -43,8 +43,8 @@ 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'h2f) ^ in[20];
assign d_o[21] = (syndrome_o == 6'h1f) ^ in[21];
assign d_o[20] = (syndrome_o == 6'h1f) ^ in[20];
assign d_o[21] = (syndrome_o == 6'h3d) ^ in[21];
// err_o calc. bit0: single error, bit1: double error
assign single_error = ^syndrome_o;

View file

@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
//
// SECDED Encoder generated by
// util/design/secded_gen.py -m 6 -k 22 -s 4256260335 -c hsiao
// util/design/secded_gen.py -m 6 -k 22 -s 1592631616 -c hsiao
module prim_secded_28_22_enc (
input [21:0] in,
@ -13,11 +13,11 @@ module prim_secded_28_22_enc (
always_comb begin : p_encode
out = 28'(in);
out[22] = ^(out & 28'h03003FF);
out[23] = ^(out & 28'h030FC0F);
out[23] = ^(out & 28'h010FC0F);
out[24] = ^(out & 28'h0371C71);
out[25] = ^(out & 28'h03B6592);
out[26] = ^(out & 28'h02DAAA4);
out[27] = ^(out & 28'h01ED348);
out[26] = ^(out & 28'h03DAAA4);
out[27] = ^(out & 28'h02ED348);
end
endmodule : prim_secded_28_22_enc

View file

@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
//
// SECDED Decoder generated by
// util/design/secded_gen.py -m 7 -k 32 -s 3759507082 -c hsiao
// util/design/secded_gen.py -m 7 -k 32 -s 1592631616 -c hsiao
module prim_secded_39_32_dec (
input [38:0] in,
@ -15,47 +15,47 @@ module prim_secded_39_32_dec (
logic single_error;
// Syndrome calculation
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);
assign syndrome_o[0] = ^(in & 39'h01850E56A2);
assign syndrome_o[1] = ^(in & 39'h022E534C61);
assign syndrome_o[2] = ^(in & 39'h040901A9FE);
assign syndrome_o[3] = ^(in & 39'h087079A702);
assign syndrome_o[4] = ^(in & 39'h10CABA900D);
assign syndrome_o[5] = ^(in & 39'h20D3C44B18);
assign syndrome_o[6] = ^(in & 39'h4034A430D5);
// Corrected output calculation
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[0] = (syndrome_o == 7'h52) ^ in[0];
assign d_o[1] = (syndrome_o == 7'hd) ^ in[1];
assign d_o[2] = (syndrome_o == 7'h54) ^ in[2];
assign d_o[3] = (syndrome_o == 7'h34) ^ in[3];
assign d_o[4] = (syndrome_o == 7'h64) ^ in[4];
assign d_o[5] = (syndrome_o == 7'h7) ^ in[5];
assign d_o[6] = (syndrome_o == 7'h46) ^ in[6];
assign d_o[7] = (syndrome_o == 7'h45) ^ in[7];
assign d_o[8] = (syndrome_o == 7'h2c) ^ in[8];
assign d_o[9] = (syndrome_o == 7'h29) ^ in[9];
assign d_o[10] = (syndrome_o == 7'hb) ^ in[10];
assign d_o[11] = (syndrome_o == 7'h26) ^ in[11];
assign d_o[12] = (syndrome_o == 7'h51) ^ in[12];
assign d_o[13] = (syndrome_o == 7'h4c) ^ in[13];
assign d_o[14] = (syndrome_o == 7'h23) ^ in[14];
assign d_o[15] = (syndrome_o == 7'h1c) ^ in[15];
assign d_o[16] = (syndrome_o == 7'he) ^ in[16];
assign d_o[17] = (syndrome_o == 7'h13) ^ in[17];
assign d_o[18] = (syndrome_o == 7'h61) ^ in[18];
assign d_o[19] = (syndrome_o == 7'h19) ^ in[19];
assign d_o[20] = (syndrome_o == 7'h1a) ^ in[20];
assign d_o[21] = (syndrome_o == 7'h58) ^ in[21];
assign d_o[22] = (syndrome_o == 7'h2a) ^ 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];
assign d_o[24] = (syndrome_o == 7'h25) ^ in[24];
assign d_o[25] = (syndrome_o == 7'h32) ^ in[25];
assign d_o[26] = (syndrome_o == 7'h43) ^ in[26];
assign d_o[27] = (syndrome_o == 7'h16) ^ in[27];
assign d_o[28] = (syndrome_o == 7'h68) ^ in[28];
assign d_o[29] = (syndrome_o == 7'h4a) ^ in[29];
assign d_o[30] = (syndrome_o == 7'h38) ^ in[30];
assign d_o[31] = (syndrome_o == 7'h31) ^ in[31];
// err_o calc. bit0: single error, bit1: double error
assign single_error = ^syndrome_o;

View file

@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
//
// SECDED Encoder generated by
// util/design/secded_gen.py -m 7 -k 32 -s 3759507082 -c hsiao
// util/design/secded_gen.py -m 7 -k 32 -s 1592631616 -c hsiao
module prim_secded_39_32_enc (
input [31:0] in,
@ -12,13 +12,13 @@ module prim_secded_39_32_enc (
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);
out[32] = ^(out & 39'h00850E56A2);
out[33] = ^(out & 39'h002E534C61);
out[34] = ^(out & 39'h000901A9FE);
out[35] = ^(out & 39'h007079A702);
out[36] = ^(out & 39'h00CABA900D);
out[37] = ^(out & 39'h00D3C44B18);
out[38] = ^(out & 39'h0034A430D5);
end
endmodule : prim_secded_39_32_enc

View file

@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
//
// SECDED Decoder generated by
// util/design/secded_gen.py -m 7 -k 57 -s 2871209727 -c hsiao
// util/design/secded_gen.py -m 7 -k 57 -s 1592631616 -c hsiao
module prim_secded_64_57_dec (
input [63:0] in,

View file

@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
//
// SECDED Encoder generated by
// util/design/secded_gen.py -m 7 -k 57 -s 2871209727 -c hsiao
// util/design/secded_gen.py -m 7 -k 57 -s 1592631616 -c hsiao
module prim_secded_64_57_enc (
input [56:0] in,

View file

@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
//
// SECDED Decoder generated by
// util/design/secded_gen.py -m 8 -k 64 -s 3843802612 -c hsiao
// util/design/secded_gen.py -m 8 -k 64 -s 1592631616 -c hsiao
module prim_secded_72_64_dec (
input [71:0] in,
@ -15,14 +15,14 @@ module prim_secded_72_64_dec (
logic single_error;
// Syndrome calculation
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);
assign syndrome_o[0] = ^(in & 72'h019D000000001FFFFF);
assign syndrome_o[1] = ^(in & 72'h027600000FFFE0003F);
assign syndrome_o[2] = ^(in & 72'h0479003FF003E007C1);
assign syndrome_o[3] = ^(in & 72'h08A70FC0F03C207842);
assign syndrome_o[4] = ^(in & 72'h10D371C711C4438884);
assign syndrome_o[5] = ^(in & 72'h20F8B65926488C9108);
assign syndrome_o[6] = ^(in & 72'h40AEDAAA4A91152210);
assign syndrome_o[7] = ^(in & 72'h804FED348D221A4420);
// Corrected output calculation
assign d_o[0] = (syndrome_o == 8'h7) ^ in[0];
@ -81,14 +81,14 @@ module prim_secded_72_64_dec (
assign d_o[53] = (syndrome_o == 8'hb0) ^ in[53];
assign d_o[54] = (syndrome_o == 8'hd0) ^ in[54];
assign d_o[55] = (syndrome_o == 8'he0) ^ in[55];
assign d_o[56] = (syndrome_o == 8'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];
assign d_o[56] = (syndrome_o == 8'h9d) ^ in[56];
assign d_o[57] = (syndrome_o == 8'hda) ^ in[57];
assign d_o[58] = (syndrome_o == 8'hcb) ^ in[58];
assign d_o[59] = (syndrome_o == 8'he5) ^ in[59];
assign d_o[60] = (syndrome_o == 8'h37) ^ in[60];
assign d_o[61] = (syndrome_o == 8'h6e) ^ in[61];
assign d_o[62] = (syndrome_o == 8'hb6) ^ in[62];
assign d_o[63] = (syndrome_o == 8'h79) ^ in[63];
// err_o calc. bit0: single error, bit1: double error
assign single_error = ^syndrome_o;

View file

@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
//
// SECDED Encoder generated by
// util/design/secded_gen.py -m 8 -k 64 -s 3843802612 -c hsiao
// util/design/secded_gen.py -m 8 -k 64 -s 1592631616 -c hsiao
module prim_secded_72_64_enc (
input [63:0] in,
@ -12,14 +12,14 @@ module prim_secded_72_64_enc (
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);
out[64] = ^(out & 72'h009D000000001FFFFF);
out[65] = ^(out & 72'h007600000FFFE0003F);
out[66] = ^(out & 72'h0079003FF003E007C1);
out[67] = ^(out & 72'h00A70FC0F03C207842);
out[68] = ^(out & 72'h00D371C711C4438884);
out[69] = ^(out & 72'h00F8B65926488C9108);
out[70] = ^(out & 72'h00AEDAAA4A91152210);
out[71] = ^(out & 72'h004FED348D221A4420);
end
endmodule : prim_secded_72_64_enc

View file

@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
//
// SECDED Decoder generated by
// util/design/secded_gen.py -m 6 -k 16 -s 1997031251 -c hamming
// util/design/secded_gen.py -m 6 -k 16 -s 1592631616 -c hamming
module prim_secded_hamming_22_16_dec (
input [21:0] in,

View file

@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
//
// SECDED Encoder generated by
// util/design/secded_gen.py -m 6 -k 16 -s 1997031251 -c hamming
// util/design/secded_gen.py -m 6 -k 16 -s 1592631616 -c hamming
module prim_secded_hamming_22_16_enc (
input [15:0] in,

View file

@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
//
// SECDED Decoder generated by
// util/design/secded_gen.py -m 7 -k 32 -s 390368410 -c hamming
// util/design/secded_gen.py -m 7 -k 32 -s 1592631616 -c hamming
module prim_secded_hamming_39_32_dec (
input [38:0] in,

View file

@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
//
// SECDED Encoder generated by
// util/design/secded_gen.py -m 7 -k 32 -s 390368410 -c hamming
// util/design/secded_gen.py -m 7 -k 32 -s 1592631616 -c hamming
module prim_secded_hamming_39_32_enc (
input [31:0] in,

View file

@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
//
// SECDED Decoder generated by
// util/design/secded_gen.py -m 8 -k 64 -s 1218923287 -c hamming
// util/design/secded_gen.py -m 8 -k 64 -s 1592631616 -c hamming
module prim_secded_hamming_72_64_dec (
input [71:0] in,

View file

@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
//
// SECDED Encoder generated by
// util/design/secded_gen.py -m 8 -k 64 -s 1218923287 -c hamming
// util/design/secded_gen.py -m 8 -k 64 -s 1592631616 -c hamming
module prim_secded_hamming_72_64_enc (
input [63:0] in,

View file

@ -0,0 +1,714 @@
// 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 -s 1592631616 from util/design/data/secded_cfg.hjson
package prim_secded_pkg;
typedef struct packed {
logic [15:0] data;
logic [5:0] syndrome;
logic [1:0] err;
} secded_22_16_t;
typedef struct packed {
logic [21:0] data;
logic [5:0] syndrome;
logic [1:0] err;
} secded_28_22_t;
typedef struct packed {
logic [31:0] data;
logic [6:0] syndrome;
logic [1:0] err;
} secded_39_32_t;
typedef struct packed {
logic [56:0] data;
logic [6:0] syndrome;
logic [1:0] err;
} secded_64_57_t;
typedef struct packed {
logic [63:0] data;
logic [7:0] syndrome;
logic [1:0] err;
} secded_72_64_t;
typedef struct packed {
logic [15:0] data;
logic [5:0] syndrome;
logic [1:0] err;
} secded_hamming_22_16_t;
typedef struct packed {
logic [31:0] data;
logic [6:0] syndrome;
logic [1:0] err;
} secded_hamming_39_32_t;
typedef struct packed {
logic [63:0] data;
logic [7:0] syndrome;
logic [1:0] err;
} secded_hamming_72_64_t;
function automatic logic [21:0] prim_secded_22_16_enc (logic [15:0] in);
logic [21:0] out;
out = 22'(in);
out[16] = ^(out & 22'h009F41);
out[17] = ^(out & 22'h007A34);
out[18] = ^(out & 22'h0029CD);
out[19] = ^(out & 22'h00C0AF);
out[20] = ^(out & 22'h0074D2);
out[21] = ^(out & 22'h00873A);
return out;
endfunction
function automatic secded_22_16_t prim_secded_22_16_dec (logic [21:0] in);
logic [15:0] d_o;
logic [5:0] syndrome_o;
logic [1:0] err_o;
secded_22_16_t dec;
logic single_error;
// Syndrome calculation
syndrome_o[0] = ^(in & 22'h019F41);
syndrome_o[1] = ^(in & 22'h027A34);
syndrome_o[2] = ^(in & 22'h0429CD);
syndrome_o[3] = ^(in & 22'h08C0AF);
syndrome_o[4] = ^(in & 22'h1074D2);
syndrome_o[5] = ^(in & 22'h20873A);
// Corrected output calculation
d_o[0] = (syndrome_o == 6'hd) ^ in[0];
d_o[1] = (syndrome_o == 6'h38) ^ in[1];
d_o[2] = (syndrome_o == 6'he) ^ in[2];
d_o[3] = (syndrome_o == 6'h2c) ^ in[3];
d_o[4] = (syndrome_o == 6'h32) ^ in[4];
d_o[5] = (syndrome_o == 6'h2a) ^ in[5];
d_o[6] = (syndrome_o == 6'h15) ^ in[6];
d_o[7] = (syndrome_o == 6'h1c) ^ in[7];
d_o[8] = (syndrome_o == 6'h25) ^ in[8];
d_o[9] = (syndrome_o == 6'h23) ^ in[9];
d_o[10] = (syndrome_o == 6'h31) ^ in[10];
d_o[11] = (syndrome_o == 6'h7) ^ in[11];
d_o[12] = (syndrome_o == 6'h13) ^ in[12];
d_o[13] = (syndrome_o == 6'h16) ^ in[13];
d_o[14] = (syndrome_o == 6'h1a) ^ in[14];
d_o[15] = (syndrome_o == 6'h29) ^ in[15];
// err_o calc. bit0: single error, bit1: double error
single_error = ^syndrome_o;
err_o[0] = single_error;
err_o[1] = ~single_error & (|syndrome_o);
dec.data = d_o;
dec.syndrome = syndrome_o;
dec.err = err_o;
return dec;
endfunction
function automatic logic [27:0] prim_secded_28_22_enc (logic [21:0] in);
logic [27:0] out;
out = 28'(in);
out[22] = ^(out & 28'h03003FF);
out[23] = ^(out & 28'h010FC0F);
out[24] = ^(out & 28'h0371C71);
out[25] = ^(out & 28'h03B6592);
out[26] = ^(out & 28'h03DAAA4);
out[27] = ^(out & 28'h02ED348);
return out;
endfunction
function automatic secded_28_22_t prim_secded_28_22_dec (logic [27:0] in);
logic [21:0] d_o;
logic [5:0] syndrome_o;
logic [1:0] err_o;
secded_28_22_t dec;
logic single_error;
// Syndrome calculation
syndrome_o[0] = ^(in & 28'h07003FF);
syndrome_o[1] = ^(in & 28'h090FC0F);
syndrome_o[2] = ^(in & 28'h1371C71);
syndrome_o[3] = ^(in & 28'h23B6592);
syndrome_o[4] = ^(in & 28'h43DAAA4);
syndrome_o[5] = ^(in & 28'h82ED348);
// Corrected output calculation
d_o[0] = (syndrome_o == 6'h7) ^ in[0];
d_o[1] = (syndrome_o == 6'hb) ^ in[1];
d_o[2] = (syndrome_o == 6'h13) ^ in[2];
d_o[3] = (syndrome_o == 6'h23) ^ in[3];
d_o[4] = (syndrome_o == 6'hd) ^ in[4];
d_o[5] = (syndrome_o == 6'h15) ^ in[5];
d_o[6] = (syndrome_o == 6'h25) ^ in[6];
d_o[7] = (syndrome_o == 6'h19) ^ in[7];
d_o[8] = (syndrome_o == 6'h29) ^ in[8];
d_o[9] = (syndrome_o == 6'h31) ^ in[9];
d_o[10] = (syndrome_o == 6'he) ^ in[10];
d_o[11] = (syndrome_o == 6'h16) ^ in[11];
d_o[12] = (syndrome_o == 6'h26) ^ in[12];
d_o[13] = (syndrome_o == 6'h1a) ^ in[13];
d_o[14] = (syndrome_o == 6'h2a) ^ in[14];
d_o[15] = (syndrome_o == 6'h32) ^ in[15];
d_o[16] = (syndrome_o == 6'h1c) ^ in[16];
d_o[17] = (syndrome_o == 6'h2c) ^ in[17];
d_o[18] = (syndrome_o == 6'h34) ^ in[18];
d_o[19] = (syndrome_o == 6'h38) ^ in[19];
d_o[20] = (syndrome_o == 6'h1f) ^ in[20];
d_o[21] = (syndrome_o == 6'h3d) ^ in[21];
// err_o calc. bit0: single error, bit1: double error
single_error = ^syndrome_o;
err_o[0] = single_error;
err_o[1] = ~single_error & (|syndrome_o);
dec.data = d_o;
dec.syndrome = syndrome_o;
dec.err = err_o;
return dec;
endfunction
function automatic logic [38:0] prim_secded_39_32_enc (logic [31:0] in);
logic [38:0] out;
out = 39'(in);
out[32] = ^(out & 39'h00850E56A2);
out[33] = ^(out & 39'h002E534C61);
out[34] = ^(out & 39'h000901A9FE);
out[35] = ^(out & 39'h007079A702);
out[36] = ^(out & 39'h00CABA900D);
out[37] = ^(out & 39'h00D3C44B18);
out[38] = ^(out & 39'h0034A430D5);
return out;
endfunction
function automatic secded_39_32_t prim_secded_39_32_dec (logic [38:0] in);
logic [31:0] d_o;
logic [6:0] syndrome_o;
logic [1:0] err_o;
secded_39_32_t dec;
logic single_error;
// Syndrome calculation
syndrome_o[0] = ^(in & 39'h01850E56A2);
syndrome_o[1] = ^(in & 39'h022E534C61);
syndrome_o[2] = ^(in & 39'h040901A9FE);
syndrome_o[3] = ^(in & 39'h087079A702);
syndrome_o[4] = ^(in & 39'h10CABA900D);
syndrome_o[5] = ^(in & 39'h20D3C44B18);
syndrome_o[6] = ^(in & 39'h4034A430D5);
// Corrected output calculation
d_o[0] = (syndrome_o == 7'h52) ^ in[0];
d_o[1] = (syndrome_o == 7'hd) ^ in[1];
d_o[2] = (syndrome_o == 7'h54) ^ in[2];
d_o[3] = (syndrome_o == 7'h34) ^ in[3];
d_o[4] = (syndrome_o == 7'h64) ^ in[4];
d_o[5] = (syndrome_o == 7'h7) ^ in[5];
d_o[6] = (syndrome_o == 7'h46) ^ in[6];
d_o[7] = (syndrome_o == 7'h45) ^ in[7];
d_o[8] = (syndrome_o == 7'h2c) ^ in[8];
d_o[9] = (syndrome_o == 7'h29) ^ in[9];
d_o[10] = (syndrome_o == 7'hb) ^ in[10];
d_o[11] = (syndrome_o == 7'h26) ^ in[11];
d_o[12] = (syndrome_o == 7'h51) ^ in[12];
d_o[13] = (syndrome_o == 7'h4c) ^ in[13];
d_o[14] = (syndrome_o == 7'h23) ^ in[14];
d_o[15] = (syndrome_o == 7'h1c) ^ in[15];
d_o[16] = (syndrome_o == 7'he) ^ in[16];
d_o[17] = (syndrome_o == 7'h13) ^ in[17];
d_o[18] = (syndrome_o == 7'h61) ^ in[18];
d_o[19] = (syndrome_o == 7'h19) ^ in[19];
d_o[20] = (syndrome_o == 7'h1a) ^ in[20];
d_o[21] = (syndrome_o == 7'h58) ^ in[21];
d_o[22] = (syndrome_o == 7'h2a) ^ in[22];
d_o[23] = (syndrome_o == 7'h70) ^ in[23];
d_o[24] = (syndrome_o == 7'h25) ^ in[24];
d_o[25] = (syndrome_o == 7'h32) ^ in[25];
d_o[26] = (syndrome_o == 7'h43) ^ in[26];
d_o[27] = (syndrome_o == 7'h16) ^ in[27];
d_o[28] = (syndrome_o == 7'h68) ^ in[28];
d_o[29] = (syndrome_o == 7'h4a) ^ in[29];
d_o[30] = (syndrome_o == 7'h38) ^ in[30];
d_o[31] = (syndrome_o == 7'h31) ^ in[31];
// err_o calc. bit0: single error, bit1: double error
single_error = ^syndrome_o;
err_o[0] = single_error;
err_o[1] = ~single_error & (|syndrome_o);
dec.data = d_o;
dec.syndrome = syndrome_o;
dec.err = err_o;
return dec;
endfunction
function automatic logic [63:0] prim_secded_64_57_enc (logic [56:0] in);
logic [63:0] out;
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);
return out;
endfunction
function automatic secded_64_57_t prim_secded_64_57_dec (logic [63:0] in);
logic [56:0] d_o;
logic [6:0] syndrome_o;
logic [1:0] err_o;
secded_64_57_t dec;
logic single_error;
// Syndrome calculation
syndrome_o[0] = ^(in & 64'h0303FFF800007FFF);
syndrome_o[1] = ^(in & 64'h057C1FF801FF801F);
syndrome_o[2] = ^(in & 64'h09BDE1F87E0781E1);
syndrome_o[3] = ^(in & 64'h11DEEE3B8E388E22);
syndrome_o[4] = ^(in & 64'h21EF76CDB2C93244);
syndrome_o[5] = ^(in & 64'h41F7BB56D5525488);
syndrome_o[6] = ^(in & 64'h81FBDDA769A46910);
// Corrected output calculation
d_o[0] = (syndrome_o == 7'h7) ^ in[0];
d_o[1] = (syndrome_o == 7'hb) ^ in[1];
d_o[2] = (syndrome_o == 7'h13) ^ in[2];
d_o[3] = (syndrome_o == 7'h23) ^ in[3];
d_o[4] = (syndrome_o == 7'h43) ^ in[4];
d_o[5] = (syndrome_o == 7'hd) ^ in[5];
d_o[6] = (syndrome_o == 7'h15) ^ in[6];
d_o[7] = (syndrome_o == 7'h25) ^ in[7];
d_o[8] = (syndrome_o == 7'h45) ^ in[8];
d_o[9] = (syndrome_o == 7'h19) ^ in[9];
d_o[10] = (syndrome_o == 7'h29) ^ in[10];
d_o[11] = (syndrome_o == 7'h49) ^ in[11];
d_o[12] = (syndrome_o == 7'h31) ^ in[12];
d_o[13] = (syndrome_o == 7'h51) ^ in[13];
d_o[14] = (syndrome_o == 7'h61) ^ in[14];
d_o[15] = (syndrome_o == 7'he) ^ in[15];
d_o[16] = (syndrome_o == 7'h16) ^ in[16];
d_o[17] = (syndrome_o == 7'h26) ^ in[17];
d_o[18] = (syndrome_o == 7'h46) ^ in[18];
d_o[19] = (syndrome_o == 7'h1a) ^ in[19];
d_o[20] = (syndrome_o == 7'h2a) ^ in[20];
d_o[21] = (syndrome_o == 7'h4a) ^ in[21];
d_o[22] = (syndrome_o == 7'h32) ^ in[22];
d_o[23] = (syndrome_o == 7'h52) ^ in[23];
d_o[24] = (syndrome_o == 7'h62) ^ in[24];
d_o[25] = (syndrome_o == 7'h1c) ^ in[25];
d_o[26] = (syndrome_o == 7'h2c) ^ in[26];
d_o[27] = (syndrome_o == 7'h4c) ^ in[27];
d_o[28] = (syndrome_o == 7'h34) ^ in[28];
d_o[29] = (syndrome_o == 7'h54) ^ in[29];
d_o[30] = (syndrome_o == 7'h64) ^ in[30];
d_o[31] = (syndrome_o == 7'h38) ^ in[31];
d_o[32] = (syndrome_o == 7'h58) ^ in[32];
d_o[33] = (syndrome_o == 7'h68) ^ in[33];
d_o[34] = (syndrome_o == 7'h70) ^ in[34];
d_o[35] = (syndrome_o == 7'h1f) ^ in[35];
d_o[36] = (syndrome_o == 7'h2f) ^ in[36];
d_o[37] = (syndrome_o == 7'h4f) ^ in[37];
d_o[38] = (syndrome_o == 7'h37) ^ in[38];
d_o[39] = (syndrome_o == 7'h57) ^ in[39];
d_o[40] = (syndrome_o == 7'h67) ^ in[40];
d_o[41] = (syndrome_o == 7'h3b) ^ in[41];
d_o[42] = (syndrome_o == 7'h5b) ^ in[42];
d_o[43] = (syndrome_o == 7'h6b) ^ in[43];
d_o[44] = (syndrome_o == 7'h73) ^ in[44];
d_o[45] = (syndrome_o == 7'h3d) ^ in[45];
d_o[46] = (syndrome_o == 7'h5d) ^ in[46];
d_o[47] = (syndrome_o == 7'h6d) ^ in[47];
d_o[48] = (syndrome_o == 7'h75) ^ in[48];
d_o[49] = (syndrome_o == 7'h79) ^ in[49];
d_o[50] = (syndrome_o == 7'h3e) ^ in[50];
d_o[51] = (syndrome_o == 7'h5e) ^ in[51];
d_o[52] = (syndrome_o == 7'h6e) ^ in[52];
d_o[53] = (syndrome_o == 7'h76) ^ in[53];
d_o[54] = (syndrome_o == 7'h7a) ^ in[54];
d_o[55] = (syndrome_o == 7'h7c) ^ in[55];
d_o[56] = (syndrome_o == 7'h7f) ^ in[56];
// err_o calc. bit0: single error, bit1: double error
single_error = ^syndrome_o;
err_o[0] = single_error;
err_o[1] = ~single_error & (|syndrome_o);
dec.data = d_o;
dec.syndrome = syndrome_o;
dec.err = err_o;
return dec;
endfunction
function automatic logic [71:0] prim_secded_72_64_enc (logic [63:0] in);
logic [71:0] out;
out = 72'(in);
out[64] = ^(out & 72'h009D000000001FFFFF);
out[65] = ^(out & 72'h007600000FFFE0003F);
out[66] = ^(out & 72'h0079003FF003E007C1);
out[67] = ^(out & 72'h00A70FC0F03C207842);
out[68] = ^(out & 72'h00D371C711C4438884);
out[69] = ^(out & 72'h00F8B65926488C9108);
out[70] = ^(out & 72'h00AEDAAA4A91152210);
out[71] = ^(out & 72'h004FED348D221A4420);
return out;
endfunction
function automatic secded_72_64_t prim_secded_72_64_dec (logic [71:0] in);
logic [63:0] d_o;
logic [7:0] syndrome_o;
logic [1:0] err_o;
secded_72_64_t dec;
logic single_error;
// Syndrome calculation
syndrome_o[0] = ^(in & 72'h019D000000001FFFFF);
syndrome_o[1] = ^(in & 72'h027600000FFFE0003F);
syndrome_o[2] = ^(in & 72'h0479003FF003E007C1);
syndrome_o[3] = ^(in & 72'h08A70FC0F03C207842);
syndrome_o[4] = ^(in & 72'h10D371C711C4438884);
syndrome_o[5] = ^(in & 72'h20F8B65926488C9108);
syndrome_o[6] = ^(in & 72'h40AEDAAA4A91152210);
syndrome_o[7] = ^(in & 72'h804FED348D221A4420);
// Corrected output calculation
d_o[0] = (syndrome_o == 8'h7) ^ in[0];
d_o[1] = (syndrome_o == 8'hb) ^ in[1];
d_o[2] = (syndrome_o == 8'h13) ^ in[2];
d_o[3] = (syndrome_o == 8'h23) ^ in[3];
d_o[4] = (syndrome_o == 8'h43) ^ in[4];
d_o[5] = (syndrome_o == 8'h83) ^ in[5];
d_o[6] = (syndrome_o == 8'hd) ^ in[6];
d_o[7] = (syndrome_o == 8'h15) ^ in[7];
d_o[8] = (syndrome_o == 8'h25) ^ in[8];
d_o[9] = (syndrome_o == 8'h45) ^ in[9];
d_o[10] = (syndrome_o == 8'h85) ^ in[10];
d_o[11] = (syndrome_o == 8'h19) ^ in[11];
d_o[12] = (syndrome_o == 8'h29) ^ in[12];
d_o[13] = (syndrome_o == 8'h49) ^ in[13];
d_o[14] = (syndrome_o == 8'h89) ^ in[14];
d_o[15] = (syndrome_o == 8'h31) ^ in[15];
d_o[16] = (syndrome_o == 8'h51) ^ in[16];
d_o[17] = (syndrome_o == 8'h91) ^ in[17];
d_o[18] = (syndrome_o == 8'h61) ^ in[18];
d_o[19] = (syndrome_o == 8'ha1) ^ in[19];
d_o[20] = (syndrome_o == 8'hc1) ^ in[20];
d_o[21] = (syndrome_o == 8'he) ^ in[21];
d_o[22] = (syndrome_o == 8'h16) ^ in[22];
d_o[23] = (syndrome_o == 8'h26) ^ in[23];
d_o[24] = (syndrome_o == 8'h46) ^ in[24];
d_o[25] = (syndrome_o == 8'h86) ^ in[25];
d_o[26] = (syndrome_o == 8'h1a) ^ in[26];
d_o[27] = (syndrome_o == 8'h2a) ^ in[27];
d_o[28] = (syndrome_o == 8'h4a) ^ in[28];
d_o[29] = (syndrome_o == 8'h8a) ^ in[29];
d_o[30] = (syndrome_o == 8'h32) ^ in[30];
d_o[31] = (syndrome_o == 8'h52) ^ in[31];
d_o[32] = (syndrome_o == 8'h92) ^ in[32];
d_o[33] = (syndrome_o == 8'h62) ^ in[33];
d_o[34] = (syndrome_o == 8'ha2) ^ in[34];
d_o[35] = (syndrome_o == 8'hc2) ^ in[35];
d_o[36] = (syndrome_o == 8'h1c) ^ in[36];
d_o[37] = (syndrome_o == 8'h2c) ^ in[37];
d_o[38] = (syndrome_o == 8'h4c) ^ in[38];
d_o[39] = (syndrome_o == 8'h8c) ^ in[39];
d_o[40] = (syndrome_o == 8'h34) ^ in[40];
d_o[41] = (syndrome_o == 8'h54) ^ in[41];
d_o[42] = (syndrome_o == 8'h94) ^ in[42];
d_o[43] = (syndrome_o == 8'h64) ^ in[43];
d_o[44] = (syndrome_o == 8'ha4) ^ in[44];
d_o[45] = (syndrome_o == 8'hc4) ^ in[45];
d_o[46] = (syndrome_o == 8'h38) ^ in[46];
d_o[47] = (syndrome_o == 8'h58) ^ in[47];
d_o[48] = (syndrome_o == 8'h98) ^ in[48];
d_o[49] = (syndrome_o == 8'h68) ^ in[49];
d_o[50] = (syndrome_o == 8'ha8) ^ in[50];
d_o[51] = (syndrome_o == 8'hc8) ^ in[51];
d_o[52] = (syndrome_o == 8'h70) ^ in[52];
d_o[53] = (syndrome_o == 8'hb0) ^ in[53];
d_o[54] = (syndrome_o == 8'hd0) ^ in[54];
d_o[55] = (syndrome_o == 8'he0) ^ in[55];
d_o[56] = (syndrome_o == 8'h9d) ^ in[56];
d_o[57] = (syndrome_o == 8'hda) ^ in[57];
d_o[58] = (syndrome_o == 8'hcb) ^ in[58];
d_o[59] = (syndrome_o == 8'he5) ^ in[59];
d_o[60] = (syndrome_o == 8'h37) ^ in[60];
d_o[61] = (syndrome_o == 8'h6e) ^ in[61];
d_o[62] = (syndrome_o == 8'hb6) ^ in[62];
d_o[63] = (syndrome_o == 8'h79) ^ in[63];
// err_o calc. bit0: single error, bit1: double error
single_error = ^syndrome_o;
err_o[0] = single_error;
err_o[1] = ~single_error & (|syndrome_o);
dec.data = d_o;
dec.syndrome = syndrome_o;
dec.err = err_o;
return dec;
endfunction
function automatic logic [21:0] prim_secded_hamming_22_16_enc (logic [15:0] in);
logic [21:0] out;
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);
return out;
endfunction
function automatic secded_hamming_22_16_t prim_secded_hamming_22_16_dec (logic [21:0] in);
logic [15:0] d_o;
logic [5:0] syndrome_o;
logic [1:0] err_o;
secded_hamming_22_16_t dec;
// Syndrome calculation
syndrome_o[0] = ^(in & 22'h01AD5B);
syndrome_o[1] = ^(in & 22'h02366D);
syndrome_o[2] = ^(in & 22'h04C78E);
syndrome_o[3] = ^(in & 22'h0807F0);
syndrome_o[4] = ^(in & 22'h10F800);
syndrome_o[5] = ^(in & 22'h3FFFFF);
// Corrected output calculation
d_o[0] = (syndrome_o == 6'h23) ^ in[0];
d_o[1] = (syndrome_o == 6'h25) ^ in[1];
d_o[2] = (syndrome_o == 6'h26) ^ in[2];
d_o[3] = (syndrome_o == 6'h27) ^ in[3];
d_o[4] = (syndrome_o == 6'h29) ^ in[4];
d_o[5] = (syndrome_o == 6'h2a) ^ in[5];
d_o[6] = (syndrome_o == 6'h2b) ^ in[6];
d_o[7] = (syndrome_o == 6'h2c) ^ in[7];
d_o[8] = (syndrome_o == 6'h2d) ^ in[8];
d_o[9] = (syndrome_o == 6'h2e) ^ in[9];
d_o[10] = (syndrome_o == 6'h2f) ^ in[10];
d_o[11] = (syndrome_o == 6'h31) ^ in[11];
d_o[12] = (syndrome_o == 6'h32) ^ in[12];
d_o[13] = (syndrome_o == 6'h33) ^ in[13];
d_o[14] = (syndrome_o == 6'h34) ^ in[14];
d_o[15] = (syndrome_o == 6'h35) ^ in[15];
// err_o calc. bit0: single error, bit1: double error
err_o[0] = syndrome_o[5];
err_o[1] = |syndrome_o[4:0] & ~syndrome_o[5];
dec.data = d_o;
dec.syndrome = syndrome_o;
dec.err = err_o;
return dec;
endfunction
function automatic logic [38:0] prim_secded_hamming_39_32_enc (logic [31:0] in);
logic [38:0] out;
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);
return out;
endfunction
function automatic secded_hamming_39_32_t prim_secded_hamming_39_32_dec (logic [38:0] in);
logic [31:0] d_o;
logic [6:0] syndrome_o;
logic [1:0] err_o;
secded_hamming_39_32_t dec;
// Syndrome calculation
syndrome_o[0] = ^(in & 39'h0156AAAD5B);
syndrome_o[1] = ^(in & 39'h029B33366D);
syndrome_o[2] = ^(in & 39'h04E3C3C78E);
syndrome_o[3] = ^(in & 39'h0803FC07F0);
syndrome_o[4] = ^(in & 39'h1003FFF800);
syndrome_o[5] = ^(in & 39'h20FC000000);
syndrome_o[6] = ^(in & 39'h7FFFFFFFFF);
// Corrected output calculation
d_o[0] = (syndrome_o == 7'h43) ^ in[0];
d_o[1] = (syndrome_o == 7'h45) ^ in[1];
d_o[2] = (syndrome_o == 7'h46) ^ in[2];
d_o[3] = (syndrome_o == 7'h47) ^ in[3];
d_o[4] = (syndrome_o == 7'h49) ^ in[4];
d_o[5] = (syndrome_o == 7'h4a) ^ in[5];
d_o[6] = (syndrome_o == 7'h4b) ^ in[6];
d_o[7] = (syndrome_o == 7'h4c) ^ in[7];
d_o[8] = (syndrome_o == 7'h4d) ^ in[8];
d_o[9] = (syndrome_o == 7'h4e) ^ in[9];
d_o[10] = (syndrome_o == 7'h4f) ^ in[10];
d_o[11] = (syndrome_o == 7'h51) ^ in[11];
d_o[12] = (syndrome_o == 7'h52) ^ in[12];
d_o[13] = (syndrome_o == 7'h53) ^ in[13];
d_o[14] = (syndrome_o == 7'h54) ^ in[14];
d_o[15] = (syndrome_o == 7'h55) ^ in[15];
d_o[16] = (syndrome_o == 7'h56) ^ in[16];
d_o[17] = (syndrome_o == 7'h57) ^ in[17];
d_o[18] = (syndrome_o == 7'h58) ^ in[18];
d_o[19] = (syndrome_o == 7'h59) ^ in[19];
d_o[20] = (syndrome_o == 7'h5a) ^ in[20];
d_o[21] = (syndrome_o == 7'h5b) ^ in[21];
d_o[22] = (syndrome_o == 7'h5c) ^ in[22];
d_o[23] = (syndrome_o == 7'h5d) ^ in[23];
d_o[24] = (syndrome_o == 7'h5e) ^ in[24];
d_o[25] = (syndrome_o == 7'h5f) ^ in[25];
d_o[26] = (syndrome_o == 7'h61) ^ in[26];
d_o[27] = (syndrome_o == 7'h62) ^ in[27];
d_o[28] = (syndrome_o == 7'h63) ^ in[28];
d_o[29] = (syndrome_o == 7'h64) ^ in[29];
d_o[30] = (syndrome_o == 7'h65) ^ in[30];
d_o[31] = (syndrome_o == 7'h66) ^ in[31];
// err_o calc. bit0: single error, bit1: double error
err_o[0] = syndrome_o[6];
err_o[1] = |syndrome_o[5:0] & ~syndrome_o[6];
dec.data = d_o;
dec.syndrome = syndrome_o;
dec.err = err_o;
return dec;
endfunction
function automatic logic [71:0] prim_secded_hamming_72_64_enc (logic [63:0] in);
logic [71:0] out;
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);
return out;
endfunction
function automatic secded_hamming_72_64_t prim_secded_hamming_72_64_dec (logic [71:0] in);
logic [63:0] d_o;
logic [7:0] syndrome_o;
logic [1:0] err_o;
secded_hamming_72_64_t dec;
// Syndrome calculation
syndrome_o[0] = ^(in & 72'h01AB55555556AAAD5B);
syndrome_o[1] = ^(in & 72'h02CD9999999B33366D);
syndrome_o[2] = ^(in & 72'h04F1E1E1E1E3C3C78E);
syndrome_o[3] = ^(in & 72'h0801FE01FE03FC07F0);
syndrome_o[4] = ^(in & 72'h1001FFFE0003FFF800);
syndrome_o[5] = ^(in & 72'h2001FFFFFFFC000000);
syndrome_o[6] = ^(in & 72'h40FE00000000000000);
syndrome_o[7] = ^(in & 72'hFFFFFFFFFFFFFFFFFF);
// Corrected output calculation
d_o[0] = (syndrome_o == 8'h83) ^ in[0];
d_o[1] = (syndrome_o == 8'h85) ^ in[1];
d_o[2] = (syndrome_o == 8'h86) ^ in[2];
d_o[3] = (syndrome_o == 8'h87) ^ in[3];
d_o[4] = (syndrome_o == 8'h89) ^ in[4];
d_o[5] = (syndrome_o == 8'h8a) ^ in[5];
d_o[6] = (syndrome_o == 8'h8b) ^ in[6];
d_o[7] = (syndrome_o == 8'h8c) ^ in[7];
d_o[8] = (syndrome_o == 8'h8d) ^ in[8];
d_o[9] = (syndrome_o == 8'h8e) ^ in[9];
d_o[10] = (syndrome_o == 8'h8f) ^ in[10];
d_o[11] = (syndrome_o == 8'h91) ^ in[11];
d_o[12] = (syndrome_o == 8'h92) ^ in[12];
d_o[13] = (syndrome_o == 8'h93) ^ in[13];
d_o[14] = (syndrome_o == 8'h94) ^ in[14];
d_o[15] = (syndrome_o == 8'h95) ^ in[15];
d_o[16] = (syndrome_o == 8'h96) ^ in[16];
d_o[17] = (syndrome_o == 8'h97) ^ in[17];
d_o[18] = (syndrome_o == 8'h98) ^ in[18];
d_o[19] = (syndrome_o == 8'h99) ^ in[19];
d_o[20] = (syndrome_o == 8'h9a) ^ in[20];
d_o[21] = (syndrome_o == 8'h9b) ^ in[21];
d_o[22] = (syndrome_o == 8'h9c) ^ in[22];
d_o[23] = (syndrome_o == 8'h9d) ^ in[23];
d_o[24] = (syndrome_o == 8'h9e) ^ in[24];
d_o[25] = (syndrome_o == 8'h9f) ^ in[25];
d_o[26] = (syndrome_o == 8'ha1) ^ in[26];
d_o[27] = (syndrome_o == 8'ha2) ^ in[27];
d_o[28] = (syndrome_o == 8'ha3) ^ in[28];
d_o[29] = (syndrome_o == 8'ha4) ^ in[29];
d_o[30] = (syndrome_o == 8'ha5) ^ in[30];
d_o[31] = (syndrome_o == 8'ha6) ^ in[31];
d_o[32] = (syndrome_o == 8'ha7) ^ in[32];
d_o[33] = (syndrome_o == 8'ha8) ^ in[33];
d_o[34] = (syndrome_o == 8'ha9) ^ in[34];
d_o[35] = (syndrome_o == 8'haa) ^ in[35];
d_o[36] = (syndrome_o == 8'hab) ^ in[36];
d_o[37] = (syndrome_o == 8'hac) ^ in[37];
d_o[38] = (syndrome_o == 8'had) ^ in[38];
d_o[39] = (syndrome_o == 8'hae) ^ in[39];
d_o[40] = (syndrome_o == 8'haf) ^ in[40];
d_o[41] = (syndrome_o == 8'hb0) ^ in[41];
d_o[42] = (syndrome_o == 8'hb1) ^ in[42];
d_o[43] = (syndrome_o == 8'hb2) ^ in[43];
d_o[44] = (syndrome_o == 8'hb3) ^ in[44];
d_o[45] = (syndrome_o == 8'hb4) ^ in[45];
d_o[46] = (syndrome_o == 8'hb5) ^ in[46];
d_o[47] = (syndrome_o == 8'hb6) ^ in[47];
d_o[48] = (syndrome_o == 8'hb7) ^ in[48];
d_o[49] = (syndrome_o == 8'hb8) ^ in[49];
d_o[50] = (syndrome_o == 8'hb9) ^ in[50];
d_o[51] = (syndrome_o == 8'hba) ^ in[51];
d_o[52] = (syndrome_o == 8'hbb) ^ in[52];
d_o[53] = (syndrome_o == 8'hbc) ^ in[53];
d_o[54] = (syndrome_o == 8'hbd) ^ in[54];
d_o[55] = (syndrome_o == 8'hbe) ^ in[55];
d_o[56] = (syndrome_o == 8'hbf) ^ in[56];
d_o[57] = (syndrome_o == 8'hc1) ^ in[57];
d_o[58] = (syndrome_o == 8'hc2) ^ in[58];
d_o[59] = (syndrome_o == 8'hc3) ^ in[59];
d_o[60] = (syndrome_o == 8'hc4) ^ in[60];
d_o[61] = (syndrome_o == 8'hc5) ^ in[61];
d_o[62] = (syndrome_o == 8'hc6) ^ in[62];
d_o[63] = (syndrome_o == 8'hc7) ^ in[63];
// err_o calc. bit0: single error, bit1: double error
err_o[0] = syndrome_o[7];
err_o[1] = |syndrome_o[6:0] & ~syndrome_o[7];
dec.data = d_o;
dec.syndrome = syndrome_o;
dec.err = err_o;
return dec;
endfunction
endpackage

View file

@ -13,7 +13,11 @@
* - A parameter `Width` giving the memory width (word size) in bit.
* - A parameter `Depth` giving the memory depth in words.
* - A parameter `MemInitFile` with a file path of a VMEM file to be loaded into
* the memory if not empty.
* the memory if not empty.
*
* Note this works with memories up to a maximum width of 312 bits. Should this maximum width be
* increased all of the `simutil_set_mem` and `simutil_get_mem` call sites must be found (e.g. using
* git grep) and adjusted appropriately.
*/
`ifndef SYNTHESIS
@ -29,10 +33,10 @@
// Returns 1 (true) for success, 0 (false) for errors.
export "DPI-C" function simutil_set_mem;
function int simutil_set_mem(input int index, input bit [255:0] val);
function int simutil_set_mem(input int index, input bit [311:0] val);
// Function will only work for memories <= 256 bits
if (Width > 256) begin
// Function will only work for memories <= 312 bits
if (Width > 312) begin
return 0;
end
@ -47,10 +51,10 @@
// Function for getting a specific element in |mem|
export "DPI-C" function simutil_get_mem;
function int simutil_get_mem(input int index, output bit [255:0] val);
function int simutil_get_mem(input int index, output bit [311:0] val);
// Function will only work for memories <= 256 bits
if (Width > 256) begin
// Function will only work for memories <= 312 bits
if (Width > 312) begin
return 0;
end

View file

@ -9,6 +9,7 @@ filesets:
files_rtl:
depend:
- lowrisc:prim:assert
- lowrisc:prim:ram_1p_pkg
- lowrisc:prim:util_memload
files:
- rtl/prim_generic_ram_1p.sv

View file

@ -9,6 +9,7 @@ filesets:
files_rtl:
depend:
- lowrisc:prim:assert
- lowrisc:prim:ram_2p_pkg
- lowrisc:prim:util_memload
files:
- rtl/prim_generic_ram_2p.sv

View file

@ -9,6 +9,7 @@ filesets:
files_rtl:
depend:
- lowrisc:prim:assert
- lowrisc:prim:rom_pkg
- lowrisc:prim:util_memload
files:
- rtl/prim_generic_rom.sv

View file

@ -151,6 +151,7 @@ module prim_generic_flash #(
.addr_o(cfg_addr),
.wdata_o(cfg_wdata),
.wmask_o(),
.intg_error_o(),
.rdata_i(cfg_rdata),
.rvalid_i(cfg_rvalid),
.rerror_i('0)
@ -166,7 +167,8 @@ module prim_generic_flash #(
.addr_i(cfg_addr),
.wdata_i(cfg_wdata),
.wmask_i({32{1'b1}}),
.rdata_o(cfg_rdata)
.rdata_o(cfg_rdata),
.cfg_i('0)
);
lc_ctrl_pkg::lc_tx_t unused_bist_enable;

View file

@ -381,7 +381,8 @@ module prim_generic_flash_bank #(
.addr_i (mem_addr),
.wdata_i (mem_wdata[MemWidth-1:0]),
.wmask_i ({MemWidth{1'b1}}),
.rdata_o (rd_nom_data_main)
.rdata_o (rd_nom_data_main),
.cfg_i ('0)
);
prim_ram_1p #(
@ -395,7 +396,8 @@ module prim_generic_flash_bank #(
.addr_i (mem_addr),
.wdata_i (mem_wdata[MemWidth +: MetaDataWidth]),
.wmask_i ({MetaDataWidth{1'b1}}),
.rdata_o (rd_meta_data_main)
.rdata_o (rd_meta_data_main),
.cfg_i ('0)
);
for (genvar info_type = 0; info_type < InfoTypes; info_type++) begin : gen_info_types
@ -416,7 +418,8 @@ module prim_generic_flash_bank #(
.addr_i (mem_addr[0 +: InfoAddrW]),
.wdata_i (mem_wdata[MemWidth-1:0]),
.wmask_i ({MemWidth{1'b1}}),
.rdata_o (rd_nom_data_info[info_type])
.rdata_o (rd_nom_data_info[info_type]),
.cfg_i ('0)
);
prim_ram_1p #(
@ -430,7 +433,8 @@ module prim_generic_flash_bank #(
.addr_i (mem_addr[0 +: InfoAddrW]),
.wdata_i (mem_wdata[MemWidth +: MetaDataWidth]),
.wmask_i ({MetaDataWidth{1'b1}}),
.rdata_o (rd_meta_data_info[info_type])
.rdata_o (rd_meta_data_info[info_type]),
.cfg_i ('0)
);
end

View file

@ -78,6 +78,7 @@ module prim_generic_otp
.addr_o ( tlul_addr ),
.wdata_o ( tlul_wdata ),
.wmask_o ( ),
.intg_error_o( ),
.rdata_i ( tlul_rdata_q ),
.rvalid_i ( tlul_rvalid_q ),
.rerror_i ( '0 )

View file

@ -6,7 +6,7 @@
`include "prim_assert.sv"
module prim_generic_ram_1p #(
module prim_generic_ram_1p import prim_ram_1p_pkg::*; #(
parameter int Width = 32, // bit
parameter int Depth = 128,
parameter int DataBitsPerMask = 1, // Number of data bits per bit of write mask
@ -21,9 +21,13 @@ module prim_generic_ram_1p #(
input logic [Aw-1:0] addr_i,
input logic [Width-1:0] wdata_i,
input logic [Width-1:0] wmask_i,
output logic [Width-1:0] rdata_o // Read data. Data is returned one cycle after req_i is high.
output logic [Width-1:0] rdata_o, // Read data. Data is returned one cycle after req_i is high.
input ram_1p_cfg_t cfg_i
);
logic unused_cfg;
assign unused_cfg = ^cfg_i;
// Width of internal write mask. Note wmask_i input into the module is always assumed
// to be the full bit mask
localparam int MaskWidth = Width / DataBitsPerMask;

View file

@ -6,7 +6,7 @@
// This module is for simulation and small size SRAM.
// Implementing ECC should be done inside wrapper not this model.
`include "prim_assert.sv"
module prim_generic_ram_2p #(
module prim_generic_ram_2p import prim_ram_2p_pkg::*; #(
parameter int Width = 32, // bit
parameter int Depth = 128,
parameter int DataBitsPerMask = 1, // Number of data bits per bit of write mask
@ -30,8 +30,14 @@ module prim_generic_ram_2p #(
input [Aw-1:0] b_addr_i,
input [Width-1:0] b_wdata_i,
input logic [Width-1:0] b_wmask_i,
output logic [Width-1:0] b_rdata_o
output logic [Width-1:0] b_rdata_o,
input ram_2p_cfg_t cfg_i
);
logic unused_cfg;
assign unused_cfg = ^cfg_i;
// Width of internal write mask. Note *_wmask_i input into the module is always assumed
// to be the full bit mask.
localparam int MaskWidth = Width / DataBitsPerMask;

View file

@ -4,7 +4,7 @@
`include "prim_assert.sv"
module prim_generic_rom #(
module prim_generic_rom import prim_rom_pkg::*; #(
parameter int Width = 32,
parameter int Depth = 2048, // 8kB default
parameter MemInitFile = "", // VMEM file to initialize the memory with
@ -14,9 +14,13 @@ module prim_generic_rom #(
input logic clk_i,
input logic req_i,
input logic [Aw-1:0] addr_i,
output logic [Width-1:0] rdata_o
output logic [Width-1:0] rdata_o,
input rom_cfg_t cfg_i
);
logic unused_cfg;
assign unused_cfg = ^cfg_i;
logic [Width-1:0] mem [Depth];
always_ff @(posedge clk_i) begin

View file

@ -2,6 +2,7 @@
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
export SHELL := /bin/bash
.DEFAULT_GOAL := all
all: build

View file

@ -13,3 +13,8 @@ lint_off -rule PINCONNECTEMPTY
// This warning gives wrong results with blackboxed embedded modules, see
// https://github.com/verilator/verilator/issues/2430
lint_off -rule DECLFILENAME -file "*" -match "Filename '*' does not match NOTFOUNDMODULE name:*"
// Don't generate lint errors for unused parameters in packages. The point is
// that a user of a package might not want to use all of the parameters it
// defines.
lint_off -rule UNUSED -file "*_pkg.sv" -match "*Parameter is not used*"

File diff suppressed because it is too large Load diff

View file

@ -73,9 +73,7 @@ class FlowCfg():
self.deploy = []
# Timestamp
self.ts_format_long = args.ts_format_long
self.timestamp_long = args.timestamp_long
self.ts_format = args.ts_format
self.timestamp = args.timestamp
# Results

232
vendor/lowrisc_ip/util/dvsim/Launcher.py vendored Normal file
View file

@ -0,0 +1,232 @@
# 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 os
import re
from pathlib import Path
from utils import VERBOSE, clean_odirs, rm_path
class LauncherError(Exception):
def __init__(self, msg):
self.msg = msg
class Launcher:
"""
Abstraction for launching and maintaining a job.
An abstract class that provides methods to prepare a job's environment,
launch the job, poll for its completion and finally do some cleanup
activities. This class is not meant to be instantiated directly. Each
launcher object holds an instance of the deploy object.
"""
# If a history of previous invocations is to be maintained, then keep no
# more than this many directories.
max_odirs = 5
def __str__(self):
return self.deploy.full_name + ":launcher"
def __init__(self, deploy):
# Store the deploy object handle.
self.deploy = deploy
# Return status of the process running the job.
self.exit_code = None
# Flag to indicate whether to 'overwrite' if odir already exists,
# or to backup the existing one and create a new one.
# For builds, we want to overwrite existing to leverage the tools'
# incremental / partition compile features. For runs, we may want to
# create a new one.
self.renew_odir = False
# Construct failure message if the test fails.
self.fail_msg = "\n**{!r}:** {!r}<br>\n".format(
self.deploy.target.upper(), self.deploy.qual_name)
self.fail_msg += "**LOG:** {}<br>\n".format(self.deploy.get_log_path())
def _make_odir(self):
"""Create the output directory."""
# If renew_odir flag is True - then move it.
if self.renew_odir:
clean_odirs(odir=self.deploy.odir, max_odirs=self.max_odirs)
os.makedirs(self.deploy.odir, exist_ok=True)
def _dump_env_vars(self, exports):
"""Write env vars to a file for ease of debug.
Each extended class computes the list of exports and invokes this
method right before launching the job.
"""
with open(self.deploy.odir + "/env_vars",
"w",
encoding="UTF-8",
errors="surrogateescape") as f:
for var in sorted(exports.keys()):
f.write("{}={}\n".format(var, exports[var]))
def _pre_launch(self):
"""Do pre-launch activities.
Examples include such as preparing the job's environment, clearing
old runs, creating the output directory, dumping all env variables
etc. This method is already invoked by launch() as the first step.
"""
self.deploy.pre_launch()
self._make_odir()
def _do_launch(self):
"""Launch the job."""
raise NotImplementedError()
def launch(self):
"""Launch the job."""
self._pre_launch()
self._do_launch()
def _post_finish(self, status):
"""Do post-completion activities, such as preparing the results.
Must be invoked by poll().
"""
assert status in ['P', 'F', 'K']
if status in ['P', 'F']:
self._link_odir(status)
self.deploy.post_finish(status)
log.debug("Item %s has completed execution: %s", self, status)
def poll(self):
"""Poll the launched job for completion.
Invokes _has_passed() and _post_finish() when the job completes.
"""
raise NotImplementedError()
def kill(self):
"""Terminate the job."""
raise NotImplementedError()
def _has_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 the pattern if any of the given
patterns is found, else None."""
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.deploy.dry_run:
return True
# Only one fail pattern needs to be seen.
failed = False
chk_failed = bool(self.deploy.fail_patterns)
# All pass patterns need to be seen, so we replicate the list and remove
# patterns as we encounter them.
pass_patterns = self.deploy.pass_patterns.copy()
chk_passed = bool(pass_patterns) and (self.exit_code == 0)
try:
with open(self.deploy.get_log_path(), "r", encoding="UTF-8") as f:
lines = f.readlines()
except OSError as e:
log_fail_msg("Error opening file {}:\n{}".format(
self.deploy.get_log_path(), e))
return False
if chk_failed or chk_passed:
for cnt, line in enumerate(lines):
if chk_failed:
if _find_patterns(self.deploy.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
if chk_passed:
pattern = _find_patterns(pass_patterns, line)
if pattern is not None:
pass_patterns.remove(pattern)
chk_passed = bool(pass_patterns)
# If failed, then nothing else to do. Just return.
if failed:
return False
# 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.exit_code != 0:
msg = ''.join(lines[-10:]).strip()
log_fail_msg("Job returned non-zero exit code. "
"Last 10 lines:\n```\n{}\n```\n".format(msg))
return False
# 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
return True
def _link_odir(self, status):
"""Soft-links the job's directory based on job's status.
The dispatched, passed and failed directories in the scratch area
provide a quick way to get to the job that was executed.
"""
dest = Path(self.deploy.sim_cfg.links[status], self.deploy.qual_name)
# If dest exists, then atomically remove it and link the odir again.
while True:
try:
os.symlink(self.deploy.odir, dest)
break
except FileExistsError:
rm_path(dest)
# Delete the symlink from dispatched directory if it exists.
if status != "D":
old = Path(self.deploy.sim_cfg.links['D'], self.deploy.qual_name)
rm_path(old)

View file

@ -0,0 +1,139 @@
# 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 os
import re
import shlex
import subprocess
from Launcher import Launcher, LauncherError
class LocalLauncher(Launcher):
"""
Implementation of Launcher to launch jobs in the user's local workstation.
"""
# Misc common LocalLauncher settings.
max_odirs = 5
def __init__(self, deploy):
'''Initialize common class members.'''
super().__init__(deploy)
# Popen object when launching the job.
self.process = None
def _do_launch(self):
# Update the shell's env vars with self.exports. Values in exports must
# replace the values in the shell's env vars if the keys match.
exports = os.environ.copy()
if self.deploy.exports:
exports.update(self.deploy.exports)
# Clear the magic MAKEFLAGS variable from exports if necessary. This
# variable is used by recursive Make calls to pass variables from one
# level to the next. Here, self.cmd is a call to Make but it's
# logically a top-level invocation: we don't want to pollute the flow's
# Makefile with Make variables from any wrapper that called dvsim.
if 'MAKEFLAGS' in exports:
del exports['MAKEFLAGS']
self._dump_env_vars(exports)
args = shlex.split(self.deploy.cmd)
try:
f = open(self.deploy.get_log_path(),
"w",
encoding="UTF-8",
errors="surrogateescape")
f.write("[Executing]:\n{}\n\n".format(self.deploy.cmd))
f.flush()
self.process = subprocess.Popen(args,
bufsize=4096,
universal_newlines=True,
stdout=f,
stderr=f,
env=exports)
except subprocess.SubprocessError as e:
raise LauncherError('IO Error: {}\nSee {}'.format(
e, self.deploy.get_log_path()))
finally:
self._close_process()
self._link_odir("D")
def poll(self):
'''Check status of the running process
This returns 'D', 'P' or 'F'. If 'D', the job is still running. If 'P',
the job finished successfully. If 'F', the job finished with an error.
This function must only be called after running self.dispatch_cmd() and
must not be called again once it has returned 'P' or 'F'.
'''
assert self.process is not None
if self.process.poll() is None:
return 'D'
self.exit_code = self.process.returncode
status = 'P' if self._has_passed() else 'F'
self._post_finish(status)
return status
def _post_finish(self, status):
super()._post_finish(status)
self._close_process()
self.process = None
def kill(self):
'''Kill the running process.
This must be called between dispatching and reaping the process (the
same window as poll()).
'''
assert self.process is not None
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()
self._post_finish('K')
def _close_process(self):
'''Close the file descriptors associated with the process.'''
assert self.process
if self.process.stdout:
self.process.stdout.close()
def kill_remote_job(self):
'''
If jobs are run in remote server, need to use another command to kill them.
'''
# TODO: Currently only support lsf, may need to add support for GCP later.
# If use lsf, kill it by job ID.
if re.match("^bsub", self.deploy.sim_cfg.job_prefix):
# get job id from below string
# Job <xxxxxx> is submitted to default queue
grep_cmd = "grep -m 1 -E \'" + "^Job <" + "\' " + \
self.deploy.get_log_path()
(status, rslt) = subprocess.getstatusoutput(grep_cmd)
if rslt != "":
job_id = rslt.split('Job <')[1].split('>')[0]
try:
subprocess.run(["bkill", job_id], check=True)
except Exception as e:
log.error("%s: Failed to run bkill\n", e)

View file

@ -7,7 +7,7 @@ import threading
from collections import OrderedDict
from signal import SIGINT, signal
from Deploy import DeployError
from Launcher import LauncherError
from Timer import Timer
from utils import VERBOSE
@ -42,32 +42,31 @@ class TargetScheduler:
def _kill_item(self, item):
'''Kill a running item'''
self._running.remove(item)
item.kill()
item.launcher.kill()
self._killed.add(item)
self.item_to_status[item] = 'K'
def _poll(self, hms):
'''Check for running items that have finished
'''Check for running items that have finished.
Returns True if something changed.
'''
to_pass = []
to_fail = []
for item in self._running:
status = item.poll()
status = item.launcher.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)
item.target, item.full_name)
to_pass.append(item)
else:
log.error("[%s]: [%s]: [status] [%s: F]", hms, item.target,
item.identifier)
item.full_name)
to_fail.append(item)
for item in to_pass:
@ -85,7 +84,6 @@ class TargetScheduler:
'''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),
@ -131,14 +129,14 @@ class TargetScheduler:
return
log.log(VERBOSE, "[%s]: [%s]: [dispatch]:\n%s", hms, self.name,
", ".join(item.identifier for item in to_dispatch))
", ".join(item.full_name 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:
item.launcher.launch()
except LauncherError as err:
log.error('{}'.format(err))
self._kill_item(item)
@ -167,7 +165,6 @@ class TargetScheduler:
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
@ -195,10 +192,7 @@ class TargetScheduler:
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()
@ -271,7 +265,6 @@ class Scheduler:
'''Run all items
Returns a map from item to status.
'''
timer = Timer()

View file

@ -62,7 +62,7 @@ class Results:
'''Recursively add a single item to the table of results'''
status = results[item]
if status == "F":
self.fail_msgs.append(item.fail_msg)
self.fail_msgs.append(item.launcher.fail_msg)
# Runs get added to the table directly
if item.target == "run":

View file

@ -30,10 +30,12 @@ import textwrap
from pathlib import Path
from CfgFactory import make_cfg
from Deploy import Deploy, RunTest
from Deploy import RunTest
from Launcher import Launcher
from Scheduler import Scheduler
from Timer import Timer
from utils import VERBOSE, rm_path, run_cmd_with_timeout
from utils import (TS_FORMAT, TS_FORMAT_LONG, VERBOSE, rm_path,
run_cmd_with_timeout)
# TODO: add dvsim_cfg.hjson to retrieve this info
version = 0.1
@ -162,13 +164,14 @@ def get_proj_root():
def resolve_proj_root(args):
'''Update proj_root based on how DVSim is invoked.
If --remote env var is set, a location in the scratch area is chosen as the
If --remote switch is set, a location in the scratch area is chosen as the
new proj_root. The entire repo is copied over to this location. Else, the
proj_root is discovered using get_proj_root() method, unless the user
overrides it on the command line.
This function returns the updated proj_root src and destination path. If
--remote env var is not set, the destination path is identical to the src path.
--remote switch is not set, the destination path is identical to the src
path. Likewise, if --dry-run is set.
'''
proj_root_src = args.proj_root or get_proj_root()
@ -176,19 +179,19 @@ def resolve_proj_root(args):
# then the repo needs to be copied over to the scratch area
# accessible to those machines.
# If --purge arg is set, then purge the repo_top that was copied before.
if args.remote:
if args.remote and not args.dry_run:
proj_root_dest = os.path.join(args.scratch_root, args.branch,
"repo_top")
if args.purge:
rm_path(proj_root_dest)
copy_repo(proj_root_src, proj_root_dest, args.dry_run)
copy_repo(proj_root_src, proj_root_dest)
else:
proj_root_dest = proj_root_src
return proj_root_src, proj_root_dest
def copy_repo(src, dest, dry_run):
def copy_repo(src, dest):
'''Copy over the repo to a new location.
The repo is copied over from src to dest area. It tentatively uses the
@ -217,17 +220,17 @@ def copy_repo(src, dest, dry_run):
log.info("[copy_repo] [dest]: %s", dest)
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)
try:
subprocess.run(cmd,
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
except subprocess.CalledProcessError as e:
log.error("Failed to copy over %s to %s: %s", src, dest,
e.stderr.decode("utf-8").strip())
# Make sure the dest exists first.
os.makedirs(dest, exist_ok=True)
try:
subprocess.run(cmd,
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
except subprocess.CalledProcessError as e:
log.error("Failed to copy over %s to %s: %s", src, dest,
e.stderr.decode("utf-8").strip())
log.info("Done.")
@ -620,16 +623,9 @@ def main():
args.cfg = os.path.join(proj_root, cfg_path)
# Add timestamp to args that all downstream objects can use.
# Static variables - indicate timestamp.
ts_format_long = "%A %B %d %Y %I:%M:%S%p UTC"
ts_format = "%a.%m.%d.%y__%I.%M.%S%p"
curr_ts = datetime.datetime.utcnow()
timestamp_long = curr_ts.strftime(ts_format_long)
timestamp = curr_ts.strftime(ts_format)
setattr(args, "ts_format_long", ts_format_long)
setattr(args, "ts_format", ts_format)
setattr(args, "timestamp_long", timestamp_long)
setattr(args, "timestamp", timestamp)
setattr(args, "timestamp_long", curr_ts.strftime(TS_FORMAT_LONG))
setattr(args, "timestamp", curr_ts.strftime(TS_FORMAT))
# Register the seeds from command line with RunTest class.
RunTest.seeds = args.seeds
@ -641,7 +637,7 @@ def main():
# Register the common deploy settings.
Timer.print_interval = args.print_interval
Scheduler.max_parallel = args.max_parallel
Deploy.max_odirs = args.max_odirs
Launcher.max_odirs = args.max_odirs
# Build infrastructure from hjson file and create the list of items to
# be deployed.

View file

@ -14,6 +14,8 @@ import subprocess
import sys
import time
from collections import OrderedDict
from datetime import datetime
from pathlib import Path
import hjson
import mistletoe
@ -22,6 +24,12 @@ from premailer import transform
# For verbose logging
VERBOSE = 15
# Timestamp format when creating directory backups.
TS_FORMAT = "%y.%m.%d_%H.%M.%S"
# Timestamp format when generating reports.
TS_FORMAT_LONG = "%A %B %d %Y %H:%M:%S UTC"
# Run a command and get the result. Exit with error if the command did not
# succeed. This is a simpler version of the run_cmd function below.
@ -541,3 +549,34 @@ def rm_path(path, ignore_error=False):
log.error("Failed to remove {}:\n{}.".format(path, e))
if not ignore_error:
raise e
def clean_odirs(odir, max_odirs, ts_format=TS_FORMAT):
"""Clean previous output directories.
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.
ts = datetime.fromtimestamp(os.stat(odir).st_ctime).strftime(ts_format)
shutil.move(odir, "{}_{}".format(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[max_odirs - 1:]:
if os.path.exists(old):
shutil.rmtree(old, ignore_errors=True)
return dirs[0:max_odirs - 2]

View file

@ -16,6 +16,7 @@ def gen_agent(name, has_separate_host_device_driver, root_dir, vendor):
agent_dir = root_dir + "/" + name + "_agent"
# yapf: disable
# flake8: noqa
# 4-tuple - path, ip name, class name, file ext
agent_srcs = [(agent_dir, name + '_', 'if', '.sv'),
(agent_dir, name + '_', 'item', '.sv'),

View file

@ -15,6 +15,7 @@ from uvmdvgen import VENDOR_DEFAULT
def gen_env(name, is_cip, has_ral, has_interrupts, has_alerts, has_edn,
env_agents, root_dir, vendor):
# yapf: disable
# flake8: noqa
# 4-tuple - sub-path, ip name, class name, file ext
env_srcs = [('dv/env', name + '_', 'env_cfg', '.sv'),
('dv/env', name + '_', 'env_cov', '.sv'),
@ -35,7 +36,7 @@ def gen_env(name, is_cip, has_ral, has_interrupts, has_alerts, has_edn,
('dv/tests', name + '_', 'test', '.core'),
('dv/cov', '', '', ''),
('dv', name + '_', 'sim_cfg', '.hjson'),
('doc/dv_plan', '', 'index', '.md'),
('doc/dv', '', 'index', '.md'),
('doc', '', 'checklist', '.md'),
('data', name + '_', 'testplan', '.hjson'),
('dv', name + '_', 'sim', '.core')]

View file

@ -1,20 +1,20 @@
---
title: "${name.upper()} DV Plan"
title: "${name.upper()} DV document"
---
<!-- Copy this file to hw/ip/${name}/doc/${name}_dv_plan.md and make changes as needed.
<!-- Copy this file to hw/ip/${name}/doc/dv/index.md and make changes as needed.
For convenience '${name}' in the document can be searched and replaced easily with the
desired IP (with case sensitivity!). Also, use the testbench block diagram
located at OpenTitan team drive / 'design verification'
as a starting point and modify it to reflect your ${name} testbench and save it
to hw/ip/${name}/doc/tb.svg. It should get linked and rendered under the block
to hw/ip/${name}/doc/dv/tb.svg. It should get linked and rendered under the block
diagram section below. Please update / modify / remove sections below as
applicable. Once done, remove this comment before making a PR. -->
${'##'} Goals
* **DV**
* Verify all ${name.upper()} IP features by running dynamic simulations with a SV/UVM based testbench
* Develop and run all tests based on the [testplan](#testplan) below towards closing code and functional coverage on the IP and all of its sub-modules
* Develop and run all tests based on the [DV plan](#dv-plan) below towards closing code and functional coverage on the IP and all of its sub-modules
* **FPV**
* Verify TileLink device protocol compliance with an SVA based testbench
@ -122,6 +122,6 @@ Here's how to run a smoke test:
$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/ip/${name}/dv/${name}_sim_cfg.hjson -i ${name}_smoke
```
${'##'} Testplan
${'##'} DV plan
<!-- TODO: uncomment the line below after adding the testplan -->
{{</* testplan "hw/ip/${name}/data/${name}_testplan.hjson" */>}}