Refactor exporter class to clean up the mess of random variables
This commit is contained in:
@@ -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()
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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 %}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user