diff --git a/doc/logbooks/template-layers/4-fields b/doc/logbooks/template-layers/4-fields index a2b4fee..4480ac8 100644 --- a/doc/logbooks/template-layers/4-fields +++ b/doc/logbooks/template-layers/4-fields @@ -7,26 +7,30 @@ Any field that implements storage is defined here. Bigass struct that only contains storage elements Each field consists of: + - an always_comb block: + - generates the "next value" combinational signal + - May generate other intermediate strobes? + incr/decr? + - series of if/else statements that assign the next value in the storage element + Think of this as a flat list of "next state" conditons, ranked by their precedence as follows: + - reset + Actually, handle this in the always_ff + - sw access (if sw precedence) + - onread/onwrite + - hw access + - Counter + beware of clear events and incr/decr events happening simultaneously + - next + - etc + - sw access (if hw precedence) + - onread/onwrite + - always_comb block to also generate write-enable strobes for the actual + storage element + This is better for low-power design - an always_ff block - - series of if/else statements that assign the next value in the storage element - Think of this as a flat list of "next state" conditons, ranked by their precedence as follows: - - reset - - sw access (if sw precedence) - - onread/onwrite - - hw access - - Counter - - next - - etc - - sw access (if hw precedence) - - onread/onwrite - -TODO: - What about stuff like read-clear counters that cant lose a count? - In a traditional if/else chain, i need to be aware of the fact that its a counter - when handling the swaccess case - Is it possible to code this in a way where I can isolate the need to know every nuanced case here? - this may actually only apply to counters... - This is trivial in a 2-process implementation, but i'd rather avoid the overheads + Implements the actual storage element + Also a tidy place to abstract the specifics of activehigh/activelow field reset + selection. TODO: Scour the RDL spec. diff --git a/peakrdl/regblock/dereferencer.py b/peakrdl/regblock/dereferencer.py index d393bc9..b7a682d 100644 --- a/peakrdl/regblock/dereferencer.py +++ b/peakrdl/regblock/dereferencer.py @@ -4,7 +4,7 @@ from systemrdl.rdltypes import PropertyReference if TYPE_CHECKING: from .exporter import RegblockExporter - from .hwif.base import HwifBase + from .hwif import Hwif from .field_logic import FieldLogic from .addr_decode import AddressDecode @@ -13,7 +13,7 @@ class Dereferencer: This class provides an interface to convert conceptual SystemRDL references into Verilog identifiers """ - def __init__(self, exporter:'RegblockExporter', top_node:Node, hwif:'HwifBase', address_decode: 'AddressDecode', field_logic: 'FieldLogic'): + def __init__(self, exporter:'RegblockExporter', top_node:Node, hwif:'Hwif', address_decode: 'AddressDecode', field_logic: 'FieldLogic'): self.exporter = exporter self.hwif = hwif self.address_decode = address_decode diff --git a/peakrdl/regblock/exporter.py b/peakrdl/regblock/exporter.py index 6d1d98c..7bb73ba 100644 --- a/peakrdl/regblock/exporter.py +++ b/peakrdl/regblock/exporter.py @@ -11,7 +11,7 @@ from .readback_mux import ReadbackMux from .signals import InferredSignal from .cpuif.apb4 import APB4_Cpuif -from .hwif.struct import StructHwif +from .hwif import Hwif class RegblockExporter: def __init__(self, **kwargs): @@ -50,7 +50,7 @@ class RegblockExporter: node = node.top cpuif_cls = kwargs.pop("cpuif_cls", APB4_Cpuif) - hwif_cls = kwargs.pop("hwif_cls", StructHwif) + hwif_cls = kwargs.pop("hwif_cls", Hwif) module_name = kwargs.pop("module_name", node.inst_name) package_name = kwargs.pop("package_name", module_name + "_pkg") diff --git a/peakrdl/regblock/hwif/struct.py b/peakrdl/regblock/hwif.py similarity index 70% rename from peakrdl/regblock/hwif/struct.py rename to peakrdl/regblock/hwif.py index a5253d3..a23c609 100644 --- a/peakrdl/regblock/hwif/struct.py +++ b/peakrdl/regblock/hwif.py @@ -1,16 +1,22 @@ -from typing import Union, List, TYPE_CHECKING - -from systemrdl.node import Node, AddressableNode, FieldNode, SignalNode - -from .base import HwifBase +from typing import TYPE_CHECKING, Union, List +from systemrdl.node import Node, SignalNode, FieldNode, AddressableNode +from systemrdl.rdltypes import PropertyReference if TYPE_CHECKING: - from ..exporter import RegblockExporter + from .exporter import RegblockExporter -class StructHwif(HwifBase): +class Hwif: + """ + Defines how the hardware input/output signals are generated: + - Field outputs + - Field inputs + - Signal inputs (except those that are promoted to the top) + """ - def __init__(self, exporter:'RegblockExporter', top_node:Node, package_name:str): - super().__init__(exporter, top_node, package_name) + def __init__(self, exporter: 'RegblockExporter', top_node: Node, package_name: str): + self.exporter = exporter + self.top_node = top_node + self.package_name = package_name self.has_input_struct = None self.has_output_struct = None @@ -18,6 +24,9 @@ class StructHwif(HwifBase): def get_package_declaration(self) -> str: + """ + If this hwif requires a package, generate the string + """ lines = [] lines.append(f"package {self.package_name};") @@ -49,6 +58,7 @@ class StructHwif(HwifBase): return ",\n".join(lines) + #--------------------------------------------------------------------------- # Struct generation functions #--------------------------------------------------------------------------- @@ -180,3 +190,58 @@ class StructHwif(HwifBase): """ return contents + + #--------------------------------------------------------------------------- + # hwif utility functions + #--------------------------------------------------------------------------- + def has_value_input(self, obj: Union[FieldNode, SignalNode]) -> bool: + """ + Returns True if the object infers an input wire in the hwif + """ + if isinstance(obj, FieldNode): + return obj.is_hw_writable + elif isinstance(obj, SignalNode): + # Signals are implicitly always inputs + return True + else: + raise RuntimeError + + + def has_value_output(self, obj: FieldNode) -> bool: + """ + Returns True if the object infers an output wire in the hwif + """ + # TODO: Extend this for signals and prop references? + return obj.is_hw_readable + + + def get_input_identifier(self, obj: Union[FieldNode, SignalNode, PropertyReference]) -> str: + """ + Returns the identifier string that best represents the input object. + + if obj is: + Field: the fields input value port + Signal: signal input value + Prop reference: + could be an implied hwclr/hwset/swwe/swwel/we/wel input + Raise a runtime error if an illegal prop ref is requested, or if + the prop ref is not actually implied, but explicitly ref a component + + TODO: finish this + raises an exception if obj is invalid + """ + raise NotImplementedError() + + + def get_output_identifier(self, obj: FieldNode) -> str: + """ + Returns the identifier string that best represents the output object. + + if obj is: + Field: the fields output value port + Property ref: this is also part of the struct + TODO: finish this + + raises an exception if obj is invalid + """ + raise NotImplementedError() diff --git a/peakrdl/regblock/hwif/__init__.py b/peakrdl/regblock/hwif/__init__.py deleted file mode 100644 index ed04c84..0000000 --- a/peakrdl/regblock/hwif/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .base import HwifBase diff --git a/peakrdl/regblock/hwif/base.py b/peakrdl/regblock/hwif/base.py deleted file mode 100644 index ee4624d..0000000 --- a/peakrdl/regblock/hwif/base.py +++ /dev/null @@ -1,89 +0,0 @@ -from typing import TYPE_CHECKING, Union -from systemrdl.node import Node, SignalNode, FieldNode -from systemrdl.rdltypes import AccessType, PropertyReference - -if TYPE_CHECKING: - from ..exporter import RegblockExporter - -class HwifBase: - """ - Defines how the hardware input/output signals are generated: - - Field outputs - - Field inputs - - Signal inputs (except those that are promoted to the top) - """ - - def __init__(self, exporter: 'RegblockExporter', top_node: Node, package_name: str): - self.exporter = exporter - self.top_node = top_node - self.package_name = package_name - - - def get_package_declaration(self) -> str: - """ - If this hwif requires a package, generate the string - """ - return "" - - - @property - def port_declaration(self) -> str: - """ - Returns the declaration string for all I/O ports in the hwif group - """ - raise NotImplementedError() - - #--------------------------------------------------------------------------- - # hwif utility functions - #--------------------------------------------------------------------------- - def has_value_input(self, obj: Union[FieldNode, SignalNode]) -> bool: - """ - Returns True if the object infers an input wire in the hwif - """ - if isinstance(obj, FieldNode): - return obj.is_hw_writable - elif isinstance(obj, SignalNode): - # Signals are implicitly always inputs - return True - else: - raise RuntimeError - - - def has_value_output(self, obj: FieldNode) -> bool: - """ - Returns True if the object infers an output wire in the hwif - """ - # TODO: Extend this for signals and prop references? - return obj.is_hw_readable - - - def get_input_identifier(self, obj: Union[FieldNode, SignalNode, PropertyReference]) -> str: - """ - Returns the identifier string that best represents the input object. - - if obj is: - Field: the fields input value port - Signal: signal input value - Prop reference: - could be an implied hwclr/hwset/swwe/swwel/we/wel input - Raise a runtime error if an illegal prop ref is requested, or if - the prop ref is not actually implied, but explicitly ref a component - - TODO: finish this - raises an exception if obj is invalid - """ - raise NotImplementedError() - - - def get_output_identifier(self, obj: FieldNode) -> str: - """ - Returns the identifier string that best represents the output object. - - if obj is: - Field: the fields output value port - Property ref: this is also part of the struct - TODO: finish this - - raises an exception if obj is invalid - """ - raise NotImplementedError()