Refactor exporter class to clean up the mess of random variables
This commit is contained in:
@@ -19,7 +19,7 @@ class AddressDecode:
|
||||
|
||||
@property
|
||||
def top_node(self) -> 'AddrmapNode':
|
||||
return self.exp.top_node
|
||||
return self.exp.ds.top_node
|
||||
|
||||
def get_strobe_struct(self) -> str:
|
||||
struct_gen = DecodeStructGenerator()
|
||||
|
||||
@@ -12,7 +12,7 @@ class AXI4Lite_Cpuif(CpuifBase):
|
||||
|
||||
@property
|
||||
def regblock_latency(self) -> int:
|
||||
return max(self.exp.min_read_latency, self.exp.min_write_latency)
|
||||
return max(self.exp.ds.min_read_latency, self.exp.ds.min_write_latency)
|
||||
|
||||
@property
|
||||
def max_outstanding(self) -> int:
|
||||
|
||||
@@ -14,11 +14,17 @@ class CpuifBase:
|
||||
# Path is relative to the location of the class that assigns this variable
|
||||
template_path = ""
|
||||
|
||||
def __init__(self, exp:'RegblockExporter', data_width:int=32, addr_width:int=32):
|
||||
def __init__(self, exp:'RegblockExporter'):
|
||||
self.exp = exp
|
||||
self.reset = exp.top_node.cpuif_reset
|
||||
self.data_width = data_width
|
||||
self.addr_width = addr_width
|
||||
self.reset = exp.ds.top_node.cpuif_reset
|
||||
|
||||
@property
|
||||
def addr_width(self) -> int:
|
||||
return self.exp.ds.addr_width
|
||||
|
||||
@property
|
||||
def data_width(self) -> int:
|
||||
return self.exp.ds.cpuif_data_width
|
||||
|
||||
@property
|
||||
def data_width_bytes(self) -> int:
|
||||
|
||||
@@ -30,7 +30,7 @@ class Dereferencer:
|
||||
|
||||
@property
|
||||
def top_node(self) -> AddrmapNode:
|
||||
return self.exp.top_node
|
||||
return self.exp.ds.top_node
|
||||
|
||||
def get_value(self, obj: Union[int, FieldNode, SignalNode, PropertyReference]) -> str:
|
||||
"""
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import os
|
||||
from typing import Union, Any, Type, Optional
|
||||
from typing import TYPE_CHECKING, Union, Any, Type, Optional, Set, List
|
||||
from collections import OrderedDict
|
||||
|
||||
import jinja2 as jj
|
||||
from systemrdl.node import AddrmapNode, RootNode
|
||||
@@ -19,14 +20,16 @@ from .write_buffering import WriteBuffering
|
||||
from .read_buffering import ReadBuffering
|
||||
from .external_acks import ExternalWriteAckGenerator, ExternalReadAckGenerator
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from systemrdl.node import SignalNode
|
||||
from systemrdl.rdltypes import UserEnum
|
||||
|
||||
class RegblockExporter:
|
||||
def __init__(self, **kwargs: Any) -> None:
|
||||
# Check for stray kwargs
|
||||
if kwargs:
|
||||
raise TypeError(f"got an unexpected keyword argument '{list(kwargs.keys())[0]}'")
|
||||
|
||||
|
||||
self.top_node = None # type: AddrmapNode
|
||||
self.hwif = None # type: Hwif
|
||||
self.cpuif = None # type: CpuifBase
|
||||
self.address_decode = None # type: AddressDecode
|
||||
@@ -35,8 +38,7 @@ class RegblockExporter:
|
||||
self.write_buffering = None # type: WriteBuffering
|
||||
self.read_buffering = None # type: ReadBuffering
|
||||
self.dereferencer = None # type: Dereferencer
|
||||
self.min_read_latency = 0
|
||||
self.min_write_latency = 0
|
||||
self.ds = None # type: DesignState
|
||||
|
||||
loader = jj.ChoiceLoader([
|
||||
jj.FileSystemLoader(os.path.dirname(__file__)),
|
||||
@@ -114,83 +116,37 @@ class RegblockExporter:
|
||||
"""
|
||||
# If it is the root node, skip to top addrmap
|
||||
if isinstance(node, RootNode):
|
||||
self.top_node = node.top
|
||||
top_node = node.top
|
||||
else:
|
||||
self.top_node = node
|
||||
msg = self.top_node.env.msg
|
||||
top_node = node
|
||||
|
||||
self.ds = DesignState(top_node, kwargs)
|
||||
|
||||
cpuif_cls = kwargs.pop("cpuif_cls", None) or APB4_Cpuif # type: Type[CpuifBase]
|
||||
module_name = kwargs.pop("module_name", None) or kwf(self.top_node.inst_name) # type: str
|
||||
package_name = kwargs.pop("package_name", None) or (module_name + "_pkg") # type: str
|
||||
reuse_hwif_typedefs = kwargs.pop("reuse_hwif_typedefs", True) # type: bool
|
||||
generate_hwif_report = kwargs.pop("generate_hwif_report", False) # type: bool
|
||||
user_addr_width = kwargs.pop("address_width", None) # type: Optional[int]
|
||||
|
||||
# Pipelining options
|
||||
retime_read_fanin = kwargs.pop("retime_read_fanin", False) # type: bool
|
||||
retime_read_response = kwargs.pop("retime_read_response", False) # type: bool
|
||||
retime_external_reg = kwargs.pop("retime_external_reg", False) # type: bool
|
||||
retime_external_regfile = kwargs.pop("retime_external_regfile", False) # type: bool
|
||||
retime_external_mem = kwargs.pop("retime_external_mem", False) # type: bool
|
||||
retime_external_addrmap = kwargs.pop("retime_external_addrmap", False) # type: bool
|
||||
|
||||
# Check for stray kwargs
|
||||
if kwargs:
|
||||
raise TypeError(f"got an unexpected keyword argument '{list(kwargs.keys())[0]}'")
|
||||
|
||||
self.min_read_latency = 0
|
||||
self.min_write_latency = 0
|
||||
if retime_read_fanin:
|
||||
self.min_read_latency += 1
|
||||
if retime_read_response:
|
||||
self.min_read_latency += 1
|
||||
|
||||
addr_width = self.top_node.size.bit_length()
|
||||
if user_addr_width is not None:
|
||||
if user_addr_width < addr_width:
|
||||
msg.fatal(f"User-specified address width shall be greater than or equal to {addr_width}.")
|
||||
addr_width = user_addr_width
|
||||
|
||||
# Scan the design for pre-export information
|
||||
scanner = DesignScanner(self)
|
||||
scanner.do_scan()
|
||||
DesignScanner(self).do_scan()
|
||||
|
||||
if generate_hwif_report:
|
||||
path = os.path.join(output_dir, f"{module_name}_hwif.rpt")
|
||||
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
|
||||
else:
|
||||
hwif_report_file = None
|
||||
|
||||
# Construct exporter components
|
||||
self.cpuif = cpuif_cls(
|
||||
self,
|
||||
data_width=scanner.cpuif_data_width,
|
||||
addr_width=addr_width
|
||||
)
|
||||
self.cpuif = cpuif_cls(self)
|
||||
self.hwif = Hwif(
|
||||
self,
|
||||
package_name=package_name,
|
||||
in_hier_signal_paths=scanner.in_hier_signal_paths,
|
||||
out_of_hier_signals=scanner.out_of_hier_signals,
|
||||
user_enums=scanner.user_enums,
|
||||
reuse_typedefs=reuse_hwif_typedefs,
|
||||
hwif_report_file=hwif_report_file,
|
||||
data_width=scanner.cpuif_data_width,
|
||||
)
|
||||
self.readback = Readback(
|
||||
self,
|
||||
retime_read_fanin,
|
||||
scanner.has_external_addressable
|
||||
)
|
||||
self.readback = Readback(self)
|
||||
self.address_decode = AddressDecode(self)
|
||||
self.field_logic = FieldLogic(
|
||||
self,
|
||||
retime_external_reg=retime_external_reg,
|
||||
retime_external_regfile=retime_external_regfile,
|
||||
retime_external_mem=retime_external_mem,
|
||||
retime_external_addrmap=retime_external_addrmap,
|
||||
)
|
||||
self.field_logic = FieldLogic(self)
|
||||
self.write_buffering = WriteBuffering(self)
|
||||
self.read_buffering = ReadBuffering(self)
|
||||
self.dereferencer = Dereferencer(self)
|
||||
@@ -198,18 +154,10 @@ class RegblockExporter:
|
||||
ext_read_acks = ExternalReadAckGenerator(self)
|
||||
|
||||
# Validate that there are no unsupported constructs
|
||||
validator = DesignValidator(self)
|
||||
validator.do_validate()
|
||||
DesignValidator(self).do_validate()
|
||||
|
||||
# Build Jinja template context
|
||||
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,
|
||||
"has_buffered_write_regs": scanner.has_buffered_write_regs,
|
||||
"has_buffered_read_regs": scanner.has_buffered_read_regs,
|
||||
"has_external_addressable": scanner.has_external_addressable,
|
||||
"has_external_block": scanner.has_external_block,
|
||||
"cpuif": self.cpuif,
|
||||
"hwif": self.hwif,
|
||||
"write_buffering": self.write_buffering,
|
||||
@@ -221,24 +169,82 @@ class RegblockExporter:
|
||||
"ext_write_acks": ext_write_acks,
|
||||
"ext_read_acks": ext_read_acks,
|
||||
"get_always_ff_event": self.dereferencer.get_always_ff_event,
|
||||
"retime_read_response": retime_read_response,
|
||||
"retime_read_fanin": retime_read_fanin,
|
||||
"min_read_latency": self.min_read_latency,
|
||||
"min_write_latency": self.min_write_latency,
|
||||
"ds": self.ds,
|
||||
"kwf": kwf,
|
||||
}
|
||||
|
||||
# Write out design
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
package_file_path = os.path.join(output_dir, package_name + ".sv")
|
||||
package_file_path = os.path.join(output_dir, self.ds.package_name + ".sv")
|
||||
template = self.jj_env.get_template("package_tmpl.sv")
|
||||
stream = template.stream(context)
|
||||
stream.dump(package_file_path)
|
||||
|
||||
module_file_path = os.path.join(output_dir, module_name + ".sv")
|
||||
module_file_path = os.path.join(output_dir, self.ds.module_name + ".sv")
|
||||
template = self.jj_env.get_template("module_tmpl.sv")
|
||||
stream = template.stream(context)
|
||||
stream.dump(module_file_path)
|
||||
|
||||
if hwif_report_file:
|
||||
hwif_report_file.close()
|
||||
|
||||
|
||||
class DesignState:
|
||||
"""
|
||||
Dumping ground for all sorts of variables that are relevant to a particular
|
||||
design.
|
||||
"""
|
||||
|
||||
def __init__(self, top_node: AddrmapNode, kwargs: Any) -> None:
|
||||
self.top_node = top_node
|
||||
msg = top_node.env.msg
|
||||
|
||||
#------------------------
|
||||
# Extract compiler args
|
||||
#------------------------
|
||||
self.reuse_hwif_typedefs = kwargs.pop("reuse_hwif_typedefs", True) # type: bool
|
||||
self.module_name = kwargs.pop("module_name", None) or kwf(self.top_node.inst_name) # type: str
|
||||
self.package_name = kwargs.pop("package_name", None) or (self.module_name + "_pkg") # type: str
|
||||
user_addr_width = kwargs.pop("address_width", None) # type: Optional[int]
|
||||
|
||||
|
||||
# Pipelining options
|
||||
self.retime_read_fanin = kwargs.pop("retime_read_fanin", False) # type: bool
|
||||
self.retime_read_response = kwargs.pop("retime_read_response", False) # type: bool
|
||||
self.retime_external_reg = kwargs.pop("retime_external_reg", False) # type: bool
|
||||
self.retime_external_regfile = kwargs.pop("retime_external_regfile", False) # type: bool
|
||||
self.retime_external_mem = kwargs.pop("retime_external_mem", False) # type: bool
|
||||
self.retime_external_addrmap = kwargs.pop("retime_external_addrmap", False) # type: bool
|
||||
|
||||
#------------------------
|
||||
# Info about the design
|
||||
#------------------------
|
||||
self.min_read_latency = 0
|
||||
self.min_write_latency = 0
|
||||
self.cpuif_data_width = 0
|
||||
|
||||
# Collections of signals that were actually referenced by the design
|
||||
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
|
||||
self.has_buffered_write_regs = False
|
||||
self.has_buffered_read_regs = False
|
||||
|
||||
self.has_external_block = False
|
||||
self.has_external_addressable = False
|
||||
|
||||
# Track any referenced enums
|
||||
self.user_enums = [] # type: List[Type[UserEnum]]
|
||||
|
||||
#------------------------
|
||||
if self.retime_read_fanin:
|
||||
self.min_read_latency += 1
|
||||
if self.retime_read_response:
|
||||
self.min_read_latency += 1
|
||||
|
||||
self.addr_width = self.top_node.size.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}.")
|
||||
self.addr_width = user_addr_width
|
||||
|
||||
@@ -15,7 +15,7 @@ class ExternalWriteAckGenerator(RDLForLoopGenerator):
|
||||
self.exp = exp
|
||||
|
||||
def get_implementation(self) -> str:
|
||||
content = self.get_content(self.exp.top_node)
|
||||
content = self.get_content(self.exp.ds.top_node)
|
||||
if content is None:
|
||||
return ""
|
||||
return content
|
||||
@@ -36,7 +36,7 @@ class ExternalReadAckGenerator(RDLForLoopGenerator):
|
||||
self.exp = exp
|
||||
|
||||
def get_implementation(self) -> str:
|
||||
content = self.get_content(self.exp.top_node)
|
||||
content = self.get_content(self.exp.ds.top_node)
|
||||
if content is None:
|
||||
return ""
|
||||
return content
|
||||
|
||||
@@ -17,31 +17,24 @@ from .generators import CombinationalStructGenerator, FieldStorageStructGenerato
|
||||
if TYPE_CHECKING:
|
||||
from typing import Dict, List
|
||||
from systemrdl.node import AddrmapNode, FieldNode
|
||||
from ..exporter import RegblockExporter
|
||||
from ..exporter import RegblockExporter, DesignState
|
||||
|
||||
class FieldLogic:
|
||||
def __init__(
|
||||
self,
|
||||
exp:'RegblockExporter',
|
||||
retime_external_reg: bool,
|
||||
retime_external_regfile: bool,
|
||||
retime_external_mem: bool,
|
||||
retime_external_addrmap: bool,
|
||||
):
|
||||
def __init__(self, exp:'RegblockExporter'):
|
||||
self.exp = exp
|
||||
self.retime_external_reg = retime_external_reg
|
||||
self.retime_external_regfile = retime_external_regfile
|
||||
self.retime_external_mem = retime_external_mem
|
||||
self.retime_external_addrmap = retime_external_addrmap
|
||||
|
||||
self._hw_conditionals = {} # type: Dict[int, List[NextStateConditional]]
|
||||
self._sw_conditionals = {} # type: Dict[int, List[NextStateConditional]]
|
||||
|
||||
self.init_conditionals()
|
||||
|
||||
@property
|
||||
def ds(self) -> 'DesignState':
|
||||
return self.exp.ds
|
||||
|
||||
@property
|
||||
def top_node(self) -> 'AddrmapNode':
|
||||
return self.exp.top_node
|
||||
return self.exp.ds.top_node
|
||||
|
||||
def get_storage_struct(self) -> str:
|
||||
struct_gen = FieldStorageStructGenerator(self)
|
||||
|
||||
@@ -77,7 +77,7 @@ class NextStateConditional:
|
||||
raise NotImplementedError
|
||||
|
||||
def get_field_path(self, field:'FieldNode') -> str:
|
||||
return get_indexed_path(self.exp.top_node, field)
|
||||
return get_indexed_path(self.exp.ds.top_node, field)
|
||||
|
||||
def get_predicate(self, field: 'FieldNode') -> str:
|
||||
"""
|
||||
|
||||
@@ -101,6 +101,7 @@ class FieldLogicGenerator(RDLForLoopGenerator):
|
||||
super().__init__()
|
||||
self.field_logic = field_logic
|
||||
self.exp = field_logic.exp
|
||||
self.ds = self.exp.ds
|
||||
self.field_storage_template = self.exp.jj_env.get_template(
|
||||
"field_logic/templates/field_storage.sv"
|
||||
)
|
||||
@@ -321,7 +322,7 @@ class FieldLogicGenerator(RDLForLoopGenerator):
|
||||
|
||||
|
||||
def assign_external_reg_outputs(self, node: 'RegNode') -> None:
|
||||
prefix = "hwif_out." + get_indexed_path(self.exp.top_node, node)
|
||||
prefix = "hwif_out." + get_indexed_path(self.exp.ds.top_node, node)
|
||||
strb = self.exp.dereferencer.get_access_strobe(node)
|
||||
|
||||
width = min(self.exp.cpuif.data_width, node.get_property('regwidth'))
|
||||
@@ -334,25 +335,25 @@ class FieldLogicGenerator(RDLForLoopGenerator):
|
||||
"prefix": prefix,
|
||||
"strb": strb,
|
||||
"bslice": bslice,
|
||||
"retime": self.field_logic.retime_external_reg,
|
||||
"retime": self.ds.retime_external_reg,
|
||||
'get_always_ff_event': self.exp.dereferencer.get_always_ff_event,
|
||||
"get_resetsignal": self.exp.dereferencer.get_resetsignal,
|
||||
"resetsignal": self.exp.top_node.cpuif_reset,
|
||||
"resetsignal": self.exp.ds.top_node.cpuif_reset,
|
||||
}
|
||||
self.add_content(self.external_reg_template.render(context))
|
||||
|
||||
def assign_external_block_outputs(self, node: 'AddressableNode') -> None:
|
||||
prefix = "hwif_out." + get_indexed_path(self.exp.top_node, node)
|
||||
prefix = "hwif_out." + get_indexed_path(self.exp.ds.top_node, node)
|
||||
strb = self.exp.dereferencer.get_external_block_access_strobe(node)
|
||||
addr_width = node.size.bit_length()
|
||||
|
||||
retime = False
|
||||
if isinstance(node, RegfileNode):
|
||||
retime = self.field_logic.retime_external_regfile
|
||||
retime = self.ds.retime_external_regfile
|
||||
elif isinstance(node, MemNode):
|
||||
retime = self.field_logic.retime_external_mem
|
||||
retime = self.ds.retime_external_mem
|
||||
elif isinstance(node, AddrmapNode):
|
||||
retime = self.field_logic.retime_external_addrmap
|
||||
retime = self.ds.retime_external_addrmap
|
||||
|
||||
context = {
|
||||
"prefix": prefix,
|
||||
@@ -361,6 +362,6 @@ class FieldLogicGenerator(RDLForLoopGenerator):
|
||||
"retime": retime,
|
||||
'get_always_ff_event': self.exp.dereferencer.get_always_ff_event,
|
||||
"get_resetsignal": self.exp.dereferencer.get_resetsignal,
|
||||
"resetsignal": self.exp.top_node.cpuif_reset,
|
||||
"resetsignal": self.exp.ds.top_node.cpuif_reset,
|
||||
}
|
||||
self.add_content(self.external_block_template.render(context))
|
||||
|
||||
@@ -11,7 +11,7 @@ from .generators import InputStructGenerator_TypeScope, OutputStructGenerator_Ty
|
||||
from .generators import EnumGenerator
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..exporter import RegblockExporter
|
||||
from ..exporter import RegblockExporter, DesignState
|
||||
|
||||
class Hwif:
|
||||
"""
|
||||
@@ -22,36 +22,30 @@ class Hwif:
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, exp: 'RegblockExporter', package_name: str,
|
||||
user_enums: List[Type[UserEnum]],
|
||||
in_hier_signal_paths: Set[str], out_of_hier_signals: Dict[str, SignalNode],
|
||||
reuse_typedefs: bool, hwif_report_file: Optional[TextIO],
|
||||
data_width: int
|
||||
self, exp: 'RegblockExporter',
|
||||
hwif_report_file: Optional[TextIO]
|
||||
):
|
||||
self.exp = exp
|
||||
self.package_name = package_name
|
||||
|
||||
self.has_input_struct = False
|
||||
self.has_output_struct = False
|
||||
|
||||
self.in_hier_signal_paths = in_hier_signal_paths
|
||||
self.out_of_hier_signals = out_of_hier_signals
|
||||
self.user_enums = user_enums
|
||||
|
||||
self.hwif_report_file = hwif_report_file
|
||||
|
||||
self.data_width = data_width
|
||||
|
||||
if reuse_typedefs:
|
||||
if self.ds.reuse_hwif_typedefs:
|
||||
self._gen_in_cls = InputStructGenerator_TypeScope
|
||||
self._gen_out_cls = OutputStructGenerator_TypeScope
|
||||
else:
|
||||
self._gen_in_cls = InputStructGenerator_Hier
|
||||
self._gen_out_cls = OutputStructGenerator_Hier
|
||||
|
||||
@property
|
||||
def ds(self) -> 'DesignState':
|
||||
return self.exp.ds
|
||||
|
||||
@property
|
||||
def top_node(self) -> AddrmapNode:
|
||||
return self.exp.top_node
|
||||
return self.exp.ds.top_node
|
||||
|
||||
|
||||
def get_package_contents(self) -> str:
|
||||
@@ -83,9 +77,7 @@ class Hwif:
|
||||
self.has_output_struct = False
|
||||
|
||||
gen_enum = EnumGenerator()
|
||||
enums = gen_enum.get_enums(
|
||||
self.user_enums
|
||||
)
|
||||
enums = gen_enum.get_enums(self.ds.user_enums)
|
||||
if enums is not None:
|
||||
lines.append(enums)
|
||||
|
||||
@@ -105,10 +97,10 @@ class Hwif:
|
||||
lines = []
|
||||
if self.has_input_struct:
|
||||
type_name = f"{self.top_node.inst_name}__in_t"
|
||||
lines.append(f"input {self.package_name}::{type_name} hwif_in")
|
||||
lines.append(f"input {self.ds.package_name}::{type_name} hwif_in")
|
||||
if self.has_output_struct:
|
||||
type_name = f"{self.top_node.inst_name}__out_t"
|
||||
lines.append(f"output {self.package_name}::{type_name} hwif_out")
|
||||
lines.append(f"output {self.ds.package_name}::{type_name} hwif_out")
|
||||
|
||||
return ",\n".join(lines)
|
||||
|
||||
@@ -156,7 +148,7 @@ class Hwif:
|
||||
path = get_indexed_path(self.top_node, obj)
|
||||
return "hwif_in." + path + ".next"
|
||||
elif isinstance(obj, SignalNode):
|
||||
if obj.get_path() in self.out_of_hier_signals:
|
||||
if obj.get_path() in self.ds.out_of_hier_signals:
|
||||
return kwf(obj.inst_name)
|
||||
path = get_indexed_path(self.top_node, obj)
|
||||
return "hwif_in." + path
|
||||
|
||||
@@ -63,12 +63,12 @@ class InputStructGenerator_Hier(HWIFStructGenerator):
|
||||
def enter_Signal(self, node: 'SignalNode') -> None:
|
||||
# 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:
|
||||
if path in self.hwif.ds.in_hier_signal_paths:
|
||||
self.add_member(kwf(node.inst_name), node.width)
|
||||
|
||||
def _add_external_block_members(self, node: 'AddressableNode') -> None:
|
||||
self.add_member("rd_ack")
|
||||
self.add_member("rd_data", self.hwif.data_width)
|
||||
self.add_member("rd_data", self.hwif.ds.cpuif_data_width)
|
||||
self.add_member("wr_ack")
|
||||
|
||||
def enter_Addrmap(self, node: 'AddrmapNode') -> None:
|
||||
@@ -95,7 +95,7 @@ class InputStructGenerator_Hier(HWIFStructGenerator):
|
||||
def enter_Reg(self, node: 'RegNode') -> Optional[WalkerAction]:
|
||||
super().enter_Reg(node)
|
||||
if node.external:
|
||||
width = min(self.hwif.data_width, node.get_property('regwidth'))
|
||||
width = min(self.hwif.ds.cpuif_data_width, node.get_property('regwidth'))
|
||||
self.add_member("rd_ack")
|
||||
self.add_member("rd_data", width)
|
||||
self.add_member("wr_ack")
|
||||
@@ -162,8 +162,8 @@ class OutputStructGenerator_Hier(HWIFStructGenerator):
|
||||
self.add_member("req")
|
||||
self.add_member("addr", (node.size - 1).bit_length())
|
||||
self.add_member("req_is_wr")
|
||||
self.add_member("wr_data", self.hwif.data_width)
|
||||
self.add_member("wr_biten", self.hwif.data_width)
|
||||
self.add_member("wr_data", self.hwif.ds.cpuif_data_width)
|
||||
self.add_member("wr_biten", self.hwif.ds.cpuif_data_width)
|
||||
|
||||
def enter_Addrmap(self, node: 'AddrmapNode') -> None:
|
||||
super().enter_Addrmap(node)
|
||||
@@ -189,7 +189,7 @@ class OutputStructGenerator_Hier(HWIFStructGenerator):
|
||||
def enter_Reg(self, node: 'RegNode') -> Optional[WalkerAction]:
|
||||
super().enter_Reg(node)
|
||||
if node.external:
|
||||
width = min(self.hwif.data_width, node.get_property('regwidth'))
|
||||
width = min(self.hwif.ds.cpuif_data_width, node.get_property('regwidth'))
|
||||
n_subwords = node.get_property("regwidth") // node.get_property("accesswidth")
|
||||
self.add_member("req", n_subwords)
|
||||
self.add_member("req_is_wr")
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// Generated by PeakRDL-regblock - A free and open-source SystemVerilog generator
|
||||
// https://github.com/SystemRDL/PeakRDL-regblock
|
||||
|
||||
module {{module_name}} (
|
||||
module {{ds.module_name}} (
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
{%- for signal in user_out_of_hier_signals %}
|
||||
{%- for signal in ds.out_of_hier_signals.values() %}
|
||||
{%- if signal.width == 1 %}
|
||||
input wire {{kwf(signal.inst_name)}},
|
||||
{%- else %}
|
||||
@@ -40,7 +40,7 @@ module {{module_name}} (
|
||||
{{cpuif.get_implementation()|indent}}
|
||||
|
||||
logic cpuif_req_masked;
|
||||
{%- if has_external_addressable %}
|
||||
{%- if ds.has_external_addressable %}
|
||||
logic external_req;
|
||||
logic external_pending;
|
||||
logic external_wr_ack;
|
||||
@@ -54,9 +54,9 @@ module {{module_name}} (
|
||||
end
|
||||
end
|
||||
{%- endif %}
|
||||
{% if min_read_latency == min_write_latency %}
|
||||
{% if ds.min_read_latency == ds.min_write_latency %}
|
||||
// Read & write latencies are balanced. Stalls not required
|
||||
{%- if has_external_addressable %}
|
||||
{%- if ds.has_external_addressable %}
|
||||
// except if external
|
||||
assign cpuif_req_stall_rd = external_pending;
|
||||
assign cpuif_req_stall_wr = external_pending;
|
||||
@@ -64,9 +64,9 @@ module {{module_name}} (
|
||||
assign cpuif_req_stall_rd = '0;
|
||||
assign cpuif_req_stall_wr = '0;
|
||||
{%- endif %}
|
||||
{%- elif min_read_latency > min_write_latency %}
|
||||
{%- elif ds.min_read_latency > ds.min_write_latency %}
|
||||
// Read latency > write latency. May need to delay next write that follows a read
|
||||
logic [{{min_read_latency - min_write_latency - 1}}:0] cpuif_req_stall_sr;
|
||||
logic [{{ds.min_read_latency - ds.min_write_latency - 1}}:0] cpuif_req_stall_sr;
|
||||
always_ff {{get_always_ff_event(cpuif.reset)}} begin
|
||||
if({{get_resetsignal(cpuif.reset)}}) begin
|
||||
cpuif_req_stall_sr <= '0;
|
||||
@@ -76,7 +76,7 @@ module {{module_name}} (
|
||||
cpuif_req_stall_sr <= (cpuif_req_stall_sr >> 'd1);
|
||||
end
|
||||
end
|
||||
{%- if has_external_addressable %}
|
||||
{%- if ds.has_external_addressable %}
|
||||
assign cpuif_req_stall_rd = external_pending;
|
||||
assign cpuif_req_stall_wr = cpuif_req_stall_sr[0] | external_pending;
|
||||
{%- else %}
|
||||
@@ -85,7 +85,7 @@ module {{module_name}} (
|
||||
{%- endif %}
|
||||
{%- else %}
|
||||
// Write latency > read latency. May need to delay next read that follows a write
|
||||
logic [{{min_write_latency - min_read_latency - 1}}:0] cpuif_req_stall_sr;
|
||||
logic [{{ds.min_write_latency - ds.min_read_latency - 1}}:0] cpuif_req_stall_sr;
|
||||
always_ff {{get_always_ff_event(cpuif.reset)}} begin
|
||||
if({{get_resetsignal(cpuif.reset)}}) begin
|
||||
cpuif_req_stall_sr <= '0;
|
||||
@@ -95,7 +95,7 @@ module {{module_name}} (
|
||||
cpuif_req_stall_sr <= (cpuif_req_stall_sr >> 'd1);
|
||||
end
|
||||
end
|
||||
{%- if has_external_addressable %}
|
||||
{%- if ds.has_external_addressable %}
|
||||
assign cpuif_req_stall_rd = cpuif_req_stall_sr[0] | external_pending;
|
||||
assign cpuif_req_stall_wr = external_pending;
|
||||
{%- else %}
|
||||
@@ -112,10 +112,10 @@ module {{module_name}} (
|
||||
//--------------------------------------------------------------------------
|
||||
{{address_decode.get_strobe_struct()|indent}}
|
||||
decoded_reg_strb_t decoded_reg_strb;
|
||||
{%- if has_external_addressable %}
|
||||
{%- if ds.has_external_addressable %}
|
||||
logic decoded_strb_is_external;
|
||||
{% endif %}
|
||||
{%- if has_external_block %}
|
||||
{%- if ds.has_external_block %}
|
||||
logic [{{cpuif.addr_width-1}}:0] decoded_addr;
|
||||
{% endif %}
|
||||
logic decoded_req;
|
||||
@@ -124,25 +124,25 @@ module {{module_name}} (
|
||||
logic [{{cpuif.data_width-1}}:0] decoded_wr_biten;
|
||||
|
||||
always_comb begin
|
||||
{%- if has_external_addressable %}
|
||||
{%- if ds.has_external_addressable %}
|
||||
automatic logic is_external = '0;
|
||||
{% endif %}
|
||||
{{address_decode.get_implementation()|indent(8)}}
|
||||
{%- if has_external_addressable %}
|
||||
{%- if ds.has_external_addressable %}
|
||||
decoded_strb_is_external = is_external;
|
||||
external_req = is_external;
|
||||
{% endif %}
|
||||
end
|
||||
|
||||
// Pass down signals to next stage
|
||||
{%- if has_external_block %}
|
||||
{%- if ds.has_external_block %}
|
||||
assign decoded_addr = cpuif_addr;
|
||||
{% endif %}
|
||||
assign decoded_req = cpuif_req_masked;
|
||||
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 %}
|
||||
{% if ds.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;
|
||||
@@ -150,7 +150,7 @@ module {{module_name}} (
|
||||
assign decoded_wr_biten_bswap = {<<{decoded_wr_biten}};
|
||||
{%- endif %}
|
||||
|
||||
{%- if has_buffered_write_regs %}
|
||||
{%- if ds.has_buffered_write_regs %}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Write double-buffers
|
||||
@@ -168,7 +168,7 @@ module {{module_name}} (
|
||||
|
||||
{{field_logic.get_implementation()|indent}}
|
||||
|
||||
{%- if has_buffered_read_regs %}
|
||||
{%- if ds.has_buffered_read_regs %}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Read double-buffers
|
||||
@@ -181,7 +181,7 @@ module {{module_name}} (
|
||||
//--------------------------------------------------------------------------
|
||||
// Write response
|
||||
//--------------------------------------------------------------------------
|
||||
{%- if has_external_addressable %}
|
||||
{%- if ds.has_external_addressable %}
|
||||
always_comb begin
|
||||
automatic logic wr_ack;
|
||||
wr_ack = '0;
|
||||
@@ -198,7 +198,7 @@ module {{module_name}} (
|
||||
//--------------------------------------------------------------------------
|
||||
// Readback
|
||||
//--------------------------------------------------------------------------
|
||||
{%- if has_external_addressable %}
|
||||
{%- if ds.has_external_addressable %}
|
||||
logic readback_external_rd_ack_c;
|
||||
always_comb begin
|
||||
automatic logic rd_ack;
|
||||
@@ -208,7 +208,7 @@ module {{module_name}} (
|
||||
end
|
||||
|
||||
logic readback_external_rd_ack;
|
||||
{%- if retime_read_fanin %}
|
||||
{%- if ds.retime_read_fanin %}
|
||||
always_ff {{get_always_ff_event(cpuif.reset)}} begin
|
||||
if({{get_resetsignal(cpuif.reset)}}) begin
|
||||
readback_external_rd_ack <= '0;
|
||||
@@ -227,17 +227,17 @@ module {{module_name}} (
|
||||
logic readback_done;
|
||||
logic [{{cpuif.data_width-1}}:0] readback_data;
|
||||
{{readback.get_implementation()|indent}}
|
||||
{% if 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;
|
||||
cpuif_rd_data <= '0;
|
||||
cpuif_rd_err <= '0;
|
||||
{%- if has_external_addressable %}
|
||||
{%- if ds.has_external_addressable %}
|
||||
external_rd_ack <= '0;
|
||||
{%- endif %}
|
||||
end else begin
|
||||
{%- if has_external_addressable %}
|
||||
{%- if ds.has_external_addressable %}
|
||||
external_rd_ack <= readback_external_rd_ack;
|
||||
cpuif_rd_ack <= readback_done | readback_external_rd_ack;
|
||||
{%- else %}
|
||||
@@ -248,7 +248,7 @@ module {{module_name}} (
|
||||
end
|
||||
end
|
||||
{% else %}
|
||||
{%- if has_external_addressable %}
|
||||
{%- if ds.has_external_addressable %}
|
||||
assign external_rd_ack = readback_external_rd_ack;
|
||||
assign cpuif_rd_ack = readback_done | readback_external_rd_ack;
|
||||
{%- else %}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Generated by PeakRDL-regblock - A free and open-source SystemVerilog generator
|
||||
// https://github.com/SystemRDL/PeakRDL-regblock
|
||||
|
||||
package {{hwif.package_name}};
|
||||
package {{ds.package_name}};
|
||||
{{hwif.get_package_contents()|indent}}
|
||||
endpackage
|
||||
|
||||
@@ -16,7 +16,7 @@ class ReadBuffering:
|
||||
|
||||
@property
|
||||
def top_node(self) -> 'AddrmapNode':
|
||||
return self.exp.top_node
|
||||
return self.exp.ds.top_node
|
||||
|
||||
def get_storage_struct(self) -> str:
|
||||
struct_gen = RBufStorageStructGenerator()
|
||||
|
||||
@@ -4,18 +4,21 @@ import math
|
||||
from .generators import ReadbackAssignmentGenerator
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..exporter import RegblockExporter
|
||||
from ..exporter import RegblockExporter, DesignState
|
||||
from systemrdl.node import AddrmapNode
|
||||
|
||||
class Readback:
|
||||
def __init__(self, exp:'RegblockExporter', do_fanin_stage: bool, has_external_addressable: bool):
|
||||
def __init__(self, exp:'RegblockExporter'):
|
||||
self.exp = exp
|
||||
self.do_fanin_stage = do_fanin_stage
|
||||
self.has_external_addressable = has_external_addressable
|
||||
self.do_fanin_stage = self.ds.retime_read_fanin
|
||||
|
||||
@property
|
||||
def ds(self) -> 'DesignState':
|
||||
return self.exp.ds
|
||||
|
||||
@property
|
||||
def top_node(self) -> 'AddrmapNode':
|
||||
return self.exp.top_node
|
||||
return self.exp.ds.top_node
|
||||
|
||||
def get_implementation(self) -> str:
|
||||
gen = ReadbackAssignmentGenerator(self.exp)
|
||||
@@ -33,7 +36,7 @@ class Readback:
|
||||
'get_always_ff_event': self.exp.dereferencer.get_always_ff_event,
|
||||
"cpuif": self.exp.cpuif,
|
||||
"do_fanin_stage": self.do_fanin_stage,
|
||||
"has_external_addressable": self.has_external_addressable,
|
||||
"ds": self.ds,
|
||||
}
|
||||
|
||||
if self.do_fanin_stage:
|
||||
|
||||
@@ -35,7 +35,7 @@ always_ff @(posedge clk) begin
|
||||
readback_done_r <= '0;
|
||||
end else begin
|
||||
readback_array_r <= readback_array_c;
|
||||
{%- if has_external_addressable %}
|
||||
{%- if ds.has_external_addressable %}
|
||||
readback_done_r <= decoded_req & ~decoded_req_is_wr & ~decoded_strb_is_external;
|
||||
{%- else %}
|
||||
readback_done_r <= decoded_req & ~decoded_req_is_wr;
|
||||
@@ -58,7 +58,7 @@ end
|
||||
// Reduce the array
|
||||
always_comb begin
|
||||
automatic logic [{{cpuif.data_width-1}}:0] readback_data_var;
|
||||
{%- if has_external_addressable %}
|
||||
{%- if ds.has_external_addressable %}
|
||||
readback_done = decoded_req & ~decoded_req_is_wr & ~decoded_strb_is_external;
|
||||
{%- else %}
|
||||
readback_done = decoded_req & ~decoded_req_is_wr;
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
from typing import TYPE_CHECKING, Set, Optional, Type, List
|
||||
from collections import OrderedDict
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from systemrdl.walker import RDLListener, RDLWalker, WalkerAction
|
||||
from systemrdl.node import SignalNode, RegNode
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from systemrdl.node import Node, FieldNode, AddressableNode
|
||||
from systemrdl.node import Node, FieldNode, AddressableNode, AddrmapNode
|
||||
from .exporter import RegblockExporter
|
||||
from systemrdl.rdltypes import UserEnum
|
||||
|
||||
|
||||
class DesignScanner(RDLListener):
|
||||
@@ -19,63 +17,53 @@ class DesignScanner(RDLListener):
|
||||
"""
|
||||
def __init__(self, exp:'RegblockExporter') -> None:
|
||||
self.exp = exp
|
||||
self.cpuif_data_width = 0
|
||||
self.msg = exp.top_node.env.msg
|
||||
self.ds = exp.ds
|
||||
self.msg = self.top_node.env.msg
|
||||
|
||||
# Collections of signals that were actually referenced by the design
|
||||
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
|
||||
self.has_buffered_write_regs = False
|
||||
self.has_buffered_read_regs = False
|
||||
|
||||
self.has_external_block = False
|
||||
self.has_external_addressable = False
|
||||
|
||||
# Track any referenced enums
|
||||
self.user_enums = [] # type: List[Type[UserEnum]]
|
||||
@property
|
||||
def top_node(self) -> 'AddrmapNode':
|
||||
return self.exp.ds.top_node
|
||||
|
||||
def _get_out_of_hier_field_reset(self) -> None:
|
||||
current_node = self.exp.top_node.parent
|
||||
current_node = self.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
|
||||
self.ds.out_of_hier_signals[path] = signal
|
||||
return
|
||||
current_node = current_node.parent
|
||||
|
||||
def do_scan(self) -> None:
|
||||
# Collect cpuif reset, if any.
|
||||
cpuif_reset = self.exp.top_node.cpuif_reset
|
||||
cpuif_reset = self.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)
|
||||
rel_path = cpuif_reset.get_rel_path(self.top_node)
|
||||
if rel_path.startswith("^"):
|
||||
self.out_of_hier_signals[path] = cpuif_reset
|
||||
self.ds.out_of_hier_signals[path] = cpuif_reset
|
||||
else:
|
||||
self.in_hier_signal_paths.add(path)
|
||||
self.ds.in_hier_signal_paths.add(path)
|
||||
|
||||
# collect out-of-hier field_reset, if any
|
||||
self._get_out_of_hier_field_reset()
|
||||
|
||||
# Ensure addrmap is not a bridge. This concept does not make sense for
|
||||
# terminal components.
|
||||
if self.exp.top_node.get_property('bridge'):
|
||||
if self.top_node.get_property('bridge'):
|
||||
self.msg.error(
|
||||
"Regblock generator does not support exporting bridge address maps",
|
||||
self.exp.top_node.inst.property_src_ref.get('bridge', self.exp.top_node.inst.inst_src_ref)
|
||||
self.top_node.inst.property_src_ref.get('bridge', self.top_node.inst.inst_src_ref)
|
||||
)
|
||||
|
||||
RDLWalker().walk(self.exp.top_node, self)
|
||||
RDLWalker().walk(self.top_node, self)
|
||||
if self.msg.had_error:
|
||||
self.msg.fatal(
|
||||
"Unable to export due to previous errors"
|
||||
)
|
||||
|
||||
def enter_Component(self, node: 'Node') -> Optional[WalkerAction]:
|
||||
if node.external and (node != self.exp.top_node):
|
||||
if node.external and (node != self.top_node):
|
||||
# Do not inspect external components. None of my business
|
||||
return WalkerAction.SkipDescendants
|
||||
|
||||
@@ -84,37 +72,37 @@ class DesignScanner(RDLListener):
|
||||
value = node.get_property(prop_name)
|
||||
if isinstance(value, SignalNode):
|
||||
path = value.get_path()
|
||||
rel_path = value.get_rel_path(self.exp.top_node)
|
||||
rel_path = value.get_rel_path(self.top_node)
|
||||
if rel_path.startswith("^"):
|
||||
self.out_of_hier_signals[path] = value
|
||||
self.ds.out_of_hier_signals[path] = value
|
||||
else:
|
||||
self.in_hier_signal_paths.add(path)
|
||||
self.ds.in_hier_signal_paths.add(path)
|
||||
|
||||
if prop_name == "encode":
|
||||
if value not in self.user_enums:
|
||||
self.user_enums.append(value)
|
||||
if value not in self.ds.user_enums:
|
||||
self.ds.user_enums.append(value)
|
||||
|
||||
return WalkerAction.Continue
|
||||
|
||||
def enter_AddressableComponent(self, node: 'AddressableNode') -> None:
|
||||
if node.external and node != self.exp.top_node:
|
||||
self.has_external_addressable = True
|
||||
if node.external and node != self.top_node:
|
||||
self.ds.has_external_addressable = True
|
||||
if not isinstance(node, RegNode):
|
||||
self.has_external_block = True
|
||||
self.ds.has_external_block = True
|
||||
|
||||
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.cpuif_data_width = max(self.cpuif_data_width, accesswidth)
|
||||
self.exp.ds.cpuif_data_width = max(self.exp.ds.cpuif_data_width, accesswidth)
|
||||
|
||||
self.has_buffered_write_regs = self.has_buffered_write_regs or bool(node.get_property('buffer_writes'))
|
||||
self.has_buffered_read_regs = self.has_buffered_read_regs or bool(node.get_property('buffer_reads'))
|
||||
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'))
|
||||
|
||||
def enter_Signal(self, node: 'SignalNode') -> None:
|
||||
if node.get_property('field_reset'):
|
||||
path = node.get_path()
|
||||
self.in_hier_signal_paths.add(path)
|
||||
self.ds.in_hier_signal_paths.add(path)
|
||||
|
||||
def enter_Field(self, node: 'FieldNode') -> None:
|
||||
if node.is_sw_writable and (node.msb < node.lsb):
|
||||
self.has_writable_msb0_fields = True
|
||||
self.ds.has_writable_msb0_fields = True
|
||||
|
||||
@@ -19,20 +19,24 @@ class DesignValidator(RDLListener):
|
||||
"""
|
||||
def __init__(self, exp:'RegblockExporter') -> None:
|
||||
self.exp = exp
|
||||
self.msg = exp.top_node.env.msg
|
||||
self.msg = self.top_node.env.msg
|
||||
|
||||
self._contains_external_block_stack = [] # type: List[bool]
|
||||
self.contains_external_block = False
|
||||
|
||||
@property
|
||||
def top_node(self) -> 'AddrmapNode':
|
||||
return self.exp.ds.top_node
|
||||
|
||||
def do_validate(self) -> None:
|
||||
RDLWalker().walk(self.exp.top_node, self)
|
||||
RDLWalker().walk(self.top_node, self)
|
||||
if self.msg.had_error:
|
||||
self.msg.fatal(
|
||||
"Unable to export due to previous errors"
|
||||
)
|
||||
|
||||
def enter_Component(self, node: 'Node') -> Optional[WalkerAction]:
|
||||
if node.external and (node != self.exp.top_node):
|
||||
if node.external and (node != self.top_node):
|
||||
# Do not inspect external components. None of my business
|
||||
return WalkerAction.SkipDescendants
|
||||
|
||||
@@ -40,7 +44,7 @@ class DesignValidator(RDLListener):
|
||||
for prop_name in node.list_properties():
|
||||
value = node.get_property(prop_name)
|
||||
if isinstance(value, (PropertyReference, Node)):
|
||||
if not ref_is_internal(self.exp.top_node, value):
|
||||
if not ref_is_internal(self.top_node, value):
|
||||
if isinstance(value, PropertyReference):
|
||||
src_ref = value.src_ref
|
||||
else:
|
||||
@@ -55,7 +59,7 @@ class DesignValidator(RDLListener):
|
||||
# If encountering a CPUIF reset that is nested within the register model,
|
||||
# warn that it will be ignored.
|
||||
# Only cpuif resets in the top-level node or above will be honored
|
||||
if node.get_property('cpuif_reset') and (node.parent != self.exp.top_node):
|
||||
if node.get_property('cpuif_reset') and (node.parent != self.top_node):
|
||||
self.msg.warning(
|
||||
"Only cpuif_reset signals that are instantiated in the top-level "
|
||||
"addrmap or above will be honored. Any cpuif_reset signals nested "
|
||||
@@ -81,7 +85,7 @@ class DesignValidator(RDLListener):
|
||||
|
||||
if not isinstance(node, RegNode):
|
||||
# Entering a block-like node
|
||||
if node == self.exp.top_node:
|
||||
if node == self.top_node:
|
||||
# Ignore top addrmap's external property when entering
|
||||
self._contains_external_block_stack.append(False)
|
||||
else:
|
||||
|
||||
@@ -16,7 +16,7 @@ class WriteBuffering:
|
||||
|
||||
@property
|
||||
def top_node(self) -> 'AddrmapNode':
|
||||
return self.exp.top_node
|
||||
return self.exp.ds.top_node
|
||||
|
||||
|
||||
def get_storage_struct(self) -> str:
|
||||
|
||||
Reference in New Issue
Block a user