diff --git a/src/peakrdl_regblock/__about__.py b/src/peakrdl_regblock/__about__.py index 49e0fc1..777f190 100644 --- a/src/peakrdl_regblock/__about__.py +++ b/src/peakrdl_regblock/__about__.py @@ -1 +1 @@ -__version__ = "0.7.0" +__version__ = "0.8.0" diff --git a/src/peakrdl_regblock/exporter.py b/src/peakrdl_regblock/exporter.py index af05bed..76a07cc 100644 --- a/src/peakrdl_regblock/exporter.py +++ b/src/peakrdl_regblock/exporter.py @@ -152,6 +152,7 @@ class RegblockExporter: context = { "module_name": module_name, "user_out_of_hier_signals": scanner.out_of_hier_signals.values(), + "has_writable_msb0_fields": scanner.has_writable_msb0_fields, "cpuif": self.cpuif, "hwif": self.hwif, "get_resetsignal": self.dereferencer.get_resetsignal, diff --git a/src/peakrdl_regblock/field_logic/sw_onwrite.py b/src/peakrdl_regblock/field_logic/sw_onwrite.py index a8038cd..df2ad3d 100644 --- a/src/peakrdl_regblock/field_logic/sw_onwrite.py +++ b/src/peakrdl_regblock/field_logic/sw_onwrite.py @@ -40,6 +40,14 @@ class _OnWrite(NextStateConditional): high = max(min(high, accesswidth), 0) low = max(min(low, accesswidth), 0) + if field.msb < field.lsb: + # slice is for an msb0 field. + # mirror it + bus_width = self.exp.cpuif.data_width + low = bus_width - 1 - low + high = bus_width - 1 - high + low, high = high, low + return f"[{high}:{low}]" def _wr_data(self, field: 'FieldNode', subword_idx: int=0) -> str: @@ -47,7 +55,7 @@ class _OnWrite(NextStateConditional): if field.msb < field.lsb: # Field gets bitswapped since it is in [low:high] orientation - value = f"{{<<{{decoded_wr_data{bslice}}}}}" + value = f"decoded_wr_data_bswap{bslice}" else: value = f"decoded_wr_data{bslice}" return value @@ -57,7 +65,7 @@ class _OnWrite(NextStateConditional): if field.msb < field.lsb: # Field gets bitswapped since it is in [low:high] orientation - value = f"{{<<{{decoded_wr_biten{bslice}}}}}" + value = f"decoded_wr_biten_bswap{bslice}" else: value = f"decoded_wr_biten{bslice}" return value diff --git a/src/peakrdl_regblock/module_tmpl.sv b/src/peakrdl_regblock/module_tmpl.sv index c5d84a2..c9bd456 100644 --- a/src/peakrdl_regblock/module_tmpl.sv +++ b/src/peakrdl_regblock/module_tmpl.sv @@ -96,6 +96,13 @@ module {{module_name}} ( assign decoded_req_is_wr = cpuif_req_is_wr; assign decoded_wr_data = cpuif_wr_data; assign decoded_wr_biten = cpuif_wr_biten; +{% if has_writable_msb0_fields %} + // bitswap for use by fields with msb0 ordering + logic [{{cpuif.data_width-1}}:0] decoded_wr_data_bswap; + logic [{{cpuif.data_width-1}}:0] decoded_wr_biten_bswap; + assign decoded_wr_data_bswap = {<<{decoded_wr_data}}; + assign decoded_wr_biten_bswap = {<<{decoded_wr_biten}}; +{%- endif %} // Writes are always granted with no error response assign cpuif_wr_ack = decoded_req & decoded_req_is_wr; diff --git a/src/peakrdl_regblock/scan_design.py b/src/peakrdl_regblock/scan_design.py index 580c547..f2960bf 100644 --- a/src/peakrdl_regblock/scan_design.py +++ b/src/peakrdl_regblock/scan_design.py @@ -25,6 +25,8 @@ class DesignScanner(RDLListener): self.in_hier_signal_paths = set() # type: Set[str] self.out_of_hier_signals = OrderedDict() # type: OrderedDict[str, SignalNode] + self.has_writable_msb0_fields = False + def _get_out_of_hier_field_reset(self) -> None: current_node = self.exp.top_node.parent while current_node is not None: @@ -80,6 +82,7 @@ class DesignScanner(RDLListener): self.in_hier_signal_paths.add(path) def enter_Field(self, node: 'FieldNode') -> None: + # Collect any signals that are referenced by a property for prop_name in node.list_properties(): value = node.get_property(prop_name) if isinstance(value, SignalNode): @@ -89,3 +92,6 @@ class DesignScanner(RDLListener): self.out_of_hier_signals[path] = value else: self.in_hier_signal_paths.add(path) + + if node.is_sw_writable and (node.msb < node.lsb): + self.has_writable_msb0_fields = True diff --git a/tests/lib/simulators/xilinx.py b/tests/lib/simulators/xilinx.py index 56464f1..b6e4440 100644 --- a/tests/lib/simulators/xilinx.py +++ b/tests/lib/simulators/xilinx.py @@ -7,8 +7,10 @@ from . import Simulator class Xilinx(Simulator): """ Don't bother using the Xilinx simulator... Its buggy and extraordinarily slow. - As observed in v2021.1, clocking block assignments do not seem to actually simulate - correctly - assignment statements get ignored or the values get mangled. + As observed in v2021.1: + - clocking block assignments do not seem to actually simulate correctly. + assignment statements get ignored or the values get mangled. + - Streaming operators have all sorts of limitations. Keeping this here in case someday it works better... """ @@ -16,6 +18,7 @@ class Xilinx(Simulator): cmd = [ "xvlog", "--sv", "--include", os.path.join(os.path.dirname(__file__), ".."), + "--define", "XSIM", ] cmd.extend(self.tb_files) subprocess.run(cmd, check=True) diff --git a/tests/test_structural_sw_rw/tb_template.sv b/tests/test_structural_sw_rw/tb_template.sv index 2df4cbb..bd7d4d3 100644 --- a/tests/test_structural_sw_rw/tb_template.sv +++ b/tests/test_structural_sw_rw/tb_template.sv @@ -71,10 +71,13 @@ cpuif.assert_read('h3000, 'h4DEAB000); // rw_reg_lsb0 - cpuif.assert_read('h3004, 0); - cpuif.write('h3004, 'h4DEAB000); - @cb; - assert({<<{cb.hwif_out.rw_reg_lsb0.f1.value}} == 8'hAB); - assert({<<{cb.hwif_out.rw_reg_lsb0.f2.value}} == 11'h4DE); - cpuif.assert_read('h3004, 'h4DEAB000); + `ifndef XSIM + // Xilinx simulator has poor support for streaming operators. Skip + cpuif.assert_read('h3004, 0); + cpuif.write('h3004, 'h4DEAB000); + @cb; + assert({<<{cb.hwif_out.rw_reg_lsb0.f1.value}} == 8'hAB); + assert({<<{cb.hwif_out.rw_reg_lsb0.f2.value}} == 11'h4DE); + cpuif.assert_read('h3004, 'h4DEAB000); + `endif {% endblock %}