Signals working!

This commit is contained in:
Alex Mykyta
2021-12-15 22:03:57 -08:00
parent 7d0130078d
commit 769907404a
22 changed files with 376 additions and 212 deletions

View File

@@ -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

View File

@@ -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 ! incrwidth/decrwidth must be between 1 and the width of the counter
================================================================================ ================================================================================
Things that need validation by this exporter Things that need validation by this exporter
================================================================================ ================================================================================

View File

@@ -5,11 +5,37 @@ Summary
RTL interface that provides access to per-field context signals RTL interface that provides access to per-field context signals
Regarding signals: Regarding signals:
I think RDL-declared signals should actually be part of the hwif input RDL-declared signals are part of the hwif input structure.
structure. Only include them if they are referenced by the design (need to scan the
Exceptions: full design anyways, so may as well filter out unreferenced ones)
- 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 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 Naming Scheme

View File

@@ -446,8 +446,8 @@ integer
|OK| |OK|
reference reference
|EX| |OK|
resetsignal resetsignal
^^^^^^^^^^^ ^^^^^^^^^^^
|EX| |OK|

View File

@@ -4,7 +4,7 @@
// Request // Request
logic is_active; logic is_active;
always_ff {{get_always_ff_event(cpuif.reset)}} begin always_ff {{get_always_ff_event(cpuif.reset)}} begin
if({{cpuif.reset.activehigh_identifier}}) begin if({{get_resetsignal(cpuif.reset)}}) begin
is_active <= '0; is_active <= '0;
cpuif_req <= '0; cpuif_req <= '0;
cpuif_req_is_wr <= '0; cpuif_req_is_wr <= '0;

View File

@@ -1,15 +1,15 @@
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Optional
from ..utils import get_always_ff_event, clog2 from ..utils import get_always_ff_event, clog2
if TYPE_CHECKING: if TYPE_CHECKING:
from ..exporter import RegblockExporter from ..exporter import RegblockExporter
from ..signals import SignalBase from systemrdl import SignalNode
class CpuifBase: class CpuifBase:
template_path = "cpuif/base_tmpl.sv" 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.exp = exp
self.reset = cpuif_reset self.reset = cpuif_reset
self.data_width = data_width self.data_width = data_width
@@ -22,7 +22,8 @@ class CpuifBase:
def get_implementation(self) -> str: def get_implementation(self) -> str:
context = { context = {
"cpuif": self, "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, "clog2": clog2,
} }

View File

@@ -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.node import AddrmapNode, FieldNode, SignalNode, RegNode
from systemrdl.rdltypes import PropertyReference from systemrdl.rdltypes import PropertyReference
@@ -200,3 +200,17 @@ class Dereferencer:
Returns the Verilog string that represents the register's access strobe Returns the Verilog string that represents the register's access strobe
""" """
return self.address_decode.get_access_strobe(obj) 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"

View File

@@ -3,13 +3,11 @@ from typing import Union
import jinja2 as jj import jinja2 as jj
from systemrdl.node import AddrmapNode, RootNode from systemrdl.node import AddrmapNode, RootNode
from systemrdl.walker import RDLWalker
from .addr_decode import AddressDecode from .addr_decode import AddressDecode
from .field_logic import FieldLogic from .field_logic import FieldLogic
from .dereferencer import Dereferencer from .dereferencer import Dereferencer
from .readback import Readback from .readback import Readback
from .signals import InferredSignal, RDLSignal
from .cpuif import CpuifBase from .cpuif import CpuifBase
from .cpuif.apb3 import APB3_Cpuif from .cpuif.apb3 import APB3_Cpuif
@@ -33,8 +31,6 @@ class RegblockExporter:
self.field_logic = FieldLogic(self) self.field_logic = FieldLogic(self)
self.readback = None # type: Readback self.readback = None # type: Readback
self.dereferencer = Dereferencer(self) self.dereferencer = Dereferencer(self)
self.default_resetsignal = InferredSignal("rst")
if user_template_dir: if user_template_dir:
loader = jj.ChoiceLoader([ loader = jj.ChoiceLoader([
@@ -84,23 +80,11 @@ class RegblockExporter:
# Scan the design for any unsupported features # Scan the design for any unsupported features
# Also collect pre-export information # Also collect pre-export information
scanner = DesignScanner(self) scanner = DesignScanner(self)
RDLWalker().walk(self.top_node, scanner) scanner.do_scan()
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])
self.cpuif = cpuif_cls( self.cpuif = cpuif_cls(
self, self,
cpuif_reset=cpuif_reset, cpuif_reset=self.top_node.cpuif_reset,
data_width=scanner.cpuif_data_width, data_width=scanner.cpuif_data_width,
addr_width=self.top_node.size.bit_length() addr_width=self.top_node.size.bit_length()
) )
@@ -108,7 +92,9 @@ class RegblockExporter:
self.hwif = Hwif( self.hwif = Hwif(
self, self,
package_name=package_name, 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( self.readback = Readback(
@@ -119,15 +105,15 @@ class RegblockExporter:
# Build Jinja template context # Build Jinja template context
context = { context = {
"module_name": module_name, "module_name": module_name,
"reset_signals": reset_signals, "user_out_of_hier_signals": scanner.out_of_hier_signals.values(),
"user_signals": [], # TODO:
"interrupts": [], # TODO: "interrupts": [], # TODO:
"cpuif": self.cpuif, "cpuif": self.cpuif,
"hwif": self.hwif, "hwif": self.hwif,
"get_resetsignal": self.dereferencer.get_resetsignal,
"address_decode": self.address_decode, "address_decode": self.address_decode,
"field_logic": self.field_logic, "field_logic": self.field_logic,
"readback": self.readback, "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, "retime_read_response": retime_read_response,
} }

View File

@@ -5,7 +5,6 @@ from collections import OrderedDict
from ..struct_generator import RDLStructGenerator from ..struct_generator import RDLStructGenerator
from ..forloop_generator import RDLForLoopGenerator from ..forloop_generator import RDLForLoopGenerator
from ..utils import get_indexed_path, get_always_ff_event from ..utils import get_indexed_path, get_always_ff_event
from ..signals import RDLSignal
if TYPE_CHECKING: if TYPE_CHECKING:
from . import FieldLogic from . import FieldLogic
@@ -92,11 +91,7 @@ class FieldLogicGenerator(RDLForLoopGenerator):
for signal in conditional.get_extra_combo_signals(node): for signal in conditional.get_extra_combo_signals(node):
extra_combo_signals[signal.name] = signal extra_combo_signals[signal.name] = signal
sig = node.get_property('resetsignal') resetsignal = node.get_property('resetsignal')
if sig is not None:
resetsignal = RDLSignal(sig)
else:
resetsignal = self.exp.default_resetsignal
reset_value = node.get_property('reset') reset_value = node.get_property('reset')
if reset_value is not None: if reset_value is not None:
@@ -114,8 +109,9 @@ class FieldLogicGenerator(RDLForLoopGenerator):
'extra_combo_signals': extra_combo_signals, 'extra_combo_signals': extra_combo_signals,
'conditionals': conditionals, 'conditionals': conditionals,
'resetsignal': resetsignal, '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_value': self.exp.dereferencer.get_value,
'get_resetsignal': self.exp.dereferencer.get_resetsignal,
} }
self.add_content(self.field_storage_template.render(context)) self.add_content(self.field_storage_template.render(context))

View File

@@ -23,8 +23,8 @@ always_comb begin
field_combo.{{field_path}}.load_next = load_next_c; field_combo.{{field_path}}.load_next = load_next_c;
end end
always_ff {{get_always_ff_event(resetsignal)}} begin always_ff {{get_always_ff_event(resetsignal)}} begin
{% if resetsignal is not none -%} {% if reset is not none -%}
if({{resetsignal.activehigh_identifier}}) begin if({{get_resetsignal(resetsignal)}}) begin
field_storage.{{field_path}} <= {{reset}}; field_storage.{{field_path}} <= {{reset}};
end else {% endif %}if(field_combo.{{field_path}}.load_next) begin end else {% endif %}if(field_combo.{{field_path}}.load_next) begin
field_storage.{{field_path}} <= field_combo.{{field_path}}.next; field_storage.{{field_path}} <= field_combo.{{field_path}}.next;

View File

@@ -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.node import AddrmapNode, Node, SignalNode, FieldNode, AddressableNode
from systemrdl.rdltypes import PropertyReference from systemrdl.rdltypes import PropertyReference
@@ -19,13 +19,19 @@ class Hwif:
- Signal inputs (except those that are promoted to the top) - 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.exp = exp
self.package_name = package_name self.package_name = package_name
self.has_input_struct = None self.has_input_struct = None
self.has_output_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: if reuse_typedefs:
self._gen_in_cls = InputStructGenerator_TypeScope self._gen_in_cls = InputStructGenerator_TypeScope
@@ -45,7 +51,7 @@ class Hwif:
""" """
lines = [] lines = []
gen_in = self._gen_in_cls(self.top_node) gen_in = self._gen_in_cls(self)
structs_in = gen_in.get_struct( structs_in = gen_in.get_struct(
self.top_node, self.top_node,
f"{self.top_node.inst_name}__in_t" f"{self.top_node.inst_name}__in_t"
@@ -56,7 +62,7 @@ class Hwif:
else: else:
self.has_input_struct = False 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( structs_out = gen_out.get_struct(
self.top_node, self.top_node,
f"{self.top_node.inst_name}__out_t" f"{self.top_node.inst_name}__out_t"
@@ -129,8 +135,10 @@ class Hwif:
path = get_indexed_path(self.top_node, obj) path = get_indexed_path(self.top_node, obj)
return "hwif_in." + path + ".value" return "hwif_in." + path + ".value"
elif isinstance(obj, SignalNode): elif isinstance(obj, SignalNode):
# TODO: Implement this if obj.get_path() in self.out_of_hier_signals:
raise NotImplementedError() return obj.inst_name
path = get_indexed_path(self.top_node, obj)
return "hwif_in." + path
elif isinstance(obj, PropertyReference): elif isinstance(obj, PropertyReference):
return self.get_implied_prop_input_identifier(obj.node, obj.name) return self.get_implied_prop_input_identifier(obj.node, obj.name)

View File

@@ -3,11 +3,13 @@ from ..struct_generator import RDLFlatStructGenerator
if TYPE_CHECKING: if TYPE_CHECKING:
from systemrdl.node import Node, SignalNode, FieldNode from systemrdl.node import Node, SignalNode, FieldNode
from . import Hwif
class InputStructGenerator_Hier(RDLFlatStructGenerator): class InputStructGenerator_Hier(RDLFlatStructGenerator):
def __init__(self, top_node: 'Node'): def __init__(self, hwif: 'Hwif'):
super().__init__() super().__init__()
self.top_node = top_node self.hwif = hwif
self.top_node = hwif.top_node
def get_typdef_name(self, node:'Node') -> str: def get_typdef_name(self, node:'Node') -> str:
base = node.get_rel_path( base = node.get_rel_path(
@@ -19,7 +21,10 @@ class InputStructGenerator_Hier(RDLFlatStructGenerator):
return f'{base}__in_t' return f'{base}__in_t'
def enter_Signal(self, node: 'SignalNode') -> None: 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: def enter_Field(self, node: 'FieldNode') -> None:
type_name = self.get_typdef_name(node) type_name = self.get_typdef_name(node)

View File

@@ -1,16 +1,18 @@
// TODO: Add a banner // TODO: Add a banner
module {{module_name}} ( module {{module_name}} (
input wire clk, input wire clk,
{%- for signal in reset_signals %} input wire rst,
{{signal.port_declaration}},
{%- endfor %}
{%- for signal in user_signals %} {%- for signal in user_out_of_hier_signals %}
{{signal.port_declaration}}, {%- if signal.width == 1 %}
input wire {{signal.inst_name}},
{%- else %}
input wire [{{signal.width-1}}:0] {{signal.inst_name}},
{%- endif %}
{%- endfor %} {%- endfor %}
{%- for interrupt in interrupts %} {%- for interrupt in interrupts %}
{{interrupt.port_declaration}}, // TODO:
{%- endfor %} {%- endfor %}
{{cpuif.port_declaration|indent(8)}} {{cpuif.port_declaration|indent(8)}}
@@ -77,7 +79,7 @@ module {{module_name}} (
{% if retime_read_response %} {% if retime_read_response %}
always_ff {{get_always_ff_event(cpuif.reset)}} begin 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_ack <= '0;
cpuif_rd_data <= '0; cpuif_rd_data <= '0;
cpuif_rd_err <= '0; cpuif_rd_err <= '0;

View File

@@ -30,7 +30,7 @@ class Readback:
context = { context = {
"array_assignments" : array_assignments, "array_assignments" : array_assignments,
"array_size" : array_size, "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, "cpuif": self.exp.cpuif,
"do_fanin_stage": self.do_fanin_stage, "do_fanin_stage": self.do_fanin_stage,
} }

View File

@@ -1,10 +1,11 @@
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from collections import OrderedDict
from systemrdl.walker import RDLListener from systemrdl.walker import RDLListener, RDLWalker
from systemrdl.node import AddrmapNode from systemrdl.node import AddrmapNode, SignalNode
if TYPE_CHECKING: if TYPE_CHECKING:
from systemrdl.node import Node, RegNode, SignalNode, MemNode from systemrdl.node import Node, RegNode, MemNode, FieldNode
from .exporter import RegblockExporter from .exporter import RegblockExporter
@@ -20,13 +21,45 @@ class DesignScanner(RDLListener):
self.cpuif_data_width = 0 self.cpuif_data_width = 0
self.msg = exp.top_node.env.msg 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: def enter_Reg(self, node: 'RegNode') -> None:
# The CPUIF's bus width is sized according to the largest register in the design # 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')) 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: def enter_Component(self, node: 'Node') -> None:
if not isinstance(node, AddrmapNode) and node.external: if not isinstance(node, AddrmapNode) and node.external:
self.msg.error( self.msg.error(
@@ -46,6 +79,21 @@ class DesignScanner(RDLListener):
node.inst.inst_src_ref 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: def enter_Mem(self, node: 'MemNode') -> None:
self.msg.error( self.msg.error(
"Cannot export a register block that contains a memory", "Cannot export a register block that contains a memory",

View File

@@ -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

View File

@@ -2,9 +2,9 @@ import re
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
if TYPE_CHECKING: if TYPE_CHECKING:
from systemrdl.node import Node from systemrdl.node import Node, SignalNode
from .signals import SignalBase
from typing import Optional from typing import Optional
from .dereferencer import Dereferencer
def get_indexed_path(top_node: 'Node', target_node: 'Node') -> str: 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) 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: if resetsignal is None:
return "@(posedge clk)" return "@(posedge clk)"
if resetsignal.is_async and resetsignal.is_activehigh: if resetsignal.get_property('async') and resetsignal.get_property('activehigh'):
return f"@(posedge clk or posedge {resetsignal.identifier})" return f"@(posedge clk or posedge {dereferencer.get_value(resetsignal)})"
elif resetsignal.is_async and not resetsignal.is_activehigh: elif resetsignal.get_property('async') and not resetsignal.get_property('activehigh'):
return f"@(posedge clk or negedge {resetsignal.identifier})" return f"@(posedge clk or negedge {dereferencer.get_value(resetsignal)})"
return "@(posedge clk)" return "@(posedge clk)"
def clog2(n: int) -> int: def clog2(n: int) -> int:

View File

@@ -6,7 +6,7 @@ module tb;
logic rst = '1; logic rst = '1;
logic clk = '0; logic clk = '0;
initial forever begin initial forever begin
#10ns; #5ns;
clk = ~clk; clk = ~clk;
end end

View File

View File

@@ -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;
};

View File

@@ -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 %}

View File

@@ -0,0 +1,5 @@
from ..lib.regblock_testcase import RegblockTestCase
class Test(RegblockTestCase):
def test_dut(self):
self.run_test()