Skip to content

Commit a0ea68e

Browse files
Razer6andreaskurth
authored andcommitted
[racl] Implement RACL checks in reggen
Signed-off-by: Robert Schilling <[email protected]>
1 parent 582b99b commit a0ea68e

File tree

3 files changed

+107
-14
lines changed

3 files changed

+107
-14
lines changed

util/reggen/bus_interfaces.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from typing import Dict, List, Optional, Tuple
88

99
from reggen.inter_signal import InterSignal
10-
from reggen.lib import check_list, check_keys, check_str, check_optional_str
10+
from reggen.lib import check_list, check_keys, check_str, check_optional_bool, check_optional_str
1111

1212

1313
class BusInterfaces:
@@ -18,7 +18,8 @@ def __init__(self,
1818
has_unnamed_device: bool,
1919
named_devices: List[str],
2020
device_async: Dict[Optional[str], str],
21-
device_hier_paths: Dict[Optional[str], str]):
21+
device_hier_paths: Dict[Optional[str], str],
22+
racl_support: Dict[Optional[str], bool]):
2223
assert has_unnamed_device or named_devices
2324
assert len(named_hosts) == len(set(named_hosts))
2425
assert len(named_devices) == len(set(named_devices))
@@ -30,6 +31,7 @@ def __init__(self,
3031
self.named_devices = named_devices
3132
self.device_async = device_async
3233
self.device_hier_paths = device_hier_paths
34+
self.racl_support = racl_support
3335

3436
@staticmethod
3537
def from_raw(raw: object, where: str) -> 'BusInterfaces':
@@ -41,12 +43,13 @@ def from_raw(raw: object, where: str) -> 'BusInterfaces':
4143
named_devices = []
4244
device_async = {}
4345
device_hier_paths = {}
46+
racl_support_map = {}
4447

4548
for idx, raw_entry in enumerate(check_list(raw, where)):
4649
entry_what = 'entry {} of {}'.format(idx + 1, where)
4750
ed = check_keys(raw_entry, entry_what,
4851
['protocol', 'direction'],
49-
['name', 'async', 'hier_path'])
52+
['name', 'async', 'hier_path', 'racl_support'])
5053

5154
protocol = check_str(ed['protocol'],
5255
'protocol field of ' + entry_what)
@@ -69,6 +72,9 @@ def from_raw(raw: object, where: str) -> 'BusInterfaces':
6972
hier_path = check_optional_str(ed.get('hier_path'),
7073
'hier_path field of ' + entry_what)
7174

75+
racl_support = check_optional_bool(ed.get('racl_support'),
76+
'racl_support field of ' + entry_what)
77+
7278
if direction == 'host':
7379
if name is None:
7480
if has_unnamed_host:
@@ -111,12 +117,14 @@ def from_raw(raw: object, where: str) -> 'BusInterfaces':
111117
else:
112118
device_hier_paths[name] = 'u_reg'
113119

120+
racl_support_map[name] = bool(racl_support)
121+
114122
if not (has_unnamed_device or named_devices):
115123
raise ValueError('No device interface at ' + where)
116124

117125
return BusInterfaces(has_unnamed_host, named_hosts, host_async,
118126
has_unnamed_device, named_devices,
119-
device_async, device_hier_paths)
127+
device_async, device_hier_paths, racl_support_map)
120128

121129
def has_host(self) -> bool:
122130
return bool(self.has_unnamed_host or self.named_hosts)

util/reggen/lib.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,11 @@ def check_optional_str(obj: object, what: str) -> Optional[str]:
239239
return None if obj is None else check_str(obj, what)
240240

241241

242+
def check_optional_bool(obj: object, what: str) -> Optional[bool]:
243+
'''Check that obj is a bool or None'''
244+
return None if obj is None else check_bool(obj, what)
245+
246+
242247
def check_optional_name(obj: object, what: str) -> Optional[str]:
243248
'''Check that obj is a valid name or None'''
244249
return None if obj is None else check_name(obj, what)

util/reggen/reg_top.sv.tpl

Lines changed: 90 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
reg2hw_t = gen_rtl.get_iface_tx_type(block, if_name, False)
3434
hw2reg_t = gen_rtl.get_iface_tx_type(block, if_name, True)
3535

36+
racl_support = block.bus_interfaces.racl_support[if_name]
37+
3638
win_array_decl = f' [{num_wins}]' if num_wins > 1 else ''
3739

3840
# Calculate whether we're going to need an AW parameter. We use it if there
@@ -115,7 +117,13 @@
115117
%>
116118
`include "prim_assert.sv"
117119

118-
module ${mod_name} (
120+
module ${mod_name}${' (' if not racl_support else ''}
121+
% if racl_support:
122+
# (
123+
parameter bit EnableRacl = 1'b0,
124+
parameter bit RaclErrorRsp = 1'b1
125+
) (
126+
% endif
119127
input clk_i,
120128
input rst_ni,
121129
% if rb.has_internal_shadowed_reg():
@@ -147,6 +155,14 @@ module ${mod_name} (
147155
output logic shadowed_update_err_o,
148156

149157
%endif
158+
% if racl_support:
159+
// RACL interface
160+
input top_racl_pkg::racl_policy_vec_t racl_policies_i,
161+
input integer racl_policy_sel_vec_i[${len(rb.flat_regs)}],
162+
output logic racl_error_o,
163+
output top_racl_pkg::racl_error_log_t racl_error_log_o,
164+
165+
% endif
150166
// Integrity check errors
151167
output logic intg_err_o
152168
);
@@ -387,7 +403,12 @@ module ${mod_name} (
387403
.be_o (reg_be),
388404
.busy_i (reg_busy),
389405
.rdata_i (reg_rdata),
406+
% if racl_support:
407+
// Translate RACL error to TLUL error if enabled
408+
.error_i (reg_error | (RaclErrorRsp & racl_error_o))
409+
% else:
390410
.error_i (reg_error)
411+
% endif
391412
);
392413

393414
// cdc oversampling signals
@@ -641,24 +662,81 @@ ${finst_gen(sr, field, finst_name, fsig_name, fidx)}
641662
% endfor
642663

643664
logic [${len(regs_flat)-1}:0] addr_hit;
665+
% if racl_support:
666+
top_racl_pkg::racl_role_vec_t racl_role_vec;
667+
top_racl_pkg::racl_role_t racl_role;
668+
669+
logic [${len(regs_flat)-1}:0] racl_addr_hit_read;
670+
logic [${len(regs_flat)-1}:0] racl_addr_hit_write;
671+
672+
if (EnableRacl) begin : gen_racl_role_logic
673+
// Retrieve RACL role from user bits and one-hot encode that for the comparison bitmap
674+
assign racl_role = top_racl_pkg::tlul_extract_racl_role_bits(tl_i.a_user.rsvd);
675+
676+
prim_onehot_enc #(
677+
.OneHotWidth( $bits(prim_onehot_enc) )
678+
) u_racl_role_encode (
679+
.in_i ( racl_role ),
680+
.en_i ( 1'b1 ),
681+
.out_o( racl_role_vec )
682+
);
683+
end else begin : gen_no_racl_role_logic
684+
assign racl_role = '0;
685+
assign racl_role_vec = '0;
686+
end
687+
688+
% endif
644689
always_comb begin
645690
addr_hit = '0;
691+
% if racl_support:
692+
racl_addr_hit_read = '0;
693+
racl_addr_hit_write = '0;
694+
% endif
646695
% for i,r in enumerate(regs_flat):
647-
addr_hit[${"{}".format(i).rjust(max_regs_char)}] = (reg_addr == ${ublock}_${r.name.upper()}_OFFSET);
696+
<% slice = '{}'.format(i).rjust(max_regs_char) %>\
697+
addr_hit[${slice}] = (reg_addr == ${ublock}_${r.name.upper()}_OFFSET);
648698
% endfor
699+
% if racl_support:
700+
701+
if (EnableRacl) begin : gen_racl_hit
702+
% for i,r in enumerate(regs_flat):
703+
<% slice = '{}'.format(i).rjust(max_regs_char) %>\
704+
racl_addr_hit_read [${slice}] = addr_hit[${slice}] & (|(racl_policies_i[racl_policy_sel_vec_i[${slice}]].read_perm & racl_role_vec));
705+
racl_addr_hit_write[${slice}] = addr_hit[${slice}] & (|(racl_policies_i[racl_policy_sel_vec_i[${slice}]].write_perm & racl_role_vec));
706+
% endfor
707+
end else begin : gen_no_racl
708+
racl_addr_hit_read = addr_hit;
709+
racl_addr_hit_write = addr_hit;
710+
end
711+
% endif
649712
end
650713

651714
assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
715+
% if racl_support:
716+
// Address hit but failed the RACL check
717+
assign racl_error_o = (|addr_hit) & ~(|(addr_hit & (racl_addr_hit_read | racl_addr_hit_write)));
718+
assign racl_error_log_o.racl_role = racl_role;
719+
720+
if (EnableRacl) begin : gen_racl_log
721+
assign racl_error_log_o.ctn_uid = top_racl_pkg::tlul_extract_ctn_uid_bits(tl_i.a_user.rsvd);
722+
assign racl_error_log_o.read_not_write = tl_i.a_opcode == tlul_pkg::Get;
723+
end else begin : gen_no_racl_log
724+
assign racl_error_log_o.ctn_uid = '0;
725+
assign racl_error_log_o.read_not_write = 1'b0;
726+
end
727+
% endif
652728

653729
% if regs_flat:
654730
<%
655731
# We want to signal wr_err if reg_be (the byte enable signal) is true for
656732
# any bytes that aren't supported by a register. That's true if a
657733
# addr_hit[i] and a bit is set in reg_be but not in *_PERMIT[i].
658734

659-
wr_err_terms = ['(addr_hit[{idx}] & (|({mod}_PERMIT[{idx}] & ~reg_be)))'
735+
wr_addr_hit = 'racl_addr_hit_write' if racl_support else 'addr_hit'
736+
wr_err_terms = ['({wr_addr_hit}[{idx}] & (|({mod}_PERMIT[{idx}] & ~reg_be)))'
660737
.format(idx=str(i).rjust(max_regs_char),
661-
mod=u_mod_base)
738+
mod=u_mod_base,
739+
wr_addr_hit=wr_addr_hit)
662740
for i in range(len(regs_flat))]
663741
wr_err_expr = (' |\n' + (' ' * 15)).join(wr_err_terms)
664742
%>\
@@ -715,18 +793,19 @@ ${field_wd_gen(f, r.name.lower() + "_" + f.name.lower(), r.hwext, r.shadowed, r.
715793
always_comb begin
716794
reg_rdata_next = '0;
717795
unique case (1'b1)
796+
<% read_addr_hit = 'racl_addr_hit_read' if racl_support else 'addr_hit' %>\
718797
% for i, r in enumerate(regs_flat):
719798
% if r.async_clk:
720-
addr_hit[${i}]: begin
799+
${read_addr_hit}[${i}]: begin
721800
reg_rdata_next = DW'(${r.name.lower()}_qs);
722801
end
723802
% elif len(r.fields) == 1:
724-
addr_hit[${i}]: begin
803+
${read_addr_hit}[${i}]: begin
725804
${rdata_gen(r.fields[0], r.name.lower())}\
726805
end
727806

728807
% else:
729-
addr_hit[${i}]: begin
808+
${read_addr_hit}[${i}]: begin
730809
% for f in r.fields:
731810
${rdata_gen(f, r.name.lower() + "_" + f.name.lower())}\
732811
% endfor
@@ -942,7 +1021,7 @@ ${bits.msb}\
9421021
mubi_expr = "1'b1"
9431022
else:
9441023
mubi_expr = "1'b0"
945-
1024+
9461025
# when async, the outputs are aggregated first by the cdc module
9471026
async_suffix = '_int' if reg.async_clk else ''
9481027
qs_expr = f'{clk_base_name}{finst_name}_qs{async_suffix}' if field.swaccess.allows_read() else ''
@@ -1068,11 +1147,12 @@ ${bits.msb}\
10681147
% endif
10691148
</%def>\
10701149
<%def name="reg_enable_gen(reg, idx)">\
1150+
<% wr_addr_hit = 'racl_addr_hit_write' if racl_support else 'addr_hit'%>\
10711151
% if reg.needs_re():
1072-
assign ${reg.name.lower()}_re = addr_hit[${idx}] & reg_re & !reg_error;
1152+
assign ${reg.name.lower()}_re = ${wr_addr_hit}[${idx}] & reg_re & !reg_error;
10731153
% endif
10741154
% if reg.needs_we():
1075-
assign ${reg.name.lower()}_we = addr_hit[${idx}] & reg_we & !reg_error;
1155+
assign ${reg.name.lower()}_we = ${wr_addr_hit}[${idx}] & reg_we & !reg_error;
10761156
% endif
10771157
</%def>\
10781158
<%def name="field_wd_gen(field, sig_name, hwext, shadowed, async_clk, reg_name, idx)">\

0 commit comments

Comments
 (0)