fix: handle error response for overlapped registers with read-only and write-only attributes (#178)

This commit is contained in:
Sebastien Baillou
2025-11-16 00:43:45 +01:00
committed by Alex Mykyta
parent e1d7b3aa38
commit efbddccc54
4 changed files with 115 additions and 124 deletions

View File

@@ -141,23 +141,26 @@ class DecodeLogicGenerator(RDLForLoopGenerator):
readable = node.is_sw_readable
writable = node.is_sw_writable
if readable and writable:
rhs_invalid_rw = "'0"
pass
elif readable and not writable:
rhs = f"{addr_decoding_str} & !cpuif_req_is_wr"
rhs_invalid_rw = f"{addr_decoding_str} & cpuif_req_is_wr"
elif not readable and writable:
rhs = f"{addr_decoding_str} & cpuif_req_is_wr"
rhs_invalid_rw = f"{addr_decoding_str} & !cpuif_req_is_wr"
else:
raise RuntimeError
# Add decoding flags
self.add_content(f"{self.addr_decode.get_external_block_access_strobe(node)} = {rhs};")
self.add_content(f"is_external |= {rhs};")
if self.addr_decode.exp.ds.err_if_bad_addr:
# Also assign is_valid_adddr when err_if_bad_rw is set so that it can be used to catch
# invalid RW accesses on existing registers only.
if self.addr_decode.exp.ds.err_if_bad_addr or self.addr_decode.exp.ds.err_if_bad_rw:
self.add_content(f"is_valid_addr |= {rhs_valid_addr};")
if isinstance(node, MemNode):
if self.addr_decode.exp.ds.err_if_bad_rw:
self.add_content(f"is_invalid_rw |= {rhs_invalid_rw};")
self.add_content(f"is_valid_rw |= {rhs};")
else:
# For external register blocks, all accesses are valid RW
self.add_content(f"is_valid_rw |= {rhs_valid_addr};")
def enter_AddressableComponent(self, node: 'AddressableNode') -> Optional[WalkerAction]:
@@ -206,13 +209,10 @@ class DecodeLogicGenerator(RDLForLoopGenerator):
writable = node.has_sw_writable
if readable and writable:
rhs = addr_decoding_str
rhs_invalid_rw = "'0"
elif readable and not writable:
rhs = f"{addr_decoding_str} & !cpuif_req_is_wr"
rhs_invalid_rw = f"{addr_decoding_str} & cpuif_req_is_wr"
elif not readable and writable:
rhs = f"{addr_decoding_str} & cpuif_req_is_wr"
rhs_invalid_rw = f"{addr_decoding_str} & !cpuif_req_is_wr"
else:
raise RuntimeError
# Add decoding flags
@@ -222,10 +222,12 @@ class DecodeLogicGenerator(RDLForLoopGenerator):
self.add_content(f"{self.addr_decode.get_access_strobe(node)}[{subword_index}] = {rhs};")
if node.external:
self.add_content(f"is_external |= {rhs};")
if self.addr_decode.exp.ds.err_if_bad_addr:
# Also assign is_valid_adddr when err_if_bad_rw is set so that it can be used to catch
# invalid RW accesses on existing registers only.
if self.addr_decode.exp.ds.err_if_bad_addr or self.addr_decode.exp.ds.err_if_bad_rw:
self.add_content(f"is_valid_addr |= {rhs_valid_addr};")
if self.addr_decode.exp.ds.err_if_bad_rw:
self.add_content(f"is_invalid_rw |= {rhs_invalid_rw};")
self.add_content(f"is_valid_rw |= {rhs};")
def enter_Reg(self, node: RegNode) -> None:
regwidth = node.get_property('regwidth')

View File

@@ -121,19 +121,31 @@ module {{ds.module_name}}
always_comb begin
automatic logic is_valid_addr;
automatic logic is_invalid_rw;
automatic logic is_valid_rw;
{%- if ds.has_external_addressable %}
automatic logic is_external;
is_external = '0;
{%- endif %}
{%- if ds.err_if_bad_addr %}
{%- if ds.err_if_bad_addr or ds.err_if_bad_rw %}
is_valid_addr = '0;
{%- else %}
is_valid_addr = '1; // No error checking on valid address access
is_valid_addr = '1; // No valid address check
{%- endif %}
{%- if ds.err_if_bad_rw %}
is_valid_rw = '0;
{%- else %}
is_valid_rw = '1; // No valid RW check
{%- endif %}
is_invalid_rw = '0;
{{address_decode.get_implementation()|indent(8)}}
decoded_err = (~is_valid_addr | is_invalid_rw) & decoded_req;
{%- if ds.err_if_bad_addr and ds.err_if_bad_rw %}
decoded_err = (~is_valid_addr | (is_valid_addr & ~is_valid_rw)) & decoded_req;
{%- elif ds.err_if_bad_addr %}
decoded_err = ~is_valid_addr & decoded_req;
{%- elif ds.err_if_bad_rw %}
decoded_err = (is_valid_addr & ~is_valid_rw) & decoded_req;
{%- else %}
decoded_err = '0;
{%- endif %}
{%- if ds.has_external_addressable %}
decoded_strb_is_external = is_external;
external_req = is_external;