diff --git a/docs/dev_notes/Some Classes b/docs/dev_notes/Some Classes deleted file mode 100644 index eadfad3..0000000 --- a/docs/dev_notes/Some Classes +++ /dev/null @@ -1,45 +0,0 @@ - -================================================================================ -Signal wrapper classes -================================================================================ -Define a signal wrapper class that is easier to use in templates. - -Provides the following properties: - .is_async - .is_activehigh - .identifier - Returns the Verilog identifier string for this signal - .activehigh_identifier - Normalizes identifier to active-high logic - same as .identifier, but prepends '~' if is_activehigh = False - .width - -Default reset class instance: - Extends the base class - Hardcodes as follows: - .is_async = True - .is_activehigh = True - .identifier = "rst" - .width = 1 - -Wrapper classes - Wrap around a systemrdl.SignalNode - - -================================================================================ -CPU Interface Class -================================================================================ -Entry point class for a given CPU interface type (APB, AXI, etc..) - -Does the following: - - Provide linkage to the logic implementation Jinja template - - Interface signal identifier properties - Aliases for signal identifiers to allow flat or sv-interface style - eg: - self.psel --> "s_apb_psel" or "s_apb.psel" - if sv interface, use the interface name class prpoerty - - Port declaration text property - declare as sv interface, or flat port list - If flattened, should use signal identifier properties - If sv interface, I should breakout the interface & modport name as - class properties for easy user-override diff --git a/docs/dev_notes/Validation Needed b/docs/dev_notes/Validation Needed index 5cc6ae6..c30fed6 100644 --- a/docs/dev_notes/Validation Needed +++ b/docs/dev_notes/Validation Needed @@ -117,6 +117,7 @@ X incrvalue/decrvalue needs to be the same or narrower than counter itself ! incrwidth/decrwidth must be between 1 and the width of the counter + ================================================================================ Things that need validation by this exporter ================================================================================ diff --git a/docs/dev_notes/template-layers/1.1.hardware-interface b/docs/dev_notes/template-layers/1.1.hardware-interface index b6a76d4..e23442a 100644 --- a/docs/dev_notes/template-layers/1.1.hardware-interface +++ b/docs/dev_notes/template-layers/1.1.hardware-interface @@ -5,11 +5,37 @@ Summary RTL interface that provides access to per-field context signals Regarding signals: - I think RDL-declared signals should actually be part of the hwif input - structure. - Exceptions: - - if the signal instance is at the top-level, it will get promoted to the - top level port list for convenience, and therefore omitted from the struct + RDL-declared signals are part of the hwif input structure. + Only include them if they are referenced by the design (need to scan the + full design anyways, so may as well filter out unreferenced ones) + + It is possible to use signals declared in a parent scope. + This means that not all signals will be discovered by a hierarchical listener alone + Need to scan ALL assigned properties for signal references too. + - get signal associated with top node's cpuif_reset helper property, if any + - collect all field_resets + X check all signal instances in the hier tree + - search parents of top node for the first field_reset signal, if any + This is WAY less expensive than querying EACH field's resetsignal property + X Check all explicitly assigned properties + only need to do this for fields + Collect all of these into the following: + - If inside the hier, add to a list of paths + - if outside the hier, add to a dict of path:SignalNode + These are all the signals in-use by the design + + Pass list into the hwif generator + If the hwif generator encounters a signal during traversal: + check if it exists in the signal path list + + out-of-hier signals are inserted outside of the hwif_in as standalone signals. + For now, just use their plain inst names. If I need to uniquify them i can add that later. + I should at least check against a list of known "dirty words". Seems very likely someone will choose + a signal called "rst". + Prefix with usersig_ if needed + + + ================================================================================ Naming Scheme diff --git a/docs/props/field.rst b/docs/props/field.rst index b766786..273e431 100644 --- a/docs/props/field.rst +++ b/docs/props/field.rst @@ -446,8 +446,8 @@ integer |OK| reference - |EX| + |OK| resetsignal ^^^^^^^^^^^ -|EX| +|OK| diff --git a/peakrdl/regblock/cpuif/apb3/apb3_tmpl.sv b/peakrdl/regblock/cpuif/apb3/apb3_tmpl.sv index c4c77be..c7bc6d0 100644 --- a/peakrdl/regblock/cpuif/apb3/apb3_tmpl.sv +++ b/peakrdl/regblock/cpuif/apb3/apb3_tmpl.sv @@ -4,7 +4,7 @@ // Request logic is_active; always_ff {{get_always_ff_event(cpuif.reset)}} begin - if({{cpuif.reset.activehigh_identifier}}) begin + if({{get_resetsignal(cpuif.reset)}}) begin is_active <= '0; cpuif_req <= '0; cpuif_req_is_wr <= '0; diff --git a/peakrdl/regblock/cpuif/base.py b/peakrdl/regblock/cpuif/base.py index d6a9f96..db5a8c4 100644 --- a/peakrdl/regblock/cpuif/base.py +++ b/peakrdl/regblock/cpuif/base.py @@ -1,15 +1,15 @@ -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Optional from ..utils import get_always_ff_event, clog2 if TYPE_CHECKING: from ..exporter import RegblockExporter - from ..signals import SignalBase + from systemrdl import SignalNode class CpuifBase: template_path = "cpuif/base_tmpl.sv" - def __init__(self, exp:'RegblockExporter', cpuif_reset:'SignalBase', data_width:int=32, addr_width:int=32): + def __init__(self, exp:'RegblockExporter', cpuif_reset:Optional['SignalNode'], data_width:int=32, addr_width:int=32): self.exp = exp self.reset = cpuif_reset self.data_width = data_width @@ -22,7 +22,8 @@ class CpuifBase: def get_implementation(self) -> str: context = { "cpuif": self, - "get_always_ff_event": get_always_ff_event, + "get_always_ff_event": lambda resetsignal : get_always_ff_event(self.exp.dereferencer, resetsignal), + "get_resetsignal": self.exp.dereferencer.get_resetsignal, "clog2": clog2, } diff --git a/peakrdl/regblock/dereferencer.py b/peakrdl/regblock/dereferencer.py index e475f9b..6013515 100644 --- a/peakrdl/regblock/dereferencer.py +++ b/peakrdl/regblock/dereferencer.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Union +from typing import TYPE_CHECKING, Union, Optional from systemrdl.node import AddrmapNode, FieldNode, SignalNode, RegNode from systemrdl.rdltypes import PropertyReference @@ -200,3 +200,17 @@ class Dereferencer: Returns the Verilog string that represents the register's access strobe """ return self.address_decode.get_access_strobe(obj) + + def get_resetsignal(self, obj: Optional[SignalNode]) -> str: + """ + Returns a normalized active-high reset signal + """ + if isinstance(obj, SignalNode): + s = self.get_value(obj) + if obj.get_property('activehigh'): + return s + else: + return f"~{s}" + + # default reset signal + return "rst" diff --git a/peakrdl/regblock/exporter.py b/peakrdl/regblock/exporter.py index 623af34..f64e75e 100644 --- a/peakrdl/regblock/exporter.py +++ b/peakrdl/regblock/exporter.py @@ -3,13 +3,11 @@ from typing import Union import jinja2 as jj from systemrdl.node import AddrmapNode, RootNode -from systemrdl.walker import RDLWalker from .addr_decode import AddressDecode from .field_logic import FieldLogic from .dereferencer import Dereferencer from .readback import Readback -from .signals import InferredSignal, RDLSignal from .cpuif import CpuifBase from .cpuif.apb3 import APB3_Cpuif @@ -33,8 +31,6 @@ class RegblockExporter: self.field_logic = FieldLogic(self) self.readback = None # type: Readback self.dereferencer = Dereferencer(self) - self.default_resetsignal = InferredSignal("rst") - if user_template_dir: loader = jj.ChoiceLoader([ @@ -84,23 +80,11 @@ class RegblockExporter: # Scan the design for any unsupported features # Also collect pre-export information scanner = DesignScanner(self) - RDLWalker().walk(self.top_node, scanner) - if scanner.msg.had_error: - scanner.msg.fatal( - "Unable to export due to previous errors" - ) - raise ValueError - - cpuif_reset_tmp = self.top_node.cpuif_reset - if cpuif_reset_tmp: - cpuif_reset = RDLSignal(cpuif_reset_tmp) - else: - cpuif_reset = self.default_resetsignal - reset_signals = set([cpuif_reset, self.default_resetsignal]) + scanner.do_scan() self.cpuif = cpuif_cls( self, - cpuif_reset=cpuif_reset, + cpuif_reset=self.top_node.cpuif_reset, data_width=scanner.cpuif_data_width, addr_width=self.top_node.size.bit_length() ) @@ -108,7 +92,9 @@ class RegblockExporter: self.hwif = Hwif( self, package_name=package_name, - reuse_typedefs=reuse_hwif_typedefs + in_hier_signal_paths=scanner.in_hier_signal_paths, + out_of_hier_signals=scanner.out_of_hier_signals, + reuse_typedefs=reuse_hwif_typedefs, ) self.readback = Readback( @@ -119,15 +105,15 @@ class RegblockExporter: # Build Jinja template context context = { "module_name": module_name, - "reset_signals": reset_signals, - "user_signals": [], # TODO: + "user_out_of_hier_signals": scanner.out_of_hier_signals.values(), "interrupts": [], # TODO: "cpuif": self.cpuif, "hwif": self.hwif, + "get_resetsignal": self.dereferencer.get_resetsignal, "address_decode": self.address_decode, "field_logic": self.field_logic, "readback": self.readback, - "get_always_ff_event": get_always_ff_event, + "get_always_ff_event": lambda resetsignal : get_always_ff_event(self.dereferencer, resetsignal), "retime_read_response": retime_read_response, } diff --git a/peakrdl/regblock/field_logic/generators.py b/peakrdl/regblock/field_logic/generators.py index 7716880..d450664 100644 --- a/peakrdl/regblock/field_logic/generators.py +++ b/peakrdl/regblock/field_logic/generators.py @@ -5,7 +5,6 @@ from collections import OrderedDict from ..struct_generator import RDLStructGenerator from ..forloop_generator import RDLForLoopGenerator from ..utils import get_indexed_path, get_always_ff_event -from ..signals import RDLSignal if TYPE_CHECKING: from . import FieldLogic @@ -92,11 +91,7 @@ class FieldLogicGenerator(RDLForLoopGenerator): for signal in conditional.get_extra_combo_signals(node): extra_combo_signals[signal.name] = signal - sig = node.get_property('resetsignal') - if sig is not None: - resetsignal = RDLSignal(sig) - else: - resetsignal = self.exp.default_resetsignal + resetsignal = node.get_property('resetsignal') reset_value = node.get_property('reset') if reset_value is not None: @@ -114,8 +109,9 @@ class FieldLogicGenerator(RDLForLoopGenerator): 'extra_combo_signals': extra_combo_signals, 'conditionals': conditionals, 'resetsignal': resetsignal, - 'get_always_ff_event': get_always_ff_event, + 'get_always_ff_event': lambda resetsignal : get_always_ff_event(self.exp.dereferencer, resetsignal), 'get_value': self.exp.dereferencer.get_value, + 'get_resetsignal': self.exp.dereferencer.get_resetsignal, } self.add_content(self.field_storage_template.render(context)) diff --git a/peakrdl/regblock/field_logic/templates/field_storage.sv b/peakrdl/regblock/field_logic/templates/field_storage.sv index 8536e2f..d763311 100644 --- a/peakrdl/regblock/field_logic/templates/field_storage.sv +++ b/peakrdl/regblock/field_logic/templates/field_storage.sv @@ -23,8 +23,8 @@ always_comb begin field_combo.{{field_path}}.load_next = load_next_c; end always_ff {{get_always_ff_event(resetsignal)}} begin - {% if resetsignal is not none -%} - if({{resetsignal.activehigh_identifier}}) begin + {% if reset is not none -%} + if({{get_resetsignal(resetsignal)}}) begin field_storage.{{field_path}} <= {{reset}}; end else {% endif %}if(field_combo.{{field_path}}.load_next) begin field_storage.{{field_path}} <= field_combo.{{field_path}}.next; diff --git a/peakrdl/regblock/hwif/__init__.py b/peakrdl/regblock/hwif/__init__.py index 4ce5b22..026e4de 100644 --- a/peakrdl/regblock/hwif/__init__.py +++ b/peakrdl/regblock/hwif/__init__.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Union, List +from typing import TYPE_CHECKING, Union, List, Set, Dict from systemrdl.node import AddrmapNode, Node, SignalNode, FieldNode, AddressableNode from systemrdl.rdltypes import PropertyReference @@ -19,13 +19,19 @@ class Hwif: - Signal inputs (except those that are promoted to the top) """ - def __init__(self, exp: 'RegblockExporter', package_name: str, reuse_typedefs: bool): + def __init__( + self, exp: 'RegblockExporter', package_name: str, + in_hier_signal_paths: Set[str], out_of_hier_signals: Dict[str, SignalNode], + reuse_typedefs: bool + ): self.exp = exp self.package_name = package_name self.has_input_struct = None self.has_output_struct = None - self._indent_level = 0 + + self.in_hier_signal_paths = in_hier_signal_paths + self.out_of_hier_signals = out_of_hier_signals if reuse_typedefs: self._gen_in_cls = InputStructGenerator_TypeScope @@ -45,7 +51,7 @@ class Hwif: """ lines = [] - gen_in = self._gen_in_cls(self.top_node) + gen_in = self._gen_in_cls(self) structs_in = gen_in.get_struct( self.top_node, f"{self.top_node.inst_name}__in_t" @@ -56,7 +62,7 @@ class Hwif: else: self.has_input_struct = False - gen_out = self._gen_out_cls(self.top_node) + gen_out = self._gen_out_cls(self) structs_out = gen_out.get_struct( self.top_node, f"{self.top_node.inst_name}__out_t" @@ -129,8 +135,10 @@ class Hwif: path = get_indexed_path(self.top_node, obj) return "hwif_in." + path + ".value" elif isinstance(obj, SignalNode): - # TODO: Implement this - raise NotImplementedError() + if obj.get_path() in self.out_of_hier_signals: + return obj.inst_name + path = get_indexed_path(self.top_node, obj) + return "hwif_in." + path elif isinstance(obj, PropertyReference): return self.get_implied_prop_input_identifier(obj.node, obj.name) diff --git a/peakrdl/regblock/hwif/generators.py b/peakrdl/regblock/hwif/generators.py index 05e6f0d..902d547 100644 --- a/peakrdl/regblock/hwif/generators.py +++ b/peakrdl/regblock/hwif/generators.py @@ -3,11 +3,13 @@ from ..struct_generator import RDLFlatStructGenerator if TYPE_CHECKING: from systemrdl.node import Node, SignalNode, FieldNode + from . import Hwif class InputStructGenerator_Hier(RDLFlatStructGenerator): - def __init__(self, top_node: 'Node'): + def __init__(self, hwif: 'Hwif'): super().__init__() - self.top_node = top_node + self.hwif = hwif + self.top_node = hwif.top_node def get_typdef_name(self, node:'Node') -> str: base = node.get_rel_path( @@ -19,7 +21,10 @@ class InputStructGenerator_Hier(RDLFlatStructGenerator): return f'{base}__in_t' def enter_Signal(self, node: 'SignalNode') -> None: - self.add_member(node.inst_name, node.width) + # only emit the signal if design scanner detected it is actually being used + path = node.get_path() + if path in self.hwif.in_hier_signal_paths: + self.add_member(node.inst_name, node.width) def enter_Field(self, node: 'FieldNode') -> None: type_name = self.get_typdef_name(node) diff --git a/peakrdl/regblock/module_tmpl.sv b/peakrdl/regblock/module_tmpl.sv index 17099b9..92b4912 100644 --- a/peakrdl/regblock/module_tmpl.sv +++ b/peakrdl/regblock/module_tmpl.sv @@ -1,16 +1,18 @@ // TODO: Add a banner module {{module_name}} ( input wire clk, - {%- for signal in reset_signals %} - {{signal.port_declaration}}, - {%- endfor %} + input wire rst, - {%- for signal in user_signals %} - {{signal.port_declaration}}, + {%- for signal in user_out_of_hier_signals %} + {%- if signal.width == 1 %} + input wire {{signal.inst_name}}, + {%- else %} + input wire [{{signal.width-1}}:0] {{signal.inst_name}}, + {%- endif %} {%- endfor %} {%- for interrupt in interrupts %} - {{interrupt.port_declaration}}, + // TODO: {%- endfor %} {{cpuif.port_declaration|indent(8)}} @@ -77,7 +79,7 @@ module {{module_name}} ( {% if retime_read_response %} always_ff {{get_always_ff_event(cpuif.reset)}} begin - if({{cpuif.reset.activehigh_identifier}}) begin + if({{get_resetsignal(cpuif.reset)}}) begin cpuif_rd_ack <= '0; cpuif_rd_data <= '0; cpuif_rd_err <= '0; diff --git a/peakrdl/regblock/readback/__init__.py b/peakrdl/regblock/readback/__init__.py index 46d8b98..4494229 100644 --- a/peakrdl/regblock/readback/__init__.py +++ b/peakrdl/regblock/readback/__init__.py @@ -30,7 +30,7 @@ class Readback: context = { "array_assignments" : array_assignments, "array_size" : array_size, - "get_always_ff_event": get_always_ff_event, + "get_always_ff_event": lambda resetsignal : get_always_ff_event(self.exp.dereferencer, resetsignal), "cpuif": self.exp.cpuif, "do_fanin_stage": self.do_fanin_stage, } diff --git a/peakrdl/regblock/scan_design.py b/peakrdl/regblock/scan_design.py index 8bb4e1c..578faec 100644 --- a/peakrdl/regblock/scan_design.py +++ b/peakrdl/regblock/scan_design.py @@ -1,10 +1,11 @@ from typing import TYPE_CHECKING +from collections import OrderedDict -from systemrdl.walker import RDLListener -from systemrdl.node import AddrmapNode +from systemrdl.walker import RDLListener, RDLWalker +from systemrdl.node import AddrmapNode, SignalNode if TYPE_CHECKING: - from systemrdl.node import Node, RegNode, SignalNode, MemNode + from systemrdl.node import Node, RegNode, MemNode, FieldNode from .exporter import RegblockExporter @@ -20,13 +21,45 @@ class DesignScanner(RDLListener): self.cpuif_data_width = 0 self.msg = exp.top_node.env.msg + # Collections of signals that were actually referenced by the design + self.in_hier_signal_paths = set() + self.out_of_hier_signals = OrderedDict() + + def _get_out_of_hier_field_reset(self): + current_node = self.exp.top_node.parent + while current_node is not None: + for signal in current_node.signals(): + if signal.get_property('field_reset'): + path = signal.get_path() + self.out_of_hier_signals[path] = signal + return + current_node = current_node.parent + + def do_scan(self): + # Collect cpuif reset, if any. + cpuif_reset = self.exp.top_node.cpuif_reset + if cpuif_reset is not None: + path = cpuif_reset.get_path() + rel_path = cpuif_reset.get_rel_path(self.exp.top_node) + if rel_path.startswith("^"): + self.out_of_hier_signals[path] = cpuif_reset + else: + self.in_hier_signal_paths.add(path) + + # collect out-of-hier field_reset, if any + self._get_out_of_hier_field_reset() + + RDLWalker().walk(self.exp.top_node, self) + if self.msg.had_error: + self.msg.fatal( + "Unable to export due to previous errors" + ) + raise ValueError + def enter_Reg(self, node: 'RegNode') -> None: # The CPUIF's bus width is sized according to the largest register in the design self.cpuif_data_width = max(self.cpuif_data_width, node.get_property('regwidth')) - # TODO: Collect any references to signals that lie outside of the hierarchy - # These will be added as top-level signals - def enter_Component(self, node: 'Node') -> None: if not isinstance(node, AddrmapNode) and node.external: self.msg.error( @@ -46,6 +79,21 @@ class DesignScanner(RDLListener): node.inst.inst_src_ref ) + if node.get_property('field_reset'): + path = node.get_path() + self.in_hier_signal_paths.add(path) + + def enter_Field(self, node: 'FieldNode') -> None: + for prop_name in node.list_properties(): + value = node.get_property(prop_name) + if isinstance(value, SignalNode): + path = value.get_path() + rel_path = value.get_rel_path(self.exp.top_node) + if rel_path.startswith("^"): + self.out_of_hier_signals[path] = value + else: + self.in_hier_signal_paths.add(path) + def enter_Mem(self, node: 'MemNode') -> None: self.msg.error( "Cannot export a register block that contains a memory", diff --git a/peakrdl/regblock/signals.py b/peakrdl/regblock/signals.py deleted file mode 100644 index 7abd586..0000000 --- a/peakrdl/regblock/signals.py +++ /dev/null @@ -1,91 +0,0 @@ -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from systemrdl import SignalNode - -class SignalBase: - - @property - def is_async(self) -> bool: - raise NotImplementedError() - - @property - def is_activehigh(self) -> bool: - raise NotImplementedError() - - @property - def width(self) -> int: - raise NotImplementedError() - - @property - def identifier(self) -> str: - raise NotImplementedError() - - @property - def activehigh_identifier(self) -> str: - """ - Normalizes the identifier reference to be active-high logic - """ - if not self.is_activehigh: - return "~%s" % self.identifier - return self.identifier - - @property - def port_declaration(self) -> str: - """ - Returns the port delcaration text for this signal. - In the context of this exporter, all signal objects happen to be inputs. - """ - if self.width > 1: - return "input wire [%d:0] %s" % (self.width - 1, self.identifier) - return "input wire %s" % self.identifier - - -class RDLSignal(SignalBase): - """ - Wrapper around a SystemRDL signal object - """ - def __init__(self, rdl_signal:'SignalNode'): - self.rdl_signal = rdl_signal - - @property - def is_async(self) -> bool: - return self.rdl_signal.get_property('async') - - @property - def is_activehigh(self) -> bool: - return self.rdl_signal.get_property('activehigh') - - @property - def width(self) -> int: - return self.rdl_signal.width - - @property - def identifier(self) -> str: - # TODO: uniquify this somehow - # TODO: Deal with different hierarchies - return "TODO_%s" % self.rdl_signal.inst_name - - -class InferredSignal(SignalBase): - def __init__(self, identifier:str, width:int=1, is_async:bool=False, is_activehigh=True): - self._identifier = identifier - self._width = width - self._is_async = is_async - self._is_activehigh = is_activehigh - - @property - def is_async(self) -> bool: - return self._is_async - - @property - def is_activehigh(self) -> bool: - return self._is_activehigh - - @property - def width(self) -> int: - return self._width - - @property - def identifier(self) -> str: - return self._identifier diff --git a/peakrdl/regblock/utils.py b/peakrdl/regblock/utils.py index 45ade86..c550bdd 100644 --- a/peakrdl/regblock/utils.py +++ b/peakrdl/regblock/utils.py @@ -2,9 +2,9 @@ import re from typing import TYPE_CHECKING if TYPE_CHECKING: - from systemrdl.node import Node - from .signals import SignalBase + from systemrdl.node import Node, SignalNode from typing import Optional + from .dereferencer import Dereferencer def get_indexed_path(top_node: 'Node', target_node: 'Node') -> str: """ @@ -22,13 +22,13 @@ def get_indexed_path(top_node: 'Node', target_node: 'Node') -> str: return re.sub(r'!', repl(), path) -def get_always_ff_event(resetsignal: 'Optional[SignalBase]') -> str: +def get_always_ff_event(dereferencer: 'Dereferencer', resetsignal: 'Optional[SignalNode]') -> str: if resetsignal is None: return "@(posedge clk)" - if resetsignal.is_async and resetsignal.is_activehigh: - return f"@(posedge clk or posedge {resetsignal.identifier})" - elif resetsignal.is_async and not resetsignal.is_activehigh: - return f"@(posedge clk or negedge {resetsignal.identifier})" + if resetsignal.get_property('async') and resetsignal.get_property('activehigh'): + return f"@(posedge clk or posedge {dereferencer.get_value(resetsignal)})" + elif resetsignal.get_property('async') and not resetsignal.get_property('activehigh'): + return f"@(posedge clk or negedge {dereferencer.get_value(resetsignal)})" return "@(posedge clk)" def clog2(n: int) -> int: diff --git a/test/lib/tb_base.sv b/test/lib/tb_base.sv index b64fa83..1b3fb3a 100644 --- a/test/lib/tb_base.sv +++ b/test/lib/tb_base.sv @@ -6,7 +6,7 @@ module tb; logic rst = '1; logic clk = '0; initial forever begin - #10ns; + #5ns; clk = ~clk; end diff --git a/test/test_reset_signals/__init__.py b/test/test_reset_signals/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/test_reset_signals/regblock.rdl b/test/test_reset_signals/regblock.rdl new file mode 100644 index 0000000..e62fef8 --- /dev/null +++ b/test/test_reset_signals/regblock.rdl @@ -0,0 +1,80 @@ + +signal { + cpuif_reset; activehigh; +} root_cpuif_reset; + +signal {} r5f2_resetvalue[16]; + +addrmap top { + reg { + field { + sw=rw; hw=na; + } f1[16] = 0x1234; + field { + sw=rw; hw=na; + } f2[16] = 0x5678; + } r1; + + reg { + field { + sw=rw; hw=na; + } f1[16] = 0x1234; + field { + sw=rw; hw=na; + } f2[16] = 0x5678; + + signal { + field_reset; activehigh; sync; + } my_reset; + } r2; + + reg { + field { + sw=rw; hw=na; + } f1[16] = 0x1234; + field { + sw=rw; hw=na; + } f2[16] = 0x5678; + + signal { + field_reset; activehigh; async; + } my_areset; + } r3; + + reg { + field { + sw=rw; hw=na; + } f1[16] = 0x1234; + field { + sw=rw; hw=na; + } f2[16] = 0x5678; + + signal { + field_reset; activelow; sync; + } my_reset_n; + } r4; + + reg { + field { + sw=rw; hw=na; + } f1[16] = 0x1234; + field { + sw=rw; hw=na; + reset = r5f2_resetvalue; + } f2[16]; + + signal { + field_reset; activelow; async; + } my_areset_n; + } r5; + + signal { + activehigh; sync; + } f2_reset; + + r1.f2->resetsignal = f2_reset; + r2.f2->resetsignal = f2_reset; + r3.f2->resetsignal = f2_reset; + r4.f2->resetsignal = f2_reset; + r5.f2->resetsignal = f2_reset; +}; diff --git a/test/test_reset_signals/tb_template.sv b/test/test_reset_signals/tb_template.sv new file mode 100644 index 0000000..5429b9e --- /dev/null +++ b/test/test_reset_signals/tb_template.sv @@ -0,0 +1,128 @@ +{% extends "lib/tb_base.sv" %} + +{%- block declarations %} + logic root_cpuif_reset; + logic [15:0] r5f2_resetvalue; +{%- endblock %} + +{%- block clocking_dirs %} + output root_cpuif_reset; + output r5f2_resetvalue; +{%- endblock %} + +{% block seq %} + {% sv_line_anchor %} + cb.root_cpuif_reset <= '1; + cb.hwif_in.r2.my_reset <= '1; + cb.hwif_in.r3.my_areset <= '1; + cb.hwif_in.r4.my_reset_n <= '0; + cb.hwif_in.r5.my_areset_n <= '0; + cb.hwif_in.f2_reset <= '1; + cb.r5f2_resetvalue <= 'hABCD; + ##2; + cb.rst <= '0; + cb.root_cpuif_reset <= '0; + cb.hwif_in.r2.my_reset <= '0; + cb.hwif_in.r3.my_areset <= '0; + cb.hwif_in.r4.my_reset_n <= '1; + cb.hwif_in.r5.my_areset_n <= '1; + cb.hwif_in.f2_reset <= '0; + ##1; + + + cpuif.assert_read('h00, 'h5678_1234); + cpuif.assert_read('h04, 'h5678_1234); + cpuif.assert_read('h08, 'h5678_1234); + cpuif.assert_read('h0c, 'h5678_1234); + cpuif.assert_read('h10, 'hABCD_1234); + + for(int i=0; i<5; i++) cpuif.write(i*4, 0); + + cpuif.assert_read('h00, 'h0000_0000); + cpuif.assert_read('h04, 'h0000_0000); + cpuif.assert_read('h08, 'h0000_0000); + cpuif.assert_read('h0c, 'h0000_0000); + cpuif.assert_read('h10, 'h0000_0000); + + cb.rst <= '1; + @cb; + cb.rst <= '0; + @cb; + + cpuif.assert_read('h00, 'h0000_1234); + cpuif.assert_read('h04, 'h0000_0000); + cpuif.assert_read('h08, 'h0000_0000); + cpuif.assert_read('h0c, 'h0000_0000); + cpuif.assert_read('h10, 'h0000_0000); + + for(int i=0; i<5; i++) cpuif.write(i*4, 0); + + cb.hwif_in.r2.my_reset <= '1; + @cb; + cb.hwif_in.r2.my_reset <= '0; + @cb; + + cpuif.assert_read('h00, 'h0000_0000); + cpuif.assert_read('h04, 'h0000_1234); + cpuif.assert_read('h08, 'h0000_0000); + cpuif.assert_read('h0c, 'h0000_0000); + cpuif.assert_read('h10, 'h0000_0000); + + for(int i=0; i<5; i++) cpuif.write(i*4, 0); + + ##1; + #2ns; + hwif_in.r3.my_areset = '1; + #1ns; + hwif_in.r3.my_areset = '0; + ##1; + + cpuif.assert_read('h00, 'h0000_0000); + cpuif.assert_read('h04, 'h0000_0000); + cpuif.assert_read('h08, 'h0000_1234); + cpuif.assert_read('h0c, 'h0000_0000); + cpuif.assert_read('h10, 'h0000_0000); + + for(int i=0; i<5; i++) cpuif.write(i*4, 0); + + cb.hwif_in.r4.my_reset_n <= '0; + @cb; + cb.hwif_in.r4.my_reset_n <= '1; + @cb; + + cpuif.assert_read('h00, 'h0000_0000); + cpuif.assert_read('h04, 'h0000_0000); + cpuif.assert_read('h08, 'h0000_0000); + cpuif.assert_read('h0c, 'h0000_1234); + cpuif.assert_read('h10, 'h0000_0000); + + for(int i=0; i<5; i++) cpuif.write(i*4, 0); + + ##1; + #2ns; + hwif_in.r5.my_areset_n = '0; + #1ns; + hwif_in.r5.my_areset_n = '1; + ##1; + + cpuif.assert_read('h00, 'h0000_0000); + cpuif.assert_read('h04, 'h0000_0000); + cpuif.assert_read('h08, 'h0000_0000); + cpuif.assert_read('h0c, 'h0000_0000); + cpuif.assert_read('h10, 'h0000_1234); + + for(int i=0; i<5; i++) cpuif.write(i*4, 0); + + @cb; + cb.hwif_in.f2_reset <= '1; + cb.r5f2_resetvalue <= 'h3210; + @cb; + cb.hwif_in.f2_reset <= '0; + + cpuif.assert_read('h00, 'h5678_0000); + cpuif.assert_read('h04, 'h5678_0000); + cpuif.assert_read('h08, 'h5678_0000); + cpuif.assert_read('h0c, 'h5678_0000); + cpuif.assert_read('h10, 'h3210_0000); + +{% endblock %} diff --git a/test/test_reset_signals/testcase.py b/test/test_reset_signals/testcase.py new file mode 100644 index 0000000..b458d3c --- /dev/null +++ b/test/test_reset_signals/testcase.py @@ -0,0 +1,5 @@ +from ..lib.regblock_testcase import RegblockTestCase + +class Test(RegblockTestCase): + def test_dut(self): + self.run_test()