| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| // FPV CSR read and write assertions auto-generated by `reggen` containing data structure |
| // Do Not Edit directly |
| |
| <% from reggen import (gen_fpv) |
| %>\ |
| <% from topgen import lib # TODO: Split lib to common lib module |
| %>\ |
| <%def name="construct_classes(block)">\ |
| % for b in block.blocks: |
| ${construct_classes(b)} |
| % endfor |
| |
| `include "prim_assert.sv" |
| |
| // Block: ${block.name} |
| module ${block.name}_csr_assert_fpv import tlul_pkg::*; ( |
| input clk_i, |
| input rst_ni, |
| |
| //tile link ports |
| input tl_h2d_t h2d, |
| input tl_d2h_t d2h |
| ); |
| |
| // mask register to convert byte to bit |
| logic [31:0] a_mask_bit; |
| |
| assign a_mask_bit[7:0] = h2d.a_mask[0] ? '1 : '0; |
| assign a_mask_bit[15:8] = h2d.a_mask[1] ? '1 : '0; |
| assign a_mask_bit[23:16] = h2d.a_mask[2] ? '1 : '0; |
| assign a_mask_bit[31:24] = h2d.a_mask[3] ? '1 : '0; |
| |
| <% |
| addr_msb = block.addr_width - 1 |
| %>\ |
| // declare common read and write sequences |
| sequence device_wr_S(logic [${addr_msb}:0] addr); |
| h2d.a_address == addr && h2d.a_opcode inside {PutFullData, PutPartialData} && h2d.a_valid && h2d.d_ready && !d2h.d_valid; |
| endsequence |
| |
| sequence device_rd_S(logic [${addr_msb}:0] addr); |
| h2d.a_address == addr && h2d.a_opcode inside {Get} && h2d.a_valid && h2d.d_ready && !d2h.d_valid; |
| endsequence |
| |
| // declare common read and write properties |
| property wr_P(int width, bit [${addr_msb}:0] addr, bit [31:0] compare_data, bit regen = 1); |
| logic [31:0] id; |
| logic [width:0] data; |
| (device_wr_S(addr),id = h2d.a_source, data = h2d.a_data & a_mask_bit) |-> |
| strong(##[1:$] (d2h.d_valid && d2h.d_source == id && (d2h.d_error || |
| (!d2h.d_error && compare_data == data) || !regen))); |
| endproperty |
| |
| property wr_ext_P(int width, bit [${addr_msb}:0] addr, bit [31:0] compare_data, bit regen = 1); |
| logic [31:0] id; |
| logic [width:0] data; |
| logic [width:0] compare_value; |
| (device_wr_S(addr),id = h2d.a_source, data = h2d.a_data & a_mask_bit, |
| compare_value = compare_data) |-> |
| strong(##[1:$] (d2h.d_valid && d2h.d_source == id && (d2h.d_error || |
| (!d2h.d_error && compare_value == data) || !regen))); |
| endproperty |
| |
| property rd_P(int width, bit [${addr_msb}:0] addr, bit [31:0] compare_data); |
| logic [31:0] id; |
| logic [width:0] data; |
| (device_rd_S(addr), id = h2d.a_source, data = $past(compare_data)) |-> |
| strong(##[1:$] (d2h.d_valid && d2h.d_source == id && (d2h.d_error || |
| (!d2h.d_error && d2h.d_data == data)))); |
| endproperty |
| |
| property rd_ext_P(int width, bit [${addr_msb}:0] addr, bit [31:0] compare_data); |
| logic [31:0] id; |
| logic [width:0] data; |
| (device_rd_S(addr), id = h2d.a_source, data = compare_data) |-> |
| strong(##[1:$] (d2h.d_valid && d2h.d_source == id && (d2h.d_error || |
| (!d2h.d_error && d2h.d_data == data)))); |
| endproperty |
| |
| property wr_regen_stable_P(regen, compare_data); |
| (!regen && $stable(regen)) |-> $stable(compare_data); |
| endproperty |
| |
| // for all the regsters, declare assertion |
| % for r in block.regs: |
| <% |
| i = -1 |
| msb = -1 |
| lsb = 0 |
| %>\ |
| % for reg_flat in r.get_regs_flat(): |
| <% |
| reg_name = reg_flat.name |
| reg_right = reg_flat.dvrights |
| reg_width = block.addr_width |
| reg_offset = str(reg_width) + "'h" + "%x" % reg_flat.offset |
| reg_msb = reg_flat.width - 1 |
| hwaccess = reg_flat.fields[0].hwaccess |
| regwen = reg_flat.regwen |
| %>\ |
| % if regwen: |
| <% |
| reg_wen = "i_"+ block.name + ".i_reg_top."+ regwen + "_qs" |
| %>\ |
| % else: |
| <% |
| reg_wen = "0" |
| %>\ |
| % endif |
| % if r.is_multi_reg(): |
| <% |
| r_multi_name = r.name |
| f = reg_flat.fields[0] |
| r_multi_width = f.msb - f.lsb + 1 |
| r_multi_depth = r.get_n_fields_flat() |
| r_multi_msb = r_multi_width * r_multi_depth -1 |
| i += 1 |
| lsb = i * (msb - lsb + 1) |
| msb = lsb + reg_msb |
| reg_d_path = r_multi_name + "_d_fpv[" + str(msb) + ":" + str(lsb) + "]" |
| reg_q_path = r_multi_name + "_q_fpv[" + str(msb) + ":" + str(lsb) + "]" |
| %>\ |
| % if (i == 0): |
| |
| // define local fpv variable for the multi_reg |
| % if reg_flat.get_n_bits(["q"]): |
| logic [${r_multi_msb}:0] ${r_multi_name}_q_fpv; |
| % if r_multi_width == 1: |
| for (genvar s = 0; s <= ${r_multi_msb}; s++) begin : gen_${r_multi_name}_rd |
| assign ${r_multi_name}_q_fpv[s] = i_${block.name}.reg2hw.${r_multi_name}[s].q; |
| % else: |
| for (genvar s = 0; s <= ${r_multi_depth}-1; s++) begin : gen_${r_multi_name}_rd |
| assign ${r_multi_name}_q_fpv[((s+1)*${r_multi_width}-1):s*${r_multi_width}] = i_${block.name}.reg2hw.${r_multi_name}[s].q; |
| % endif |
| end |
| % endif |
| % if reg_flat.get_n_bits(["d"]): |
| logic [${r_multi_msb}:0] ${r_multi_name}_d_fpv; |
| % if r_multi_width == 1: |
| for (genvar s = 0; s <= ${r_multi_msb}; s++) begin : gen_${r_multi_name}_wr |
| assign ${r_multi_name}_d_fpv[s] = i_${block.name}.hw2reg.${r_multi_name}[s].d; |
| % else: |
| for (genvar s = 0; s <= ${r_multi_depth}-1; s++) begin : gen_${r_multi_name}_wr |
| assign ${r_multi_name}_d_fpv[(s*${r_multi_width}-1):s] = i_${block.name}.hw2reg.${r_multi_name}[s].d; |
| % endif |
| end |
| % endif |
| % endif |
| % else : |
| <% |
| reg_d_path = "i_" + block.name + ".hw2reg." + reg_name + ".d" |
| reg_q_path = "i_" + block.name + ".reg2hw." + reg_name + ".q" |
| %>\ |
| % endif |
| % if reg_flat.hwext: |
| <% |
| wr_prperty = "wr_ext_P" |
| rd_prperty = "rd_ext_P" |
| %>\ |
| % else: |
| <% |
| wr_prperty = "wr_P" |
| rd_prperty = "rd_P" |
| %>\ |
| % endif |
| |
| % if reg_flat.get_n_bits(["q", "d"]) == 0: |
| <% |
| reg_we_path = "i_" + block.name + ".i_reg_top." + reg_name + "_we" |
| reg_qs_path = "i_" + block.name + ".i_reg_top." + reg_name + "_qs" |
| %>\ |
| % endif |
| // read/write assertions for register: ${reg_name} |
| % if reg_flat.dvrights in {"RW", "WO"}: |
| % if reg_flat.get_n_bits(["q", "d"]) == 0: |
| `ASSERT(${reg_name}_wr_A, ${wr_prperty}(${reg_msb}, ${reg_offset}, ${reg_we_path}, ${reg_wen})) |
| % else: |
| `ASSERT(${reg_name}_wr_A, ${wr_prperty}(${reg_msb}, ${reg_offset}, ${reg_q_path}, ${reg_wen})) |
| % endif |
| % if regwen: |
| `ASSERT(${reg_name}_stable_A, wr_regen_stable_P(${reg_wen}, ${reg_q_path})) |
| % endif |
| % endif |
| % if reg_flat.dvrights in {"RW", "RO"}: |
| % if reg_flat.get_n_bits(["q", "d"]) == 0: |
| `ASSERT(${reg_name}_rd_A, ${rd_prperty}(${reg_msb}, ${reg_offset}, ${reg_qs_path})) |
| % elif reg_flat.get_n_bits(["d"]): |
| `ASSERT(${reg_name}_rd_A, ${rd_prperty}(${reg_msb}, ${reg_offset}, ${reg_d_path})) |
| % elif reg_flat.get_n_bits(["q"]) and (r.ishomog or ((not r.ishomog) and r.get_fields_flat()[0].get_n_bits(["q"]))): |
| `ASSERT(${reg_name}_rd_A, ${rd_prperty}(${reg_msb}, ${reg_offset}, ${reg_q_path})) |
| % endif |
| % endif |
| % endfor |
| % endfor |
| </%def>\ |
| ${construct_classes(block)} |
| endmodule |