Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions docs/rdl_features/external.rst
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ hwif_in..rd_data

If the register does not contain any readable fields, this signal is omitted.

hwif_in..rd_err
Read response error state (Optional).

Requires ``--allow-external-err`` flag to be set.
If the register does not contain any readable fields, this signal is omitted.

Write Response
^^^^^^^^^^^^^^
hwif_in..wr_ack
Expand All @@ -101,6 +107,11 @@ hwif_in..wr_ack

If the register does not contain any writable fields, this signal is omitted.

hwif_in..wr_err
Write response error state (Optional).

Requires ``--allow-external-err`` flag to be set.
If the register does not contain any readable fields, this signal is omitted.


External Blocks
Expand Down Expand Up @@ -149,7 +160,19 @@ hwif_in..rd_ack
hwif_in..rd_data
Read response data.

hwif_in..rd_err
Read response error state (Optional).

Requires ``--allow-external-err`` flag to be set.
If the register does not contain any readable fields, this signal is omitted.

Write Response
^^^^^^^^^^^^^^
hwif_in..wr_ack
Single-cycle strobe indicating a write transfer has completed.

hwif_in..wr_err
Write response error state (Optional).

Requires ``--allow-external-err`` flag to be set.
If the register does not contain any readable fields, this signal is omitted.
10 changes: 10 additions & 0 deletions src/peakrdl_regblock/__peakrdl__.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,15 @@ def add_exporter_arguments(self, arg_group: 'argparse._ActionsContainer') -> Non
performed to a read-only or write-only register."""
)

arg_group.add_argument(
"--allow-external-err",
action="store_true",
default=False,
help="""Allow external elements to report error states after
read/write operations.
"""
)

def do_export(self, top_node: 'AddrmapNode', options: 'argparse.Namespace') -> None:
cpuifs = self.get_cpuifs()

Expand Down Expand Up @@ -227,4 +236,5 @@ def do_export(self, top_node: 'AddrmapNode', options: 'argparse.Namespace') -> N
err_if_bad_addr=options.err_if_bad_addr or self.cfg['err_if_bad_addr'],
err_if_bad_rw=options.err_if_bad_rw or self.cfg['err_if_bad_rw'],
default_reset_async=default_reset_async,
allow_external_err=options.allow_external_err
)
14 changes: 13 additions & 1 deletion src/peakrdl_regblock/exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from .write_buffering import WriteBuffering
from .read_buffering import ReadBuffering
from .external_acks import ExternalWriteAckGenerator, ExternalReadAckGenerator
from .external_errs import ExternalWriteErrGenerator, ExternalReadErrGenerator
from .parity import ParityErrorReduceGenerator
from .sv_int import SVInt

Expand Down Expand Up @@ -127,6 +128,9 @@ def export(self, node: Union[RootNode, AddrmapNode], output_dir:str, **kwargs: A
If overriden to True: If an illegal access is performed to a read-only or write-only
register, the CPUIF response signal shows an error. For example: APB.PSLVERR = 1'b1,
AXI4LITE.*RESP = 2'b10.
allow_external_err: bool
If overriden to True: Allows for the "external" elements to return error state after
an access request.
"""
# If it is the root node, skip to top addrmap
if isinstance(node, RootNode):
Expand All @@ -138,6 +142,7 @@ def export(self, node: Union[RootNode, AddrmapNode], output_dir:str, **kwargs: A

cpuif_cls = kwargs.pop("cpuif_cls", None) or APB4_Cpuif # type: Type[CpuifBase]
generate_hwif_report = kwargs.pop("generate_hwif_report", False) # type: bool
allow_external_err = kwargs.pop("allow_external_err", False) # type: bool

# Check for stray kwargs
if kwargs:
Expand All @@ -151,15 +156,17 @@ def export(self, node: Union[RootNode, AddrmapNode], output_dir:str, **kwargs: A

# Construct exporter components
self.cpuif = cpuif_cls(self)
self.hwif = Hwif(self, hwif_report_file=hwif_report_file)
self.hwif = Hwif(self, hwif_report_file=hwif_report_file, allow_external_err=allow_external_err)
self.readback = Readback(self)
self.address_decode = AddressDecode(self)
self.field_logic = FieldLogic(self)
self.write_buffering = WriteBuffering(self)
self.read_buffering = ReadBuffering(self)
self.dereferencer = Dereferencer(self)
ext_write_acks = ExternalWriteAckGenerator(self)
ext_write_errs = ExternalWriteErrGenerator(self)
ext_read_acks = ExternalReadAckGenerator(self)
ext_read_errs = ExternalReadErrGenerator(self)
parity = ParityErrorReduceGenerator(self)

# Validate that there are no unsupported constructs
Expand All @@ -180,7 +187,9 @@ def export(self, node: Union[RootNode, AddrmapNode], output_dir:str, **kwargs: A
"field_logic": self.field_logic,
"readback_implementation": self.readback.get_implementation(),
"ext_write_acks": ext_write_acks,
"ext_write_errs": ext_write_errs,
"ext_read_acks": ext_read_acks,
"ext_read_errs": ext_read_errs,
"parity": parity,
"get_always_ff_event": self.dereferencer.get_always_ff_event,
"ds": self.ds,
Expand Down Expand Up @@ -279,6 +288,9 @@ def __init__(self, top_node: AddrmapNode, kwargs: Any) -> None:
self.err_if_bad_addr = kwargs.pop("err_if_bad_addr", False) # type: bool
self.err_if_bad_rw = kwargs.pop("err_if_bad_rw", False) # type: bool

# Generating an "external" error
self.allow_external_err = kwargs.get("allow_external_err", False) # type: bool

#------------------------
# Info about the design
#------------------------
Expand Down
54 changes: 54 additions & 0 deletions src/peakrdl_regblock/external_errs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from typing import TYPE_CHECKING

from systemrdl.walker import WalkerAction
from systemrdl.node import RegNode

from .forloop_generator import RDLForLoopGenerator

if TYPE_CHECKING:
from .exporter import RegblockExporter
from systemrdl.node import AddressableNode


class ExternalWriteErrGenerator(RDLForLoopGenerator):
def __init__(self, exp: 'RegblockExporter') -> None:
super().__init__()
self.exp = exp

def get_implementation(self) -> str:
content = self.get_content(self.exp.ds.top_node)
if content is None:
return ""
return content

def enter_AddressableComponent(self, node: 'AddressableNode') -> WalkerAction:
super().enter_AddressableComponent(node)

if node.external:
if not isinstance(node, RegNode) or node.has_sw_writable:
self.add_content(f"wr_err |= {self.exp.hwif.get_external_wr_err(node)};")
return WalkerAction.SkipDescendants

return WalkerAction.Continue


class ExternalReadErrGenerator(RDLForLoopGenerator):
def __init__(self, exp: 'RegblockExporter') -> None:
super().__init__()
self.exp = exp

def get_implementation(self) -> str:
content = self.get_content(self.exp.ds.top_node)
if content is None:
return ""
return content

def enter_AddressableComponent(self, node: 'AddressableNode') -> WalkerAction:
super().enter_AddressableComponent(node)

if node.external:
if not isinstance(node, RegNode) or node.has_sw_readable:
self.add_content(f"rd_err |= {self.exp.hwif.get_external_rd_err(node)};")
return WalkerAction.SkipDescendants

return WalkerAction.Continue
4 changes: 2 additions & 2 deletions src/peakrdl_regblock/field_logic/sw_onread.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, List
from typing import Optional, TYPE_CHECKING, List

from systemrdl.rdltypes import OnReadType

Expand All @@ -8,7 +8,7 @@
from systemrdl.node import FieldNode

class _OnRead(NextStateConditional):
onreadtype = None # type: OnReadType
onreadtype = None # type: Optional[OnReadType]
def is_match(self, field: 'FieldNode') -> bool:
return field.get_property('onread') == self.onreadtype

Expand Down
18 changes: 17 additions & 1 deletion src/peakrdl_regblock/hwif/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,16 @@ class Hwif:

def __init__(
self, exp: 'RegblockExporter',
hwif_report_file: Optional[TextIO]
hwif_report_file: Optional[TextIO],
allow_external_err: bool = False
):
self.exp = exp

self.has_input_struct = False
self.has_output_struct = False

self.hwif_report_file = hwif_report_file
self.allow_external_err = allow_external_err

if not self.ds.reuse_hwif_typedefs:
self._gen_in_cls = InputStructGenerator_Hier
Expand Down Expand Up @@ -195,6 +197,20 @@ def get_external_wr_ack(self, node: AddressableNode) -> str:
path = get_indexed_path(self.top_node, node)
return "hwif_in." + path + ".wr_ack"

def get_external_rd_err(self, node: AddressableNode) -> str:
"""
Returns the identifier string for an external component's rd_ack signal
"""
path = get_indexed_path(self.top_node, node)
return "hwif_in." + path + ".rd_err"

def get_external_wr_err(self, node: AddressableNode) -> str:
"""
Returns the identifier string for an external component's wr_ack signal
"""
path = get_indexed_path(self.top_node, node)
return "hwif_in." + path + ".wr_err"

def get_implied_prop_input_identifier(self, field: FieldNode, prop: str) -> str:
assert prop in {
'hwclr', 'hwset', 'swwe', 'swwel', 'we', 'wel',
Expand Down
7 changes: 7 additions & 0 deletions src/peakrdl_regblock/hwif/generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ def _add_external_block_members(self, node: 'AddressableNode') -> None:
self.add_member("rd_ack")
self.add_member("rd_data", self.hwif.ds.cpuif_data_width)
self.add_member("wr_ack")
if self.hwif.allow_external_err:
self.add_member("rd_err")
self.add_member("wr_err")

def enter_Addrmap(self, node: 'AddrmapNode') -> Optional[WalkerAction]:
super().enter_Addrmap(node)
Expand Down Expand Up @@ -99,9 +102,13 @@ def enter_Reg(self, node: 'RegNode') -> Optional[WalkerAction]:
n_subwords = node.get_property("regwidth") // node.get_property("accesswidth")
if node.has_sw_readable:
self.add_member("rd_ack")
if self.hwif.allow_external_err:
self.add_member("rd_err")
self.add_external_reg_rd_data(node, width, n_subwords)
if node.has_sw_writable:
self.add_member("wr_ack")
if self.hwif.allow_external_err:
self.add_member("wr_err")
return WalkerAction.SkipDescendants

return WalkerAction.Continue
Expand Down
56 changes: 53 additions & 3 deletions src/peakrdl_regblock/module_tmpl.sv
Original file line number Diff line number Diff line change
Expand Up @@ -224,12 +224,28 @@ module {{ds.module_name}}
{%- else %}
assign cpuif_wr_ack = decoded_req & decoded_req_is_wr;
{%- endif %}
// Writes are always granted with no error response
{%- if ds.allow_external_err and ds.has_external_addressable %}

logic external_wr_err;

always_comb begin
automatic logic wr_err;
wr_err = '0;
{{ext_write_errs.get_implementation()|indent(8)}}
external_wr_err = wr_err;
end
{%- if ds.err_if_bad_addr or ds.err_if_bad_rw %}
assign cpuif_wr_err = external_wr_err | decoded_err;
{%- else %}
assign cpuif_wr_err = external_wr_err;
{%- endif %}
{%- else %}
{%- if ds.err_if_bad_addr or ds.err_if_bad_rw %}
assign cpuif_wr_err = decoded_err;
{%- else %}
assign cpuif_wr_err = '0;
{%- endif %}
{%- endif %}

//--------------------------------------------------------------------------
// Readback
Expand Down Expand Up @@ -257,6 +273,32 @@ module {{ds.module_name}}

assign readback_external_rd_ack = readback_external_rd_ack_c;
{%- endif %}
{%- endif %}
{%- if ds.allow_external_err and ds.has_external_addressable %}

logic readback_external_rd_err_c;
always_comb begin
automatic logic rd_err;
rd_err = '0;
{{ext_read_errs.get_implementation()|indent(8)}}
readback_external_rd_err_c = rd_err;
end

logic readback_external_rd_err;
{%- if ds.retime_read_fanin %}
always_ff {{get_always_ff_event(cpuif.reset)}} begin
if({{get_resetsignal(cpuif.reset)}}) begin
readback_external_rd_err <= '0;
end else begin
readback_external_rd_err <= readback_external_rd_err_c;
end
end

{%- else %}

assign readback_external_rd_err = readback_external_rd_err_c;
{%- endif %}

{%- endif %}

logic [{{cpuif.addr_width-1}}:0] rd_mux_addr;
Expand All @@ -279,7 +321,7 @@ module {{ds.module_name}}
logic readback_done;
logic [{{cpuif.data_width-1}}:0] readback_data;
{{readback_implementation|indent}}
{% if ds.retime_read_response %}
{%- if ds.retime_read_response %}
always_ff {{get_always_ff_event(cpuif.reset)}} begin
if({{get_resetsignal(cpuif.reset)}}) begin
cpuif_rd_ack <= '0;
Expand All @@ -296,18 +338,26 @@ module {{ds.module_name}}
cpuif_rd_ack <= readback_done;
{%- endif %}
cpuif_rd_data <= readback_data;
{%- if ds.allow_external_err and ds.has_external_addressable %}
cpuif_rd_err <= readback_err | readback_external_rd_err;
{%- else %}
cpuif_rd_err <= readback_err;
{%- endif %}
end
end
{% else %}
{%- else %}
{%- if ds.has_external_addressable %}
assign external_rd_ack = readback_external_rd_ack;
assign cpuif_rd_ack = readback_done | readback_external_rd_ack;
{%- else %}
assign cpuif_rd_ack = readback_done;
{%- endif %}
assign cpuif_rd_data = readback_data;
{%- if ds.allow_external_err and ds.has_external_addressable %}
assign cpuif_rd_err = readback_err | readback_external_rd_err;
{%- else %}
assign cpuif_rd_err = readback_err;
{%- endif %}
{%- endif %}
endmodule
{# (eof newline anchor) #}
2 changes: 2 additions & 0 deletions tests/lib/base_testcase.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class BaseTestCase(unittest.TestCase):
default_reset_async = False
err_if_bad_addr = False
err_if_bad_rw = False
allow_external_err = False

#: this gets auto-loaded via the _load_request autouse fixture
request = None # type: pytest.FixtureRequest
Expand Down Expand Up @@ -122,6 +123,7 @@ def export_regblock(self):
default_reset_async=self.default_reset_async,
err_if_bad_addr=self.err_if_bad_addr,
err_if_bad_rw=self.err_if_bad_rw,
allow_external_err=self.allow_external_err
)

def delete_run_dir(self) -> None:
Expand Down
Loading