[reggen, util] Add support for data integrity passthrough
- When a module has no window or has windows with no integrity passthrough,
data integrity can be generated at a common location.
- When a module window has data integrity passthrough, the regfile
registers must separately generate data integrity so as to not
duplicate.
- When a module has a mix of windows with and without integrity, common
generation is not possible, and data integrity is selectively generated
for those windows that do not directly pass them in.
- The only module that is currently impacted is otbn (and soon rom_ctrl)
Otbn dmem / imem each contain their own integrity, and thus can directly
pass them through. The regfile for otbn thus no longer generates data
integrity at a common location, and instead generates it only for data
passed through tlul_adapter_reg. The data integrity for the windows are
fed through directly.
Signed-off-by: Timothy Chen <timothytim@google.com>
[top] Auto generate files
Signed-off-by: Timothy Chen <timothytim@google.com>
diff --git a/util/reggen/reg_block.py b/util/reggen/reg_block.py
index 13f811f..30a4f74 100644
--- a/util/reggen/reg_block.py
+++ b/util/reggen/reg_block.py
@@ -30,6 +30,9 @@
self.registers = [] # type: List[Register]
self.windows = [] # type: List[Window]
+ # Boolean indication whether ANY window in regblock has data integrity passthrough
+ self.has_data_intg_passthru = False
+
# A list of all registers, expanding multiregs, ordered by offset
self.flat_regs = [] # type: List[Register]
@@ -245,6 +248,8 @@
assert self.offset <= window.offset
self.offset = window.next_offset(self._addrsep)
+ self.has_data_intg_passthru |= window.data_intg_passthru
+
def validate(self) -> None:
'''Run this to check consistency after all registers have been added'''
diff --git a/util/reggen/reg_top.sv.tpl b/util/reggen/reg_top.sv.tpl
index d925c74..d1a9a9c 100644
--- a/util/reggen/reg_top.sv.tpl
+++ b/util/reggen/reg_top.sv.tpl
@@ -36,6 +36,10 @@
rb.windows[0].offset != 0 or
rb.windows[0].size_in_bytes != (1 << addr_width)))
+
+ common_data_intg_gen = 0 if rb.has_data_intg_passthru else 1
+ adapt_data_intg_gen = 1 if rb.has_data_intg_passthru else 0
+ assert common_data_intg_gen != adapt_data_intg_gen
%>
`include "prim_assert.sv"
@@ -115,7 +119,10 @@
// outgoing integrity generation
tlul_pkg::tl_d2h_t tl_o_pre;
- tlul_rsp_intg_gen u_rsp_intg_gen (
+ tlul_rsp_intg_gen #(
+ .EnableRspIntgGen(1),
+ .EnableDataIntgGen(${common_data_intg_gen})
+ ) u_rsp_intg_gen (
.tl_i(tl_o_pre),
.tl_o
);
@@ -144,7 +151,19 @@
% endif
% for i,t in enumerate(rb.windows):
assign tl_win_o[${i}] = tl_socket_h2d[${i}];
+ % if common_data_intg_gen == 0 and rb.windows[i].data_intg_passthru == False:
+ ## If there are multiple windows, and not every window has data integrity
+ ## passthrough, we must generate data integrity for it here.
+ tlul_rsp_intg_gen #(
+ .EnableRspIntgGen(0),
+ .EnableDataIntgGen(1)
+ ) u_win${i}_data_intg_gen (
+ .tl_i(tl_win_i[${i}]),
+ .tl_o(tl_socket_d2h[${i}])
+ );
+ % else:
assign tl_socket_d2h[${i}] = tl_win_i[${i}];
+ % endif
% endfor
// Create Socket_1n
@@ -204,7 +223,8 @@
tlul_adapter_reg #(
.RegAw(AW),
- .RegDw(DW)
+ .RegDw(DW),
+ .EnableDataIntgGen(${adapt_data_intg_gen})
) u_reg_if (
.clk_i,
.rst_ni,
diff --git a/util/reggen/window.py b/util/reggen/window.py
index 6ca61e6..d4355c8 100644
--- a/util/reggen/window.py
+++ b/util/reggen/window.py
@@ -19,6 +19,10 @@
# TODO potential for additional optional to give more type info?
# eg sram-hw-port: "none", "sync", "async"
OPTIONAL_FIELDS = {
+ 'data-intg-passthru': [
+ 's', "True if the window has data integrity pass through. "
+ "Defaults to false if not present."
+ ],
'byte-write': [
's', "True if byte writes are supported. "
"Defaults to false if not present."
@@ -47,6 +51,7 @@
desc: str,
unusual: bool,
byte_write: bool,
+ data_intg_passthru: bool,
validbits: int,
items: int,
size_in_bytes: int,
@@ -59,6 +64,7 @@
self.desc = desc
self.unusual = unusual
self.byte_write = byte_write
+ self.data_intg_passthru = data_intg_passthru
self.validbits = validbits
self.items = items
self.size_in_bytes = size_in_bytes
@@ -89,6 +95,8 @@
'unusual field for ' + wind_desc)
byte_write = check_bool(rd.get('byte-write', False),
'byte-write field for ' + wind_desc)
+ data_intg_passthru = check_bool(rd.get('data-intg-passthru', False),
+ 'data-intg-passthru field for ' + wind_desc)
validbits = check_int(rd.get('validbits', reg_width),
'validbits field for ' + wind_desc)
@@ -140,7 +148,7 @@
'to do this, set the "unusual" flag.'
.format(wind_desc, swaccess.key))
- return Window(name, desc, unusual, byte_write,
+ return Window(name, desc, unusual, byte_write, data_intg_passthru,
validbits, items, size_in_bytes, offset, swaccess)
def next_offset(self, addrsep: int) -> int:
diff --git a/util/topgen.py b/util/topgen.py
index 0b562b1..e14f447 100755
--- a/util/topgen.py
+++ b/util/topgen.py
@@ -790,7 +790,7 @@
# together with a map of interface addresses.
inst_to_block = {} # type: Dict[str, str]
if_addrs = {} # type: Dict[Tuple[str, Optional[str]], int],
- attrs = {} # type: Dict[str, str]
+ attrs = {} # type: Dict[str, str]
for module in top['module']:
inst_name = module['name']
@@ -798,7 +798,8 @@
block = name_to_block[block_name]
if "attr" in module:
if module["attr"] not in ['templated', 'reggen_top', 'reggen_only']:
- raise ValueError('Unsupported value for attr field of {}: {!r}'.format(what, attr))
+ raise ValueError('Unsupported value for attr field of {}: {!r}'.
+ format(block_name, module["attr"]))
attrs[inst_name] = module["attr"]
inst_to_block[inst_name] = block_name
@@ -811,6 +812,8 @@
for item in list(top.get("memory", [])):
byte_write = ('byte_write' in item and
item["byte_write"].lower() == "true")
+ data_intg_passthru = ('data_intg_passthru' in item and
+ item["data_intg_passthru"].lower() == "true")
size_in_bytes = int(item['size'], 0)
num_regs = size_in_bytes // addrsep
swaccess = access.SWAccess('top-level memory',
@@ -820,6 +823,7 @@
desc='(generated from top-level)',
unusual=False,
byte_write=byte_write,
+ data_intg_passthru=data_intg_passthru,
validbits=regwidth,
items=num_regs,
size_in_bytes=size_in_bytes,
@@ -1135,8 +1139,6 @@
# Generic Inter-module connection
im.elab_intermodule(completecfg)
- top_name = completecfg["name"]
-
# Generate top.gen.hjson right before rendering
genhjson_dir = out_path / "data/autogen"
genhjson_dir.mkdir(parents=True, exist_ok=True)