Refactor exporter class to clean up the mess of random variables

This commit is contained in:
Alex Mykyta
2023-05-12 23:44:09 -07:00
parent 5b3cdd9d7a
commit 5e76956618
19 changed files with 210 additions and 217 deletions

View File

@@ -19,7 +19,7 @@ class AddressDecode:
@property @property
def top_node(self) -> 'AddrmapNode': def top_node(self) -> 'AddrmapNode':
return self.exp.top_node return self.exp.ds.top_node
def get_strobe_struct(self) -> str: def get_strobe_struct(self) -> str:
struct_gen = DecodeStructGenerator() struct_gen = DecodeStructGenerator()

View File

@@ -12,7 +12,7 @@ class AXI4Lite_Cpuif(CpuifBase):
@property @property
def regblock_latency(self) -> int: 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 @property
def max_outstanding(self) -> int: def max_outstanding(self) -> int:

View File

@@ -14,11 +14,17 @@ class CpuifBase:
# Path is relative to the location of the class that assigns this variable # Path is relative to the location of the class that assigns this variable
template_path = "" template_path = ""
def __init__(self, exp:'RegblockExporter', data_width:int=32, addr_width:int=32): def __init__(self, exp:'RegblockExporter'):
self.exp = exp self.exp = exp
self.reset = exp.top_node.cpuif_reset self.reset = exp.ds.top_node.cpuif_reset
self.data_width = data_width
self.addr_width = addr_width @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 @property
def data_width_bytes(self) -> int: def data_width_bytes(self) -> int:

View File

@@ -30,7 +30,7 @@ class Dereferencer:
@property @property
def top_node(self) -> AddrmapNode: 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: def get_value(self, obj: Union[int, FieldNode, SignalNode, PropertyReference]) -> str:
""" """

View File

@@ -1,5 +1,6 @@
import os 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 import jinja2 as jj
from systemrdl.node import AddrmapNode, RootNode from systemrdl.node import AddrmapNode, RootNode
@@ -19,14 +20,16 @@ from .write_buffering import WriteBuffering
from .read_buffering import ReadBuffering from .read_buffering import ReadBuffering
from .external_acks import ExternalWriteAckGenerator, ExternalReadAckGenerator from .external_acks import ExternalWriteAckGenerator, ExternalReadAckGenerator
if TYPE_CHECKING:
from systemrdl.node import SignalNode
from systemrdl.rdltypes import UserEnum
class RegblockExporter: class RegblockExporter:
def __init__(self, **kwargs: Any) -> None: def __init__(self, **kwargs: Any) -> None:
# Check for stray kwargs # Check for stray kwargs
if kwargs: if kwargs:
raise TypeError(f"got an unexpected keyword argument '{list(kwargs.keys())[0]}'") raise TypeError(f"got an unexpected keyword argument '{list(kwargs.keys())[0]}'")
self.top_node = None # type: AddrmapNode
self.hwif = None # type: Hwif self.hwif = None # type: Hwif
self.cpuif = None # type: CpuifBase self.cpuif = None # type: CpuifBase
self.address_decode = None # type: AddressDecode self.address_decode = None # type: AddressDecode
@@ -35,8 +38,7 @@ class RegblockExporter:
self.write_buffering = None # type: WriteBuffering self.write_buffering = None # type: WriteBuffering
self.read_buffering = None # type: ReadBuffering self.read_buffering = None # type: ReadBuffering
self.dereferencer = None # type: Dereferencer self.dereferencer = None # type: Dereferencer
self.min_read_latency = 0 self.ds = None # type: DesignState
self.min_write_latency = 0
loader = jj.ChoiceLoader([ loader = jj.ChoiceLoader([
jj.FileSystemLoader(os.path.dirname(__file__)), jj.FileSystemLoader(os.path.dirname(__file__)),
@@ -114,83 +116,37 @@ class RegblockExporter:
""" """
# If it is the root node, skip to top addrmap # If it is the root node, skip to top addrmap
if isinstance(node, RootNode): if isinstance(node, RootNode):
self.top_node = node.top top_node = node.top
else: else:
self.top_node = node top_node = node
msg = self.top_node.env.msg
self.ds = DesignState(top_node, kwargs)
cpuif_cls = kwargs.pop("cpuif_cls", None) or APB4_Cpuif # type: Type[CpuifBase] 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 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 # Check for stray kwargs
if kwargs: if kwargs:
raise TypeError(f"got an unexpected keyword argument '{list(kwargs.keys())[0]}'") 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 # Scan the design for pre-export information
scanner = DesignScanner(self) DesignScanner(self).do_scan()
scanner.do_scan()
if generate_hwif_report: 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 hwif_report_file = open(path, "w", encoding='utf-8') # pylint: disable=consider-using-with
else: else:
hwif_report_file = None hwif_report_file = None
# Construct exporter components # Construct exporter components
self.cpuif = cpuif_cls( self.cpuif = cpuif_cls(self)
self,
data_width=scanner.cpuif_data_width,
addr_width=addr_width
)
self.hwif = Hwif( self.hwif = Hwif(
self, 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, 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.address_decode = AddressDecode(self)
self.field_logic = FieldLogic( self.field_logic = FieldLogic(self)
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.write_buffering = WriteBuffering(self) self.write_buffering = WriteBuffering(self)
self.read_buffering = ReadBuffering(self) self.read_buffering = ReadBuffering(self)
self.dereferencer = Dereferencer(self) self.dereferencer = Dereferencer(self)
@@ -198,18 +154,10 @@ class RegblockExporter:
ext_read_acks = ExternalReadAckGenerator(self) ext_read_acks = ExternalReadAckGenerator(self)
# Validate that there are no unsupported constructs # Validate that there are no unsupported constructs
validator = DesignValidator(self) DesignValidator(self).do_validate()
validator.do_validate()
# Build Jinja template context # Build Jinja template context
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, "cpuif": self.cpuif,
"hwif": self.hwif, "hwif": self.hwif,
"write_buffering": self.write_buffering, "write_buffering": self.write_buffering,
@@ -221,24 +169,82 @@ class RegblockExporter:
"ext_write_acks": ext_write_acks, "ext_write_acks": ext_write_acks,
"ext_read_acks": ext_read_acks, "ext_read_acks": ext_read_acks,
"get_always_ff_event": self.dereferencer.get_always_ff_event, "get_always_ff_event": self.dereferencer.get_always_ff_event,
"retime_read_response": retime_read_response, "ds": self.ds,
"retime_read_fanin": retime_read_fanin,
"min_read_latency": self.min_read_latency,
"min_write_latency": self.min_write_latency,
"kwf": kwf, "kwf": kwf,
} }
# Write out design # Write out design
os.makedirs(output_dir, exist_ok=True) 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") template = self.jj_env.get_template("package_tmpl.sv")
stream = template.stream(context) stream = template.stream(context)
stream.dump(package_file_path) 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") template = self.jj_env.get_template("module_tmpl.sv")
stream = template.stream(context) stream = template.stream(context)
stream.dump(module_file_path) stream.dump(module_file_path)
if hwif_report_file: if hwif_report_file:
hwif_report_file.close() 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

View File

@@ -15,7 +15,7 @@ class ExternalWriteAckGenerator(RDLForLoopGenerator):
self.exp = exp self.exp = exp
def get_implementation(self) -> str: 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: if content is None:
return "" return ""
return content return content
@@ -36,7 +36,7 @@ class ExternalReadAckGenerator(RDLForLoopGenerator):
self.exp = exp self.exp = exp
def get_implementation(self) -> str: 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: if content is None:
return "" return ""
return content return content

View File

@@ -17,31 +17,24 @@ from .generators import CombinationalStructGenerator, FieldStorageStructGenerato
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Dict, List from typing import Dict, List
from systemrdl.node import AddrmapNode, FieldNode from systemrdl.node import AddrmapNode, FieldNode
from ..exporter import RegblockExporter from ..exporter import RegblockExporter, DesignState
class FieldLogic: class FieldLogic:
def __init__( def __init__(self, exp:'RegblockExporter'):
self,
exp:'RegblockExporter',
retime_external_reg: bool,
retime_external_regfile: bool,
retime_external_mem: bool,
retime_external_addrmap: bool,
):
self.exp = exp 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._hw_conditionals = {} # type: Dict[int, List[NextStateConditional]]
self._sw_conditionals = {} # type: Dict[int, List[NextStateConditional]] self._sw_conditionals = {} # type: Dict[int, List[NextStateConditional]]
self.init_conditionals() self.init_conditionals()
@property
def ds(self) -> 'DesignState':
return self.exp.ds
@property @property
def top_node(self) -> 'AddrmapNode': def top_node(self) -> 'AddrmapNode':
return self.exp.top_node return self.exp.ds.top_node
def get_storage_struct(self) -> str: def get_storage_struct(self) -> str:
struct_gen = FieldStorageStructGenerator(self) struct_gen = FieldStorageStructGenerator(self)

View File

@@ -77,7 +77,7 @@ class NextStateConditional:
raise NotImplementedError raise NotImplementedError
def get_field_path(self, field:'FieldNode') -> str: 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: def get_predicate(self, field: 'FieldNode') -> str:
""" """

View File

@@ -101,6 +101,7 @@ class FieldLogicGenerator(RDLForLoopGenerator):
super().__init__() super().__init__()
self.field_logic = field_logic self.field_logic = field_logic
self.exp = field_logic.exp self.exp = field_logic.exp
self.ds = self.exp.ds
self.field_storage_template = self.exp.jj_env.get_template( self.field_storage_template = self.exp.jj_env.get_template(
"field_logic/templates/field_storage.sv" "field_logic/templates/field_storage.sv"
) )
@@ -321,7 +322,7 @@ class FieldLogicGenerator(RDLForLoopGenerator):
def assign_external_reg_outputs(self, node: 'RegNode') -> None: 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) strb = self.exp.dereferencer.get_access_strobe(node)
width = min(self.exp.cpuif.data_width, node.get_property('regwidth')) width = min(self.exp.cpuif.data_width, node.get_property('regwidth'))
@@ -334,25 +335,25 @@ class FieldLogicGenerator(RDLForLoopGenerator):
"prefix": prefix, "prefix": prefix,
"strb": strb, "strb": strb,
"bslice": bslice, "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_always_ff_event': self.exp.dereferencer.get_always_ff_event,
"get_resetsignal": self.exp.dereferencer.get_resetsignal, "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)) self.add_content(self.external_reg_template.render(context))
def assign_external_block_outputs(self, node: 'AddressableNode') -> None: 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) strb = self.exp.dereferencer.get_external_block_access_strobe(node)
addr_width = node.size.bit_length() addr_width = node.size.bit_length()
retime = False retime = False
if isinstance(node, RegfileNode): if isinstance(node, RegfileNode):
retime = self.field_logic.retime_external_regfile retime = self.ds.retime_external_regfile
elif isinstance(node, MemNode): elif isinstance(node, MemNode):
retime = self.field_logic.retime_external_mem retime = self.ds.retime_external_mem
elif isinstance(node, AddrmapNode): elif isinstance(node, AddrmapNode):
retime = self.field_logic.retime_external_addrmap retime = self.ds.retime_external_addrmap
context = { context = {
"prefix": prefix, "prefix": prefix,
@@ -361,6 +362,6 @@ class FieldLogicGenerator(RDLForLoopGenerator):
"retime": retime, "retime": retime,
'get_always_ff_event': self.exp.dereferencer.get_always_ff_event, 'get_always_ff_event': self.exp.dereferencer.get_always_ff_event,
"get_resetsignal": self.exp.dereferencer.get_resetsignal, "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)) self.add_content(self.external_block_template.render(context))

View File

@@ -11,7 +11,7 @@ from .generators import InputStructGenerator_TypeScope, OutputStructGenerator_Ty
from .generators import EnumGenerator from .generators import EnumGenerator
if TYPE_CHECKING: if TYPE_CHECKING:
from ..exporter import RegblockExporter from ..exporter import RegblockExporter, DesignState
class Hwif: class Hwif:
""" """
@@ -22,36 +22,30 @@ class Hwif:
""" """
def __init__( def __init__(
self, exp: 'RegblockExporter', package_name: str, self, exp: 'RegblockExporter',
user_enums: List[Type[UserEnum]], hwif_report_file: Optional[TextIO]
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 = exp self.exp = exp
self.package_name = package_name
self.has_input_struct = False self.has_input_struct = False
self.has_output_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.hwif_report_file = hwif_report_file
self.data_width = data_width if self.ds.reuse_hwif_typedefs:
if reuse_typedefs:
self._gen_in_cls = InputStructGenerator_TypeScope self._gen_in_cls = InputStructGenerator_TypeScope
self._gen_out_cls = OutputStructGenerator_TypeScope self._gen_out_cls = OutputStructGenerator_TypeScope
else: else:
self._gen_in_cls = InputStructGenerator_Hier self._gen_in_cls = InputStructGenerator_Hier
self._gen_out_cls = OutputStructGenerator_Hier self._gen_out_cls = OutputStructGenerator_Hier
@property
def ds(self) -> 'DesignState':
return self.exp.ds
@property @property
def top_node(self) -> AddrmapNode: def top_node(self) -> AddrmapNode:
return self.exp.top_node return self.exp.ds.top_node
def get_package_contents(self) -> str: def get_package_contents(self) -> str:
@@ -83,9 +77,7 @@ class Hwif:
self.has_output_struct = False self.has_output_struct = False
gen_enum = EnumGenerator() gen_enum = EnumGenerator()
enums = gen_enum.get_enums( enums = gen_enum.get_enums(self.ds.user_enums)
self.user_enums
)
if enums is not None: if enums is not None:
lines.append(enums) lines.append(enums)
@@ -105,10 +97,10 @@ class Hwif:
lines = [] lines = []
if self.has_input_struct: if self.has_input_struct:
type_name = f"{self.top_node.inst_name}__in_t" 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: if self.has_output_struct:
type_name = f"{self.top_node.inst_name}__out_t" 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) return ",\n".join(lines)
@@ -156,7 +148,7 @@ class Hwif:
path = get_indexed_path(self.top_node, obj) path = get_indexed_path(self.top_node, obj)
return "hwif_in." + path + ".next" return "hwif_in." + path + ".next"
elif isinstance(obj, SignalNode): 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) return kwf(obj.inst_name)
path = get_indexed_path(self.top_node, obj) path = get_indexed_path(self.top_node, obj)
return "hwif_in." + path return "hwif_in." + path

View File

@@ -63,12 +63,12 @@ class InputStructGenerator_Hier(HWIFStructGenerator):
def enter_Signal(self, node: 'SignalNode') -> None: def enter_Signal(self, node: 'SignalNode') -> None:
# only emit the signal if design scanner detected it is actually being used # only emit the signal if design scanner detected it is actually being used
path = node.get_path() 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) self.add_member(kwf(node.inst_name), node.width)
def _add_external_block_members(self, node: 'AddressableNode') -> None: def _add_external_block_members(self, node: 'AddressableNode') -> None:
self.add_member("rd_ack") 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") self.add_member("wr_ack")
def enter_Addrmap(self, node: 'AddrmapNode') -> None: def enter_Addrmap(self, node: 'AddrmapNode') -> None:
@@ -95,7 +95,7 @@ class InputStructGenerator_Hier(HWIFStructGenerator):
def enter_Reg(self, node: 'RegNode') -> Optional[WalkerAction]: def enter_Reg(self, node: 'RegNode') -> Optional[WalkerAction]:
super().enter_Reg(node) super().enter_Reg(node)
if node.external: 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_ack")
self.add_member("rd_data", width) self.add_member("rd_data", width)
self.add_member("wr_ack") self.add_member("wr_ack")
@@ -162,8 +162,8 @@ class OutputStructGenerator_Hier(HWIFStructGenerator):
self.add_member("req") self.add_member("req")
self.add_member("addr", (node.size - 1).bit_length()) self.add_member("addr", (node.size - 1).bit_length())
self.add_member("req_is_wr") self.add_member("req_is_wr")
self.add_member("wr_data", self.hwif.data_width) self.add_member("wr_data", self.hwif.ds.cpuif_data_width)
self.add_member("wr_biten", self.hwif.data_width) self.add_member("wr_biten", self.hwif.ds.cpuif_data_width)
def enter_Addrmap(self, node: 'AddrmapNode') -> None: def enter_Addrmap(self, node: 'AddrmapNode') -> None:
super().enter_Addrmap(node) super().enter_Addrmap(node)
@@ -189,7 +189,7 @@ class OutputStructGenerator_Hier(HWIFStructGenerator):
def enter_Reg(self, node: 'RegNode') -> Optional[WalkerAction]: def enter_Reg(self, node: 'RegNode') -> Optional[WalkerAction]:
super().enter_Reg(node) super().enter_Reg(node)
if node.external: 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") n_subwords = node.get_property("regwidth") // node.get_property("accesswidth")
self.add_member("req", n_subwords) self.add_member("req", n_subwords)
self.add_member("req_is_wr") self.add_member("req_is_wr")

View File

@@ -1,11 +1,11 @@
// Generated by PeakRDL-regblock - A free and open-source SystemVerilog generator // Generated by PeakRDL-regblock - A free and open-source SystemVerilog generator
// https://github.com/SystemRDL/PeakRDL-regblock // https://github.com/SystemRDL/PeakRDL-regblock
module {{module_name}} ( module {{ds.module_name}} (
input wire clk, input wire clk,
input wire rst, input wire rst,
{%- for signal in user_out_of_hier_signals %} {%- for signal in ds.out_of_hier_signals.values() %}
{%- if signal.width == 1 %} {%- if signal.width == 1 %}
input wire {{kwf(signal.inst_name)}}, input wire {{kwf(signal.inst_name)}},
{%- else %} {%- else %}
@@ -40,7 +40,7 @@ module {{module_name}} (
{{cpuif.get_implementation()|indent}} {{cpuif.get_implementation()|indent}}
logic cpuif_req_masked; logic cpuif_req_masked;
{%- if has_external_addressable %} {%- if ds.has_external_addressable %}
logic external_req; logic external_req;
logic external_pending; logic external_pending;
logic external_wr_ack; logic external_wr_ack;
@@ -54,9 +54,9 @@ module {{module_name}} (
end end
end end
{%- endif %} {%- 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 // Read & write latencies are balanced. Stalls not required
{%- if has_external_addressable %} {%- if ds.has_external_addressable %}
// except if external // except if external
assign cpuif_req_stall_rd = external_pending; assign cpuif_req_stall_rd = external_pending;
assign cpuif_req_stall_wr = 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_rd = '0;
assign cpuif_req_stall_wr = '0; assign cpuif_req_stall_wr = '0;
{%- endif %} {%- 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 // 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 always_ff {{get_always_ff_event(cpuif.reset)}} begin
if({{get_resetsignal(cpuif.reset)}}) begin if({{get_resetsignal(cpuif.reset)}}) begin
cpuif_req_stall_sr <= '0; cpuif_req_stall_sr <= '0;
@@ -76,7 +76,7 @@ module {{module_name}} (
cpuif_req_stall_sr <= (cpuif_req_stall_sr >> 'd1); cpuif_req_stall_sr <= (cpuif_req_stall_sr >> 'd1);
end end
end end
{%- if has_external_addressable %} {%- if ds.has_external_addressable %}
assign cpuif_req_stall_rd = external_pending; assign cpuif_req_stall_rd = external_pending;
assign cpuif_req_stall_wr = cpuif_req_stall_sr[0] | external_pending; assign cpuif_req_stall_wr = cpuif_req_stall_sr[0] | external_pending;
{%- else %} {%- else %}
@@ -85,7 +85,7 @@ module {{module_name}} (
{%- endif %} {%- endif %}
{%- else %} {%- else %}
// Write latency > read latency. May need to delay next read that follows a write // 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 always_ff {{get_always_ff_event(cpuif.reset)}} begin
if({{get_resetsignal(cpuif.reset)}}) begin if({{get_resetsignal(cpuif.reset)}}) begin
cpuif_req_stall_sr <= '0; cpuif_req_stall_sr <= '0;
@@ -95,7 +95,7 @@ module {{module_name}} (
cpuif_req_stall_sr <= (cpuif_req_stall_sr >> 'd1); cpuif_req_stall_sr <= (cpuif_req_stall_sr >> 'd1);
end end
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_rd = cpuif_req_stall_sr[0] | external_pending;
assign cpuif_req_stall_wr = external_pending; assign cpuif_req_stall_wr = external_pending;
{%- else %} {%- else %}
@@ -112,10 +112,10 @@ module {{module_name}} (
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
{{address_decode.get_strobe_struct()|indent}} {{address_decode.get_strobe_struct()|indent}}
decoded_reg_strb_t decoded_reg_strb; decoded_reg_strb_t decoded_reg_strb;
{%- if has_external_addressable %} {%- if ds.has_external_addressable %}
logic decoded_strb_is_external; logic decoded_strb_is_external;
{% endif %} {% endif %}
{%- if has_external_block %} {%- if ds.has_external_block %}
logic [{{cpuif.addr_width-1}}:0] decoded_addr; logic [{{cpuif.addr_width-1}}:0] decoded_addr;
{% endif %} {% endif %}
logic decoded_req; logic decoded_req;
@@ -124,25 +124,25 @@ module {{module_name}} (
logic [{{cpuif.data_width-1}}:0] decoded_wr_biten; logic [{{cpuif.data_width-1}}:0] decoded_wr_biten;
always_comb begin always_comb begin
{%- if has_external_addressable %} {%- if ds.has_external_addressable %}
automatic logic is_external = '0; automatic logic is_external = '0;
{% endif %} {% endif %}
{{address_decode.get_implementation()|indent(8)}} {{address_decode.get_implementation()|indent(8)}}
{%- if has_external_addressable %} {%- if ds.has_external_addressable %}
decoded_strb_is_external = is_external; decoded_strb_is_external = is_external;
external_req = is_external; external_req = is_external;
{% endif %} {% endif %}
end end
// Pass down signals to next stage // Pass down signals to next stage
{%- if has_external_block %} {%- if ds.has_external_block %}
assign decoded_addr = cpuif_addr; assign decoded_addr = cpuif_addr;
{% endif %} {% endif %}
assign decoded_req = cpuif_req_masked; assign decoded_req = cpuif_req_masked;
assign decoded_req_is_wr = cpuif_req_is_wr; assign decoded_req_is_wr = cpuif_req_is_wr;
assign decoded_wr_data = cpuif_wr_data; assign decoded_wr_data = cpuif_wr_data;
assign decoded_wr_biten = cpuif_wr_biten; 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 // 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_data_bswap;
logic [{{cpuif.data_width-1}}:0] decoded_wr_biten_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}}; assign decoded_wr_biten_bswap = {<<{decoded_wr_biten}};
{%- endif %} {%- endif %}
{%- if has_buffered_write_regs %} {%- if ds.has_buffered_write_regs %}
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// Write double-buffers // Write double-buffers
@@ -168,7 +168,7 @@ module {{module_name}} (
{{field_logic.get_implementation()|indent}} {{field_logic.get_implementation()|indent}}
{%- if has_buffered_read_regs %} {%- if ds.has_buffered_read_regs %}
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// Read double-buffers // Read double-buffers
@@ -181,7 +181,7 @@ module {{module_name}} (
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// Write response // Write response
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
{%- if has_external_addressable %} {%- if ds.has_external_addressable %}
always_comb begin always_comb begin
automatic logic wr_ack; automatic logic wr_ack;
wr_ack = '0; wr_ack = '0;
@@ -198,7 +198,7 @@ module {{module_name}} (
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// Readback // Readback
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
{%- if has_external_addressable %} {%- if ds.has_external_addressable %}
logic readback_external_rd_ack_c; logic readback_external_rd_ack_c;
always_comb begin always_comb begin
automatic logic rd_ack; automatic logic rd_ack;
@@ -208,7 +208,7 @@ module {{module_name}} (
end end
logic readback_external_rd_ack; logic readback_external_rd_ack;
{%- if retime_read_fanin %} {%- if ds.retime_read_fanin %}
always_ff {{get_always_ff_event(cpuif.reset)}} begin always_ff {{get_always_ff_event(cpuif.reset)}} begin
if({{get_resetsignal(cpuif.reset)}}) begin if({{get_resetsignal(cpuif.reset)}}) begin
readback_external_rd_ack <= '0; readback_external_rd_ack <= '0;
@@ -227,17 +227,17 @@ module {{module_name}} (
logic readback_done; logic readback_done;
logic [{{cpuif.data_width-1}}:0] readback_data; logic [{{cpuif.data_width-1}}:0] readback_data;
{{readback.get_implementation()|indent}} {{readback.get_implementation()|indent}}
{% if retime_read_response %} {% if ds.retime_read_response %}
always_ff {{get_always_ff_event(cpuif.reset)}} begin always_ff {{get_always_ff_event(cpuif.reset)}} begin
if({{get_resetsignal(cpuif.reset)}}) 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;
{%- if has_external_addressable %} {%- if ds.has_external_addressable %}
external_rd_ack <= '0; external_rd_ack <= '0;
{%- endif %} {%- endif %}
end else begin end else begin
{%- if has_external_addressable %} {%- if ds.has_external_addressable %}
external_rd_ack <= readback_external_rd_ack; external_rd_ack <= readback_external_rd_ack;
cpuif_rd_ack <= readback_done | readback_external_rd_ack; cpuif_rd_ack <= readback_done | readback_external_rd_ack;
{%- else %} {%- else %}
@@ -248,7 +248,7 @@ module {{module_name}} (
end end
end end
{% else %} {% else %}
{%- if has_external_addressable %} {%- if ds.has_external_addressable %}
assign external_rd_ack = readback_external_rd_ack; assign external_rd_ack = readback_external_rd_ack;
assign cpuif_rd_ack = readback_done | readback_external_rd_ack; assign cpuif_rd_ack = readback_done | readback_external_rd_ack;
{%- else %} {%- else %}

View File

@@ -1,6 +1,6 @@
// Generated by PeakRDL-regblock - A free and open-source SystemVerilog generator // Generated by PeakRDL-regblock - A free and open-source SystemVerilog generator
// https://github.com/SystemRDL/PeakRDL-regblock // https://github.com/SystemRDL/PeakRDL-regblock
package {{hwif.package_name}}; package {{ds.package_name}};
{{hwif.get_package_contents()|indent}} {{hwif.get_package_contents()|indent}}
endpackage endpackage

View File

@@ -16,7 +16,7 @@ class ReadBuffering:
@property @property
def top_node(self) -> 'AddrmapNode': def top_node(self) -> 'AddrmapNode':
return self.exp.top_node return self.exp.ds.top_node
def get_storage_struct(self) -> str: def get_storage_struct(self) -> str:
struct_gen = RBufStorageStructGenerator() struct_gen = RBufStorageStructGenerator()

View File

@@ -4,18 +4,21 @@ import math
from .generators import ReadbackAssignmentGenerator from .generators import ReadbackAssignmentGenerator
if TYPE_CHECKING: if TYPE_CHECKING:
from ..exporter import RegblockExporter from ..exporter import RegblockExporter, DesignState
from systemrdl.node import AddrmapNode from systemrdl.node import AddrmapNode
class Readback: class Readback:
def __init__(self, exp:'RegblockExporter', do_fanin_stage: bool, has_external_addressable: bool): def __init__(self, exp:'RegblockExporter'):
self.exp = exp self.exp = exp
self.do_fanin_stage = do_fanin_stage self.do_fanin_stage = self.ds.retime_read_fanin
self.has_external_addressable = has_external_addressable
@property
def ds(self) -> 'DesignState':
return self.exp.ds
@property @property
def top_node(self) -> 'AddrmapNode': def top_node(self) -> 'AddrmapNode':
return self.exp.top_node return self.exp.ds.top_node
def get_implementation(self) -> str: def get_implementation(self) -> str:
gen = ReadbackAssignmentGenerator(self.exp) gen = ReadbackAssignmentGenerator(self.exp)
@@ -33,7 +36,7 @@ class Readback:
'get_always_ff_event': self.exp.dereferencer.get_always_ff_event, 'get_always_ff_event': self.exp.dereferencer.get_always_ff_event,
"cpuif": self.exp.cpuif, "cpuif": self.exp.cpuif,
"do_fanin_stage": self.do_fanin_stage, "do_fanin_stage": self.do_fanin_stage,
"has_external_addressable": self.has_external_addressable, "ds": self.ds,
} }
if self.do_fanin_stage: if self.do_fanin_stage:

View File

@@ -35,7 +35,7 @@ always_ff @(posedge clk) begin
readback_done_r <= '0; readback_done_r <= '0;
end else begin end else begin
readback_array_r <= readback_array_c; 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; readback_done_r <= decoded_req & ~decoded_req_is_wr & ~decoded_strb_is_external;
{%- else %} {%- else %}
readback_done_r <= decoded_req & ~decoded_req_is_wr; readback_done_r <= decoded_req & ~decoded_req_is_wr;
@@ -58,7 +58,7 @@ end
// Reduce the array // Reduce the array
always_comb begin always_comb begin
automatic logic [{{cpuif.data_width-1}}:0] readback_data_var; 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; readback_done = decoded_req & ~decoded_req_is_wr & ~decoded_strb_is_external;
{%- else %} {%- else %}
readback_done = decoded_req & ~decoded_req_is_wr; readback_done = decoded_req & ~decoded_req_is_wr;

View File

@@ -1,13 +1,11 @@
from typing import TYPE_CHECKING, Set, Optional, Type, List from typing import TYPE_CHECKING, Optional
from collections import OrderedDict
from systemrdl.walker import RDLListener, RDLWalker, WalkerAction from systemrdl.walker import RDLListener, RDLWalker, WalkerAction
from systemrdl.node import SignalNode, RegNode from systemrdl.node import SignalNode, RegNode
if TYPE_CHECKING: if TYPE_CHECKING:
from systemrdl.node import Node, FieldNode, AddressableNode from systemrdl.node import Node, FieldNode, AddressableNode, AddrmapNode
from .exporter import RegblockExporter from .exporter import RegblockExporter
from systemrdl.rdltypes import UserEnum
class DesignScanner(RDLListener): class DesignScanner(RDLListener):
@@ -19,63 +17,53 @@ class DesignScanner(RDLListener):
""" """
def __init__(self, exp:'RegblockExporter') -> None: def __init__(self, exp:'RegblockExporter') -> None:
self.exp = exp self.exp = exp
self.cpuif_data_width = 0 self.ds = exp.ds
self.msg = exp.top_node.env.msg self.msg = self.top_node.env.msg
# Collections of signals that were actually referenced by the design @property
self.in_hier_signal_paths = set() # type: Set[str] def top_node(self) -> 'AddrmapNode':
self.out_of_hier_signals = OrderedDict() # type: OrderedDict[str, SignalNode] return self.exp.ds.top_node
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]]
def _get_out_of_hier_field_reset(self) -> None: 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: while current_node is not None:
for signal in current_node.signals(): for signal in current_node.signals():
if signal.get_property('field_reset'): if signal.get_property('field_reset'):
path = signal.get_path() path = signal.get_path()
self.out_of_hier_signals[path] = signal self.ds.out_of_hier_signals[path] = signal
return return
current_node = current_node.parent current_node = current_node.parent
def do_scan(self) -> None: def do_scan(self) -> None:
# Collect cpuif reset, if any. # 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: if cpuif_reset is not None:
path = cpuif_reset.get_path() 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("^"): if rel_path.startswith("^"):
self.out_of_hier_signals[path] = cpuif_reset self.ds.out_of_hier_signals[path] = cpuif_reset
else: else:
self.in_hier_signal_paths.add(path) self.ds.in_hier_signal_paths.add(path)
# collect out-of-hier field_reset, if any # collect out-of-hier field_reset, if any
self._get_out_of_hier_field_reset() self._get_out_of_hier_field_reset()
# Ensure addrmap is not a bridge. This concept does not make sense for # Ensure addrmap is not a bridge. This concept does not make sense for
# terminal components. # terminal components.
if self.exp.top_node.get_property('bridge'): if self.top_node.get_property('bridge'):
self.msg.error( self.msg.error(
"Regblock generator does not support exporting bridge address maps", "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: if self.msg.had_error:
self.msg.fatal( self.msg.fatal(
"Unable to export due to previous errors" "Unable to export due to previous errors"
) )
def enter_Component(self, node: 'Node') -> Optional[WalkerAction]: 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 # Do not inspect external components. None of my business
return WalkerAction.SkipDescendants return WalkerAction.SkipDescendants
@@ -84,37 +72,37 @@ class DesignScanner(RDLListener):
value = node.get_property(prop_name) value = node.get_property(prop_name)
if isinstance(value, SignalNode): if isinstance(value, SignalNode):
path = value.get_path() 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("^"): if rel_path.startswith("^"):
self.out_of_hier_signals[path] = value self.ds.out_of_hier_signals[path] = value
else: else:
self.in_hier_signal_paths.add(path) self.ds.in_hier_signal_paths.add(path)
if prop_name == "encode": if prop_name == "encode":
if value not in self.user_enums: if value not in self.ds.user_enums:
self.user_enums.append(value) self.ds.user_enums.append(value)
return WalkerAction.Continue return WalkerAction.Continue
def enter_AddressableComponent(self, node: 'AddressableNode') -> None: def enter_AddressableComponent(self, node: 'AddressableNode') -> None:
if node.external and node != self.exp.top_node: if node.external and node != self.top_node:
self.has_external_addressable = True self.ds.has_external_addressable = True
if not isinstance(node, RegNode): if not isinstance(node, RegNode):
self.has_external_block = True self.ds.has_external_block = True
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 accesswidth in the design # The CPUIF's bus width is sized according to the largest accesswidth in the design
accesswidth = node.get_property('accesswidth') 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.ds.has_buffered_write_regs = self.ds.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_read_regs = self.ds.has_buffered_read_regs or bool(node.get_property('buffer_reads'))
def enter_Signal(self, node: 'SignalNode') -> None: def enter_Signal(self, node: 'SignalNode') -> None:
if node.get_property('field_reset'): if node.get_property('field_reset'):
path = node.get_path() 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: def enter_Field(self, node: 'FieldNode') -> None:
if node.is_sw_writable and (node.msb < node.lsb): if node.is_sw_writable and (node.msb < node.lsb):
self.has_writable_msb0_fields = True self.ds.has_writable_msb0_fields = True

View File

@@ -19,20 +19,24 @@ class DesignValidator(RDLListener):
""" """
def __init__(self, exp:'RegblockExporter') -> None: def __init__(self, exp:'RegblockExporter') -> None:
self.exp = exp 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_stack = [] # type: List[bool]
self.contains_external_block = False self.contains_external_block = False
@property
def top_node(self) -> 'AddrmapNode':
return self.exp.ds.top_node
def do_validate(self) -> None: def do_validate(self) -> None:
RDLWalker().walk(self.exp.top_node, self) RDLWalker().walk(self.top_node, self)
if self.msg.had_error: if self.msg.had_error:
self.msg.fatal( self.msg.fatal(
"Unable to export due to previous errors" "Unable to export due to previous errors"
) )
def enter_Component(self, node: 'Node') -> Optional[WalkerAction]: 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 # Do not inspect external components. None of my business
return WalkerAction.SkipDescendants return WalkerAction.SkipDescendants
@@ -40,7 +44,7 @@ class DesignValidator(RDLListener):
for prop_name in node.list_properties(): for prop_name in node.list_properties():
value = node.get_property(prop_name) value = node.get_property(prop_name)
if isinstance(value, (PropertyReference, Node)): 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): if isinstance(value, PropertyReference):
src_ref = value.src_ref src_ref = value.src_ref
else: else:
@@ -55,7 +59,7 @@ class DesignValidator(RDLListener):
# If encountering a CPUIF reset that is nested within the register model, # If encountering a CPUIF reset that is nested within the register model,
# warn that it will be ignored. # warn that it will be ignored.
# Only cpuif resets in the top-level node or above will be honored # 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( self.msg.warning(
"Only cpuif_reset signals that are instantiated in the top-level " "Only cpuif_reset signals that are instantiated in the top-level "
"addrmap or above will be honored. Any cpuif_reset signals nested " "addrmap or above will be honored. Any cpuif_reset signals nested "
@@ -81,7 +85,7 @@ class DesignValidator(RDLListener):
if not isinstance(node, RegNode): if not isinstance(node, RegNode):
# Entering a block-like node # Entering a block-like node
if node == self.exp.top_node: if node == self.top_node:
# Ignore top addrmap's external property when entering # Ignore top addrmap's external property when entering
self._contains_external_block_stack.append(False) self._contains_external_block_stack.append(False)
else: else:

View File

@@ -16,7 +16,7 @@ class WriteBuffering:
@property @property
def top_node(self) -> 'AddrmapNode': def top_node(self) -> 'AddrmapNode':
return self.exp.top_node return self.exp.ds.top_node
def get_storage_struct(self) -> str: def get_storage_struct(self) -> str: