From b056a443f194f9c55bbad86c7c7247504e7568fd Mon Sep 17 00:00:00 2001 From: Alex Mykyta Date: Wed, 14 Jun 2023 21:58:41 -0700 Subject: [PATCH] Use sized integer literals in comparisons. #49 --- src/peakrdl_regblock/addr_decode.py | 9 ++++++--- .../cpuif/axi4lite/axi4lite_tmpl.sv | 2 +- src/peakrdl_regblock/dereferencer.py | 6 ++++-- src/peakrdl_regblock/exporter.py | 13 ++++++------ src/peakrdl_regblock/field_logic/__init__.py | 20 +++++++++---------- .../field_logic/generators.py | 2 +- .../field_logic/templates/counter_macros.sv | 2 +- src/peakrdl_regblock/scan_design.py | 11 +++++----- src/peakrdl_regblock/utils.py | 13 +++++++----- 9 files changed, 43 insertions(+), 35 deletions(-) diff --git a/src/peakrdl_regblock/addr_decode.py b/src/peakrdl_regblock/addr_decode.py index 3f01531..64082de 100644 --- a/src/peakrdl_regblock/addr_decode.py +++ b/src/peakrdl_regblock/addr_decode.py @@ -157,7 +157,7 @@ class DecodeLogicGenerator(RDLForLoopGenerator): # Is an external block addr_str = self._get_address_str(node) strb = self.addr_decode.get_external_block_access_strobe(node) - rhs = f"cpuif_req_masked & (cpuif_addr >= {addr_str}) & (cpuif_addr <= {addr_str} + {get_sv_int(node.size - 1)})" + rhs = f"cpuif_req_masked & (cpuif_addr >= {addr_str}) & (cpuif_addr <= {addr_str} + {get_sv_int(node.size - 1, self.addr_decode.exp.ds.addr_width)})" self.add_content(f"{strb} = {rhs};") self.add_content(f"is_external |= {rhs};") return WalkerAction.SkipDescendants @@ -166,9 +166,12 @@ class DecodeLogicGenerator(RDLForLoopGenerator): def _get_address_str(self, node: 'AddressableNode', subword_offset: int=0) -> str: - a = get_sv_int(node.raw_absolute_address - self.addr_decode.top_node.raw_absolute_address + subword_offset) + a = get_sv_int( + node.raw_absolute_address - self.addr_decode.top_node.raw_absolute_address + subword_offset, + self.addr_decode.exp.ds.addr_width + ) for i, stride in enumerate(self._array_stride_stack): - a += f" + i{i}*{get_sv_int(stride)}" + a += f" + i{i}*{get_sv_int(stride, self.addr_decode.exp.ds.addr_width)}" return a diff --git a/src/peakrdl_regblock/cpuif/axi4lite/axi4lite_tmpl.sv b/src/peakrdl_regblock/cpuif/axi4lite/axi4lite_tmpl.sv index 2da192e..5e4734e 100644 --- a/src/peakrdl_regblock/cpuif/axi4lite/axi4lite_tmpl.sv +++ b/src/peakrdl_regblock/cpuif/axi4lite/axi4lite_tmpl.sv @@ -78,7 +78,7 @@ always_comb begin axil_ar_accept = '0; axil_aw_accept = '0; - if(axil_n_in_flight < 'd{{cpuif.max_outstanding}}) begin + if(axil_n_in_flight < {{clog2(cpuif.max_outstanding+1)}}'d{{cpuif.max_outstanding}}) begin // Can safely issue more transactions without overwhelming response buffer if(axil_arvalid && !axil_prev_was_rd) begin cpuif_req = '1; diff --git a/src/peakrdl_regblock/dereferencer.py b/src/peakrdl_regblock/dereferencer.py index 92732ff..47dc7c8 100644 --- a/src/peakrdl_regblock/dereferencer.py +++ b/src/peakrdl_regblock/dereferencer.py @@ -38,7 +38,7 @@ class Dereferencer: def top_node(self) -> AddrmapNode: return self.exp.ds.top_node - def get_value(self, obj: Union[int, FieldNode, SignalNode, PropertyReference]) -> str: + def get_value(self, obj: Union[int, FieldNode, SignalNode, PropertyReference], width: Optional[int] = None) -> str: """ Returns the Verilog string that represents the readable value associated with the object. @@ -47,10 +47,12 @@ class Dereferencer: If obj references a structural systemrdl object, then the corresponding Verilog expression is returned that represents its value. + + The optional width argument can be provided to hint at the expression's desired bitwidth. """ if isinstance(obj, int): # Is a simple scalar value - return get_sv_int(obj) + return get_sv_int(obj, width) if isinstance(obj, FieldNode): if obj.implements_storage: diff --git a/src/peakrdl_regblock/exporter.py b/src/peakrdl_regblock/exporter.py index 67977d2..9124a26 100644 --- a/src/peakrdl_regblock/exporter.py +++ b/src/peakrdl_regblock/exporter.py @@ -10,7 +10,7 @@ from .field_logic import FieldLogic from .dereferencer import Dereferencer from .readback import Readback from .identifier_filter import kw_filter as kwf - +from .utils import clog2 from .scan_design import DesignScanner from .validate_design import DesignValidator from .cpuif import CpuifBase @@ -134,9 +134,6 @@ class RegblockExporter: if kwargs: raise TypeError(f"got an unexpected keyword argument '{list(kwargs.keys())[0]}'") - # Scan the design for pre-export information - DesignScanner(self).do_scan() - if generate_hwif_report: path = os.path.join(output_dir, f"{self.ds.module_name}_hwif.rpt") hwif_report_file = open(path, "w", encoding='utf-8') # pylint: disable=consider-using-with @@ -251,9 +248,13 @@ class DesignState: # Track any referenced enums self.user_enums = [] # type: List[Type[UserEnum]] - #------------------------ + # Scan the design to fill in above variables + DesignScanner(self).do_scan() + + #------------------------ + # Min address width encloses the total size AND at least 1 useful address bit + self.addr_width = max(clog2(self.top_node.size), clog2(self.cpuif_data_width//8) + 1) - self.addr_width = (self.top_node.size - 1).bit_length() if user_addr_width is not None: if user_addr_width < self.addr_width: msg.fatal(f"User-specified address width shall be greater than or equal to {self.addr_width}.") diff --git a/src/peakrdl_regblock/field_logic/__init__.py b/src/peakrdl_regblock/field_logic/__init__.py index 06f876b..c1fcb12 100644 --- a/src/peakrdl_regblock/field_logic/__init__.py +++ b/src/peakrdl_regblock/field_logic/__init__.py @@ -110,7 +110,7 @@ class FieldLogic: """ incrvalue = field.get_property('incrvalue') if incrvalue is not None: - return self.exp.dereferencer.get_value(incrvalue) + return self.exp.dereferencer.get_value(incrvalue, field.width) if field.get_property('incrwidth'): return self.exp.hwif.get_implied_prop_input_identifier(field, "incrvalue") return "1'b1" @@ -118,8 +118,8 @@ class FieldLogic: def get_counter_incrsaturate_value(self, field: 'FieldNode') -> str: prop_value = field.get_property('incrsaturate') if prop_value is True: - return self.exp.dereferencer.get_value(2**field.width - 1) - return self.exp.dereferencer.get_value(prop_value) + return self.exp.dereferencer.get_value(2**field.width - 1, field.width) + return self.exp.dereferencer.get_value(prop_value, field.width) def counter_incrsaturates(self, field: 'FieldNode') -> bool: """ @@ -131,8 +131,8 @@ class FieldLogic: prop_value = field.get_property('incrthreshold') if isinstance(prop_value, bool): # No explicit value set. use max - return self.exp.dereferencer.get_value(2**field.width - 1) - return self.exp.dereferencer.get_value(prop_value) + return self.exp.dereferencer.get_value(2**field.width - 1, field.width) + return self.exp.dereferencer.get_value(prop_value, field.width) def get_counter_decr_strobe(self, field: 'FieldNode') -> str: """ @@ -151,7 +151,7 @@ class FieldLogic: """ decrvalue = field.get_property('decrvalue') if decrvalue is not None: - return self.exp.dereferencer.get_value(decrvalue) + return self.exp.dereferencer.get_value(decrvalue, field.width) if field.get_property('decrwidth'): return self.exp.hwif.get_implied_prop_input_identifier(field, "decrvalue") return "1'b1" @@ -159,8 +159,8 @@ class FieldLogic: def get_counter_decrsaturate_value(self, field: 'FieldNode') -> str: prop_value = field.get_property('decrsaturate') if prop_value is True: - return "'d0" - return self.exp.dereferencer.get_value(prop_value) + return f"{field.width}'d0" + return self.exp.dereferencer.get_value(prop_value, field.width) def counter_decrsaturates(self, field: 'FieldNode') -> bool: """ @@ -172,8 +172,8 @@ class FieldLogic: prop_value = field.get_property('decrthreshold') if isinstance(prop_value, bool): # No explicit value set. use min - return "'d0" - return self.exp.dereferencer.get_value(prop_value) + return f"{field.width}'d0" + return self.exp.dereferencer.get_value(prop_value, field.width) def get_swacc_identifier(self, field: 'FieldNode') -> str: """ diff --git a/src/peakrdl_regblock/field_logic/generators.py b/src/peakrdl_regblock/field_logic/generators.py index fc7f477..6dbf4c2 100644 --- a/src/peakrdl_regblock/field_logic/generators.py +++ b/src/peakrdl_regblock/field_logic/generators.py @@ -220,7 +220,7 @@ class FieldLogicGenerator(RDLForLoopGenerator): reset_value = node.get_property('reset') if reset_value is not None: - reset_value_str = self.exp.dereferencer.get_value(reset_value) + reset_value_str = self.exp.dereferencer.get_value(reset_value, node.width) else: # 5.9.1-g: If no reset value given, the field is not reset, even if it has a resetsignal. reset_value_str = None diff --git a/src/peakrdl_regblock/field_logic/templates/counter_macros.sv b/src/peakrdl_regblock/field_logic/templates/counter_macros.sv index 3c2b6f1..d23568b 100644 --- a/src/peakrdl_regblock/field_logic/templates/counter_macros.sv +++ b/src/peakrdl_regblock/field_logic/templates/counter_macros.sv @@ -7,7 +7,7 @@ next_c = next_c + {{field_logic.get_counter_incrvalue(node)}}; end {%- else %} - {{field_logic.get_field_combo_identifier(node, "overflow")}} = ((({{node.width+1}})'(next_c) + {{field_logic.get_counter_incrvalue(node)}}) > {{get_value(2**node.width - 1)}}); + {{field_logic.get_field_combo_identifier(node, "overflow")}} = ((({{node.width+1}})'(next_c) + {{field_logic.get_counter_incrvalue(node)}}) > {{get_value(2**node.width - 1, node.width)}}); next_c = next_c + {{field_logic.get_counter_incrvalue(node)}}; {%- endif %} load_next_c = '1; diff --git a/src/peakrdl_regblock/scan_design.py b/src/peakrdl_regblock/scan_design.py index 9992245..9e0768b 100644 --- a/src/peakrdl_regblock/scan_design.py +++ b/src/peakrdl_regblock/scan_design.py @@ -5,7 +5,7 @@ from systemrdl.node import SignalNode, RegNode if TYPE_CHECKING: from systemrdl.node import Node, FieldNode, AddressableNode, AddrmapNode - from .exporter import RegblockExporter + from .exporter import DesignState class DesignScanner(RDLListener): @@ -15,14 +15,13 @@ class DesignScanner(RDLListener): Also collects any information that is required prior to the start of the export process. """ - def __init__(self, exp:'RegblockExporter') -> None: - self.exp = exp - self.ds = exp.ds + def __init__(self, ds:'DesignState') -> None: + self.ds = ds self.msg = self.top_node.env.msg @property def top_node(self) -> 'AddrmapNode': - return self.exp.ds.top_node + return self.ds.top_node def _get_out_of_hier_field_reset(self) -> None: current_node = self.top_node.parent @@ -93,7 +92,7 @@ class DesignScanner(RDLListener): def enter_Reg(self, node: 'RegNode') -> None: # The CPUIF's bus width is sized according to the largest accesswidth in the design accesswidth = node.get_property('accesswidth') - self.exp.ds.cpuif_data_width = max(self.exp.ds.cpuif_data_width, accesswidth) + self.ds.cpuif_data_width = max(self.ds.cpuif_data_width, accesswidth) self.ds.has_buffered_write_regs = self.ds.has_buffered_write_regs or bool(node.get_property('buffer_writes')) self.ds.has_buffered_read_regs = self.ds.has_buffered_read_regs or bool(node.get_property('buffer_reads')) diff --git a/src/peakrdl_regblock/utils.py b/src/peakrdl_regblock/utils.py index e952d34..3dd7f3b 100644 --- a/src/peakrdl_regblock/utils.py +++ b/src/peakrdl_regblock/utils.py @@ -1,5 +1,5 @@ import re -from typing import Match, Union +from typing import Match, Union, Optional from systemrdl.rdltypes.references import PropertyReference from systemrdl.node import Node, AddrmapNode @@ -65,10 +65,13 @@ def ref_is_internal(top_node: AddrmapNode, ref: Union[Node, PropertyReference]) # This is considerd internal for this exporter return True -def get_sv_int(n: int) -> str: - if n.bit_length() <= 32: - return f"'h{n:x}" - else: +def get_sv_int(n: int, width: Optional[int]=None) -> str: + if width is not None: + # Explicit width + return f"{width}'h{n:x}" + elif n.bit_length() > 32: # SV standard only enforces that unsized literals shall be at least 32-bits # To support larger literals, they need to be sized explicitly return f"{n.bit_length()}'h{n:x}" + else: + return f"'h{n:x}"