Implement new SVInt object to defer literal expansion and allow bit-fiddling operations. Fix invalid bit-slicing of literals if field reset value is a constant. #71
This commit is contained in:
@@ -3,10 +3,11 @@ from typing import TYPE_CHECKING, Union, List, Optional
|
|||||||
from systemrdl.node import FieldNode, RegNode
|
from systemrdl.node import FieldNode, RegNode
|
||||||
from systemrdl.walker import WalkerAction
|
from systemrdl.walker import WalkerAction
|
||||||
|
|
||||||
from .utils import get_indexed_path, get_sv_int
|
from .utils import get_indexed_path
|
||||||
from .struct_generator import RDLStructGenerator
|
from .struct_generator import RDLStructGenerator
|
||||||
from .forloop_generator import RDLForLoopGenerator
|
from .forloop_generator import RDLForLoopGenerator
|
||||||
from .identifier_filter import kw_filter as kwf
|
from .identifier_filter import kw_filter as kwf
|
||||||
|
from .sv_int import SVInt
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .exporter import RegblockExporter
|
from .exporter import RegblockExporter
|
||||||
@@ -149,7 +150,7 @@ class DecodeLogicGenerator(RDLForLoopGenerator):
|
|||||||
# Is an external block
|
# Is an external block
|
||||||
addr_str = self._get_address_str(node)
|
addr_str = self._get_address_str(node)
|
||||||
strb = self.addr_decode.get_external_block_access_strobe(node)
|
strb = self.addr_decode.get_external_block_access_strobe(node)
|
||||||
rhs = f"cpuif_req_masked & (cpuif_addr >= {addr_str}) & (cpuif_addr <= {addr_str} + {get_sv_int(node.size - 1, self.addr_decode.exp.ds.addr_width)})"
|
rhs = f"cpuif_req_masked & (cpuif_addr >= {addr_str}) & (cpuif_addr <= {addr_str} + {SVInt(node.size - 1, self.addr_decode.exp.ds.addr_width)})"
|
||||||
self.add_content(f"{strb} = {rhs};")
|
self.add_content(f"{strb} = {rhs};")
|
||||||
self.add_content(f"is_external |= {rhs};")
|
self.add_content(f"is_external |= {rhs};")
|
||||||
return WalkerAction.SkipDescendants
|
return WalkerAction.SkipDescendants
|
||||||
@@ -158,12 +159,12 @@ class DecodeLogicGenerator(RDLForLoopGenerator):
|
|||||||
|
|
||||||
|
|
||||||
def _get_address_str(self, node: 'AddressableNode', subword_offset: int=0) -> str:
|
def _get_address_str(self, node: 'AddressableNode', subword_offset: int=0) -> str:
|
||||||
a = get_sv_int(
|
a = str(SVInt(
|
||||||
node.raw_absolute_address - self.addr_decode.top_node.raw_absolute_address + subword_offset,
|
node.raw_absolute_address - self.addr_decode.top_node.raw_absolute_address + subword_offset,
|
||||||
self.addr_decode.exp.ds.addr_width
|
self.addr_decode.exp.ds.addr_width
|
||||||
)
|
))
|
||||||
for i, stride in enumerate(self._array_stride_stack):
|
for i, stride in enumerate(self._array_stride_stack):
|
||||||
a += f" + i{i}*{get_sv_int(stride, self.addr_decode.exp.ds.addr_width)}"
|
a += f" + i{i}*{SVInt(stride, self.addr_decode.exp.ds.addr_width)}"
|
||||||
return a
|
return a
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from typing import TYPE_CHECKING, Union, Optional
|
|||||||
from systemrdl.node import AddrmapNode, FieldNode, SignalNode, RegNode, AddressableNode
|
from systemrdl.node import AddrmapNode, FieldNode, SignalNode, RegNode, AddressableNode
|
||||||
from systemrdl.rdltypes import PropertyReference
|
from systemrdl.rdltypes import PropertyReference
|
||||||
|
|
||||||
from .utils import get_sv_int
|
from .sv_int import SVInt
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .exporter import RegblockExporter, DesignState
|
from .exporter import RegblockExporter, DesignState
|
||||||
@@ -38,7 +38,7 @@ class Dereferencer:
|
|||||||
def top_node(self) -> AddrmapNode:
|
def top_node(self) -> AddrmapNode:
|
||||||
return self.exp.ds.top_node
|
return self.exp.ds.top_node
|
||||||
|
|
||||||
def get_value(self, obj: Union[int, FieldNode, SignalNode, PropertyReference], width: Optional[int] = None) -> str:
|
def get_value(self, obj: Union[int, FieldNode, SignalNode, PropertyReference], width: Optional[int] = None) -> Union[SVInt, str]:
|
||||||
"""
|
"""
|
||||||
Returns the Verilog string that represents the readable value associated
|
Returns the Verilog string that represents the readable value associated
|
||||||
with the object.
|
with the object.
|
||||||
@@ -52,20 +52,20 @@ class Dereferencer:
|
|||||||
"""
|
"""
|
||||||
if isinstance(obj, int):
|
if isinstance(obj, int):
|
||||||
# Is a simple scalar value
|
# Is a simple scalar value
|
||||||
return get_sv_int(obj, width)
|
return SVInt(obj, width)
|
||||||
|
|
||||||
if isinstance(obj, FieldNode):
|
if isinstance(obj, FieldNode):
|
||||||
if obj.implements_storage:
|
if obj.implements_storage:
|
||||||
return self.field_logic.get_storage_identifier(obj)
|
return self.field_logic.get_storage_identifier(obj)
|
||||||
|
|
||||||
if self.hwif.has_value_input(obj):
|
if self.hwif.has_value_input(obj):
|
||||||
return self.hwif.get_input_identifier(obj)
|
return self.hwif.get_input_identifier(obj, width)
|
||||||
|
|
||||||
# Field does not have a storage element, nor does it have a HW input
|
# Field does not have a storage element, nor does it have a HW input
|
||||||
# must be a constant value as defined by its reset value
|
# must be a constant value as defined by its reset value
|
||||||
reset_value = obj.get_property('reset')
|
reset_value = obj.get_property('reset')
|
||||||
if reset_value is not None:
|
if reset_value is not None:
|
||||||
return self.get_value(reset_value)
|
return self.get_value(reset_value, obj.width)
|
||||||
else:
|
else:
|
||||||
# No reset value defined!
|
# No reset value defined!
|
||||||
obj.env.msg.warning(
|
obj.env.msg.warning(
|
||||||
@@ -76,11 +76,11 @@ class Dereferencer:
|
|||||||
|
|
||||||
if isinstance(obj, SignalNode):
|
if isinstance(obj, SignalNode):
|
||||||
# Signals are always inputs from the hwif
|
# Signals are always inputs from the hwif
|
||||||
return self.hwif.get_input_identifier(obj)
|
return self.hwif.get_input_identifier(obj, width)
|
||||||
|
|
||||||
if isinstance(obj, PropertyReference):
|
if isinstance(obj, PropertyReference):
|
||||||
if isinstance(obj.node, FieldNode):
|
if isinstance(obj.node, FieldNode):
|
||||||
return self.get_field_propref_value(obj.node, obj.name)
|
return self.get_field_propref_value(obj.node, obj.name, width)
|
||||||
elif isinstance(obj.node, RegNode):
|
elif isinstance(obj.node, RegNode):
|
||||||
return self.get_reg_propref_value(obj.node, obj.name)
|
return self.get_reg_propref_value(obj.node, obj.name)
|
||||||
else:
|
else:
|
||||||
@@ -89,7 +89,12 @@ class Dereferencer:
|
|||||||
raise RuntimeError(f"Unhandled reference to: {obj}")
|
raise RuntimeError(f"Unhandled reference to: {obj}")
|
||||||
|
|
||||||
|
|
||||||
def get_field_propref_value(self, field: FieldNode, prop_name: str) -> str:
|
def get_field_propref_value(
|
||||||
|
self,
|
||||||
|
field: FieldNode,
|
||||||
|
prop_name: str,
|
||||||
|
width: Optional[int] = None,
|
||||||
|
) -> Union[SVInt, str]:
|
||||||
# Value reduction properties.
|
# Value reduction properties.
|
||||||
# Wrap with the appropriate Verilog reduction operator
|
# Wrap with the appropriate Verilog reduction operator
|
||||||
if prop_name == "anded":
|
if prop_name == "anded":
|
||||||
@@ -115,7 +120,7 @@ class Dereferencer:
|
|||||||
'reset',
|
'reset',
|
||||||
'resetsignal',
|
'resetsignal',
|
||||||
}:
|
}:
|
||||||
return self.get_value(field.get_property(prop_name))
|
return self.get_value(field.get_property(prop_name), width)
|
||||||
|
|
||||||
# Field Next
|
# Field Next
|
||||||
if prop_name == "next":
|
if prop_name == "next":
|
||||||
@@ -124,7 +129,7 @@ class Dereferencer:
|
|||||||
# unset by the user, points to the implied internal signal
|
# unset by the user, points to the implied internal signal
|
||||||
return self.field_logic.get_field_combo_identifier(field, "next")
|
return self.field_logic.get_field_combo_identifier(field, "next")
|
||||||
else:
|
else:
|
||||||
return self.get_value(prop_value)
|
return self.get_value(prop_value, width)
|
||||||
|
|
||||||
# References to another component value, or an implied input
|
# References to another component value, or an implied input
|
||||||
if prop_name in {'hwclr', 'hwset'}:
|
if prop_name in {'hwclr', 'hwset'}:
|
||||||
@@ -163,7 +168,7 @@ class Dereferencer:
|
|||||||
else:
|
else:
|
||||||
return f"!({self.get_value(prop_value)})"
|
return f"!({self.get_value(prop_value)})"
|
||||||
else:
|
else:
|
||||||
return self.get_value(prop_value)
|
return self.get_value(prop_value, width)
|
||||||
|
|
||||||
if prop_name == "swacc":
|
if prop_name == "swacc":
|
||||||
return self.field_logic.get_swacc_identifier(field)
|
return self.field_logic.get_swacc_identifier(field)
|
||||||
@@ -232,7 +237,7 @@ class Dereferencer:
|
|||||||
if isinstance(obj, SignalNode):
|
if isinstance(obj, SignalNode):
|
||||||
s = self.get_value(obj)
|
s = self.get_value(obj)
|
||||||
if obj.get_property('activehigh'):
|
if obj.get_property('activehigh'):
|
||||||
return s
|
return str(s)
|
||||||
else:
|
else:
|
||||||
return f"~{s}"
|
return f"~{s}"
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING, Union
|
||||||
|
|
||||||
from systemrdl.rdltypes import PrecedenceType, InterruptType
|
from systemrdl.rdltypes import PrecedenceType, InterruptType
|
||||||
|
|
||||||
@@ -11,6 +11,7 @@ from . import hw_set_clr
|
|||||||
from . import hw_interrupts
|
from . import hw_interrupts
|
||||||
|
|
||||||
from ..utils import get_indexed_path
|
from ..utils import get_indexed_path
|
||||||
|
from ..sv_int import SVInt
|
||||||
|
|
||||||
from .generators import CombinationalStructGenerator, FieldStorageStructGenerator, FieldLogicGenerator
|
from .generators import CombinationalStructGenerator, FieldStorageStructGenerator, FieldLogicGenerator
|
||||||
|
|
||||||
@@ -99,12 +100,12 @@ class FieldLogic:
|
|||||||
"""
|
"""
|
||||||
prop_value = field.get_property('incr')
|
prop_value = field.get_property('incr')
|
||||||
if prop_value:
|
if prop_value:
|
||||||
return self.exp.dereferencer.get_value(prop_value)
|
return str(self.exp.dereferencer.get_value(prop_value))
|
||||||
|
|
||||||
# unset by the user, points to the implied input signal
|
# unset by the user, points to the implied input signal
|
||||||
return self.exp.hwif.get_implied_prop_input_identifier(field, "incr")
|
return self.exp.hwif.get_implied_prop_input_identifier(field, "incr")
|
||||||
|
|
||||||
def get_counter_incrvalue(self, field: 'FieldNode') -> str:
|
def get_counter_incrvalue(self, field: 'FieldNode') -> Union[SVInt, str]:
|
||||||
"""
|
"""
|
||||||
Return the string that represents the field's increment value
|
Return the string that represents the field's increment value
|
||||||
"""
|
"""
|
||||||
@@ -115,7 +116,7 @@ class FieldLogic:
|
|||||||
return self.exp.hwif.get_implied_prop_input_identifier(field, "incrvalue")
|
return self.exp.hwif.get_implied_prop_input_identifier(field, "incrvalue")
|
||||||
return "1'b1"
|
return "1'b1"
|
||||||
|
|
||||||
def get_counter_incrsaturate_value(self, field: 'FieldNode') -> str:
|
def get_counter_incrsaturate_value(self, field: 'FieldNode') -> Union[SVInt, str]:
|
||||||
prop_value = field.get_property('incrsaturate')
|
prop_value = field.get_property('incrsaturate')
|
||||||
if prop_value is True:
|
if prop_value is True:
|
||||||
return self.exp.dereferencer.get_value(2**field.width - 1, field.width)
|
return self.exp.dereferencer.get_value(2**field.width - 1, field.width)
|
||||||
@@ -127,7 +128,7 @@ class FieldLogic:
|
|||||||
"""
|
"""
|
||||||
return field.get_property('incrsaturate') is not False
|
return field.get_property('incrsaturate') is not False
|
||||||
|
|
||||||
def get_counter_incrthreshold_value(self, field: 'FieldNode') -> str:
|
def get_counter_incrthreshold_value(self, field: 'FieldNode') -> Union[SVInt, str]:
|
||||||
prop_value = field.get_property('incrthreshold')
|
prop_value = field.get_property('incrthreshold')
|
||||||
if isinstance(prop_value, bool):
|
if isinstance(prop_value, bool):
|
||||||
# No explicit value set. use max
|
# No explicit value set. use max
|
||||||
@@ -140,12 +141,12 @@ class FieldLogic:
|
|||||||
"""
|
"""
|
||||||
prop_value = field.get_property('decr')
|
prop_value = field.get_property('decr')
|
||||||
if prop_value:
|
if prop_value:
|
||||||
return self.exp.dereferencer.get_value(prop_value)
|
return str(self.exp.dereferencer.get_value(prop_value))
|
||||||
|
|
||||||
# unset by the user, points to the implied input signal
|
# unset by the user, points to the implied input signal
|
||||||
return self.exp.hwif.get_implied_prop_input_identifier(field, "decr")
|
return self.exp.hwif.get_implied_prop_input_identifier(field, "decr")
|
||||||
|
|
||||||
def get_counter_decrvalue(self, field: 'FieldNode') -> str:
|
def get_counter_decrvalue(self, field: 'FieldNode') -> Union[SVInt, str]:
|
||||||
"""
|
"""
|
||||||
Return the string that represents the field's decrement value
|
Return the string that represents the field's decrement value
|
||||||
"""
|
"""
|
||||||
@@ -156,7 +157,7 @@ class FieldLogic:
|
|||||||
return self.exp.hwif.get_implied_prop_input_identifier(field, "decrvalue")
|
return self.exp.hwif.get_implied_prop_input_identifier(field, "decrvalue")
|
||||||
return "1'b1"
|
return "1'b1"
|
||||||
|
|
||||||
def get_counter_decrsaturate_value(self, field: 'FieldNode') -> str:
|
def get_counter_decrsaturate_value(self, field: 'FieldNode') -> Union[SVInt, str]:
|
||||||
prop_value = field.get_property('decrsaturate')
|
prop_value = field.get_property('decrsaturate')
|
||||||
if prop_value is True:
|
if prop_value is True:
|
||||||
return f"{field.width}'d0"
|
return f"{field.width}'d0"
|
||||||
@@ -168,7 +169,7 @@ class FieldLogic:
|
|||||||
"""
|
"""
|
||||||
return field.get_property('decrsaturate') is not False
|
return field.get_property('decrsaturate') is not False
|
||||||
|
|
||||||
def get_counter_decrthreshold_value(self, field: 'FieldNode') -> str:
|
def get_counter_decrthreshold_value(self, field: 'FieldNode') -> Union[SVInt, str]:
|
||||||
prop_value = field.get_property('decrthreshold')
|
prop_value = field.get_property('decrthreshold')
|
||||||
if isinstance(prop_value, bool):
|
if isinstance(prop_value, bool):
|
||||||
# No explicit value set. use min
|
# No explicit value set. use min
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class HWSet(NextStateConditional):
|
|||||||
identifier = self.exp.hwif.get_implied_prop_input_identifier(field, "hwset")
|
identifier = self.exp.hwif.get_implied_prop_input_identifier(field, "hwset")
|
||||||
else:
|
else:
|
||||||
# signal or field
|
# signal or field
|
||||||
identifier = self.exp.dereferencer.get_value(prop)
|
identifier = str(self.exp.dereferencer.get_value(prop))
|
||||||
return identifier
|
return identifier
|
||||||
|
|
||||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||||
@@ -50,7 +50,7 @@ class HWClear(NextStateConditional):
|
|||||||
identifier = self.exp.hwif.get_implied_prop_input_identifier(field, "hwclr")
|
identifier = self.exp.hwif.get_implied_prop_input_identifier(field, "hwclr")
|
||||||
else:
|
else:
|
||||||
# signal or field
|
# signal or field
|
||||||
identifier = self.exp.dereferencer.get_value(prop)
|
identifier = str(self.exp.dereferencer.get_value(prop))
|
||||||
return identifier
|
return identifier
|
||||||
|
|
||||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class AlwaysWrite(NextStateConditional):
|
|||||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||||
hwmask = field.get_property('hwmask')
|
hwmask = field.get_property('hwmask')
|
||||||
hwenable = field.get_property('hwenable')
|
hwenable = field.get_property('hwenable')
|
||||||
I = self.exp.hwif.get_input_identifier(field)
|
I = str(self.exp.hwif.get_input_identifier(field))
|
||||||
R = self.exp.field_logic.get_storage_identifier(field)
|
R = self.exp.field_logic.get_storage_identifier(field)
|
||||||
if hwmask is not None:
|
if hwmask is not None:
|
||||||
M = self.exp.dereferencer.get_value(hwmask)
|
M = self.exp.dereferencer.get_value(hwmask)
|
||||||
@@ -55,7 +55,7 @@ class WEWrite(AlwaysWrite):
|
|||||||
identifier = self.exp.hwif.get_implied_prop_input_identifier(field, "we")
|
identifier = self.exp.hwif.get_implied_prop_input_identifier(field, "we")
|
||||||
else:
|
else:
|
||||||
# signal or field
|
# signal or field
|
||||||
identifier = self.exp.dereferencer.get_value(prop)
|
identifier = str(self.exp.dereferencer.get_value(prop))
|
||||||
return identifier
|
return identifier
|
||||||
|
|
||||||
class WELWrite(AlwaysWrite):
|
class WELWrite(AlwaysWrite):
|
||||||
@@ -73,5 +73,5 @@ class WELWrite(AlwaysWrite):
|
|||||||
identifier = self.exp.hwif.get_implied_prop_input_identifier(field, "wel")
|
identifier = self.exp.hwif.get_implied_prop_input_identifier(field, "wel")
|
||||||
else:
|
else:
|
||||||
# signal or field
|
# signal or field
|
||||||
identifier = self.exp.dereferencer.get_value(prop)
|
identifier = str(self.exp.dereferencer.get_value(prop))
|
||||||
return f"!{identifier}"
|
return f"!{identifier}"
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
from typing import TYPE_CHECKING, Union, Set, Dict, Optional, TextIO, Type, List
|
from typing import TYPE_CHECKING, Union, Optional, TextIO
|
||||||
|
|
||||||
from systemrdl.node import AddrmapNode, SignalNode, FieldNode, RegNode, AddressableNode
|
from systemrdl.node import AddrmapNode, SignalNode, FieldNode, RegNode, AddressableNode
|
||||||
from systemrdl.rdltypes import PropertyReference, UserEnum
|
from systemrdl.rdltypes import PropertyReference
|
||||||
|
|
||||||
from ..utils import get_indexed_path
|
from ..utils import get_indexed_path
|
||||||
from ..identifier_filter import kw_filter as kwf
|
from ..identifier_filter import kw_filter as kwf
|
||||||
|
from ..sv_int import SVInt
|
||||||
|
|
||||||
from .generators import InputStructGenerator_Hier, OutputStructGenerator_Hier
|
from .generators import InputStructGenerator_Hier, OutputStructGenerator_Hier
|
||||||
from .generators import InputStructGenerator_TypeScope, OutputStructGenerator_TypeScope
|
from .generators import InputStructGenerator_TypeScope, OutputStructGenerator_TypeScope
|
||||||
@@ -127,7 +128,11 @@ class Hwif:
|
|||||||
return obj.is_hw_readable
|
return obj.is_hw_readable
|
||||||
|
|
||||||
|
|
||||||
def get_input_identifier(self, obj: Union[FieldNode, SignalNode, PropertyReference]) -> str:
|
def get_input_identifier(
|
||||||
|
self,
|
||||||
|
obj: Union[FieldNode, SignalNode, PropertyReference],
|
||||||
|
width: Optional[int] = None,
|
||||||
|
) -> Union[SVInt, str]:
|
||||||
"""
|
"""
|
||||||
Returns the identifier string that best represents the input object.
|
Returns the identifier string that best represents the input object.
|
||||||
|
|
||||||
@@ -143,7 +148,7 @@ class Hwif:
|
|||||||
next_value = obj.get_property('next')
|
next_value = obj.get_property('next')
|
||||||
if next_value is not None:
|
if next_value is not None:
|
||||||
# 'next' property replaces the inferred input signal
|
# 'next' property replaces the inferred input signal
|
||||||
return self.exp.dereferencer.get_value(next_value)
|
return self.exp.dereferencer.get_value(next_value, width)
|
||||||
# Otherwise, use inferred
|
# Otherwise, use inferred
|
||||||
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"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from systemrdl.walker import WalkerAction
|
|||||||
|
|
||||||
from ..struct_generator import RDLFlatStructGenerator
|
from ..struct_generator import RDLFlatStructGenerator
|
||||||
from ..identifier_filter import kw_filter as kwf
|
from ..identifier_filter import kw_filter as kwf
|
||||||
from ..utils import get_sv_int
|
from ..sv_int import SVInt
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from systemrdl.node import Node, SignalNode, AddressableNode, RegfileNode
|
from systemrdl.node import Node, SignalNode, AddressableNode, RegfileNode
|
||||||
@@ -289,7 +289,7 @@ class EnumGenerator:
|
|||||||
|
|
||||||
lines = []
|
lines = []
|
||||||
for enum_member in user_enum:
|
for enum_member in user_enum:
|
||||||
lines.append(f" {prefix}__{enum_member.name} = {get_sv_int(enum_member.value)}")
|
lines.append(f" {prefix}__{enum_member.name} = {SVInt(enum_member.value)}")
|
||||||
|
|
||||||
return (
|
return (
|
||||||
"typedef enum {\n"
|
"typedef enum {\n"
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING, Union
|
||||||
|
|
||||||
from systemrdl.node import AddrmapNode, RegNode, FieldNode, SignalNode
|
from systemrdl.node import AddrmapNode, RegNode, SignalNode
|
||||||
|
|
||||||
from .storage_generator import RBufStorageStructGenerator
|
from .storage_generator import RBufStorageStructGenerator
|
||||||
from .implementation_generator import RBufLogicGenerator
|
from .implementation_generator import RBufLogicGenerator
|
||||||
from ..utils import get_indexed_path
|
from ..utils import get_indexed_path
|
||||||
|
from ..sv_int import SVInt
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from ..exporter import RegblockExporter
|
from ..exporter import RegblockExporter
|
||||||
@@ -47,12 +48,12 @@ class ReadBuffering:
|
|||||||
elif isinstance(trigger, SignalNode):
|
elif isinstance(trigger, SignalNode):
|
||||||
s = self.exp.dereferencer.get_value(trigger)
|
s = self.exp.dereferencer.get_value(trigger)
|
||||||
if trigger.get_property('activehigh'):
|
if trigger.get_property('activehigh'):
|
||||||
return s
|
return str(s)
|
||||||
else:
|
else:
|
||||||
return f"~{s}"
|
return f"~{s}"
|
||||||
else:
|
else:
|
||||||
# Trigger is a field or propref bit
|
# Trigger is a field or propref bit
|
||||||
return self.exp.dereferencer.get_value(trigger)
|
return str(self.exp.dereferencer.get_value(trigger))
|
||||||
|
|
||||||
def get_rbuf_data(self, node: RegNode) -> str:
|
def get_rbuf_data(self, node: RegNode) -> str:
|
||||||
return "rbuf_storage." + get_indexed_path(self.top_node, node) + ".data"
|
return "rbuf_storage." + get_indexed_path(self.top_node, node) + ".data"
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ from systemrdl.walker import WalkerAction
|
|||||||
|
|
||||||
from ..forloop_generator import RDLForLoopGenerator, LoopBody
|
from ..forloop_generator import RDLForLoopGenerator, LoopBody
|
||||||
|
|
||||||
|
from ..utils import do_bitswap, do_slice
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from ..exporter import RegblockExporter
|
from ..exporter import RegblockExporter
|
||||||
|
|
||||||
@@ -147,7 +149,7 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator):
|
|||||||
value = self.exp.dereferencer.get_value(field)
|
value = self.exp.dereferencer.get_value(field)
|
||||||
if field.msb < field.lsb:
|
if field.msb < field.lsb:
|
||||||
# Field gets bitswapped since it is in [low:high] orientation
|
# Field gets bitswapped since it is in [low:high] orientation
|
||||||
value = f"{{<<{{{value}}}}}"
|
value = do_bitswap(value)
|
||||||
|
|
||||||
self.add_content(f"assign readback_array[{self.current_offset_str}][{field.high}:{field.low}] = {rd_strb} ? {value} : '0;")
|
self.add_content(f"assign readback_array[{self.current_offset_str}][{field.high}:{field.low}] = {rd_strb} ? {value} : '0;")
|
||||||
|
|
||||||
@@ -223,9 +225,9 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator):
|
|||||||
f_low = field.width - 1 - f_low
|
f_low = field.width - 1 - f_low
|
||||||
f_high = field.width - 1 - f_high
|
f_high = field.width - 1 - f_high
|
||||||
f_low, f_high = f_high, f_low
|
f_low, f_high = f_high, f_low
|
||||||
value = f"{{<<{{{self.exp.dereferencer.get_value(field)}[{f_high}:{f_low}]}}}}"
|
value = do_bitswap(do_slice(self.exp.dereferencer.get_value(field), f_high, f_low))
|
||||||
else:
|
else:
|
||||||
value = self.exp.dereferencer.get_value(field) + f"[{f_high}:{f_low}]"
|
value = do_slice(self.exp.dereferencer.get_value(field), f_high, f_low)
|
||||||
|
|
||||||
self.add_content(f"assign readback_array[{self.current_offset_str}][{r_high}:{r_low}] = {rd_strb} ? {value} : '0;")
|
self.add_content(f"assign readback_array[{self.current_offset_str}][{r_high}:{r_low}] = {rd_strb} ? {value} : '0;")
|
||||||
bidx = accesswidth
|
bidx = accesswidth
|
||||||
@@ -234,7 +236,7 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator):
|
|||||||
value = self.exp.dereferencer.get_value(field)
|
value = self.exp.dereferencer.get_value(field)
|
||||||
if field.msb < field.lsb:
|
if field.msb < field.lsb:
|
||||||
# Field gets bitswapped since it is in [low:high] orientation
|
# Field gets bitswapped since it is in [low:high] orientation
|
||||||
value = f"{{<<{{{value}}}}}"
|
value = do_bitswap(value)
|
||||||
self.add_content(f"assign readback_array[{self.current_offset_str}][{field.high}:{field.low}] = {rd_strb} ? {value} : '0;")
|
self.add_content(f"assign readback_array[{self.current_offset_str}][{field.high}:{field.low}] = {rd_strb} ? {value} : '0;")
|
||||||
bidx = field.high + 1
|
bidx = field.high + 1
|
||||||
|
|
||||||
@@ -299,7 +301,7 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator):
|
|||||||
value = self.exp.dereferencer.get_value(field)
|
value = self.exp.dereferencer.get_value(field)
|
||||||
if field.msb < field.lsb:
|
if field.msb < field.lsb:
|
||||||
# Field gets bitswapped since it is in [low:high] orientation
|
# Field gets bitswapped since it is in [low:high] orientation
|
||||||
value = f"{{<<{{{value}}}}}"
|
value = do_bitswap(value)
|
||||||
|
|
||||||
self.add_content(f"assign readback_array[{self.current_offset_str}][{high}:{low}] = {rd_strb} ? {value} : '0;")
|
self.add_content(f"assign readback_array[{self.current_offset_str}][{high}:{low}] = {rd_strb} ? {value} : '0;")
|
||||||
|
|
||||||
@@ -328,9 +330,9 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator):
|
|||||||
f_high = field.width - 1 - f_high
|
f_high = field.width - 1 - f_high
|
||||||
f_low, f_high = f_high, f_low
|
f_low, f_high = f_high, f_low
|
||||||
|
|
||||||
value = f"{{<<{{{self.exp.dereferencer.get_value(field)}[{f_high}:{f_low}]}}}}"
|
value = do_bitswap(do_slice(self.exp.dereferencer.get_value(field), f_high, f_low))
|
||||||
else:
|
else:
|
||||||
value = self.exp.dereferencer.get_value(field) + f"[{f_high}:{f_low}]"
|
value = do_slice(self.exp.dereferencer.get_value(field), f_high, f_low)
|
||||||
|
|
||||||
self.add_content(f"assign readback_array[{self.current_offset_str}][{r_high}:{r_low}] = {rd_strb} ? {value} : '0;")
|
self.add_content(f"assign readback_array[{self.current_offset_str}][{r_high}:{r_low}] = {rd_strb} ? {value} : '0;")
|
||||||
|
|
||||||
@@ -358,9 +360,9 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator):
|
|||||||
f_high = field.width - 1 - f_high
|
f_high = field.width - 1 - f_high
|
||||||
f_low, f_high = f_high, f_low
|
f_low, f_high = f_high, f_low
|
||||||
|
|
||||||
value = f"{{<<{{{self.exp.dereferencer.get_value(field)}[{f_high}:{f_low}]}}}}"
|
value = do_bitswap(do_slice(self.exp.dereferencer.get_value(field), f_high, f_low))
|
||||||
else:
|
else:
|
||||||
value = self.exp.dereferencer.get_value(field) + f"[{f_high}:{f_low}]"
|
value = do_slice(self.exp.dereferencer.get_value(field), f_high, f_low)
|
||||||
|
|
||||||
self.add_content(f"assign readback_array[{self.current_offset_str}][{r_high}:{r_low}] = {rd_strb} ? {value} : '0;")
|
self.add_content(f"assign readback_array[{self.current_offset_str}][{r_high}:{r_low}] = {rd_strb} ? {value} : '0;")
|
||||||
|
|
||||||
|
|||||||
17
src/peakrdl_regblock/sv_int.py
Normal file
17
src/peakrdl_regblock/sv_int.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
class SVInt:
|
||||||
|
def __init__(self, value: int, width: Optional[int] = None) -> None:
|
||||||
|
self.value = value
|
||||||
|
self.width = width
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
if self.width is not None:
|
||||||
|
# Explicit width
|
||||||
|
return f"{self.width}'h{self.value:x}"
|
||||||
|
elif self.value.bit_length() > 32:
|
||||||
|
# SV standard only enforces that unsized literals shall be at least 32-bits
|
||||||
|
# To support larger literals, they need to be sized explicitly
|
||||||
|
return f"{self.value.bit_length()}'h{self.value:x}"
|
||||||
|
else:
|
||||||
|
return f"'h{self.value:x}"
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
import re
|
import re
|
||||||
from typing import Match, Union, Optional
|
from typing import Match, Union
|
||||||
|
|
||||||
from systemrdl.rdltypes.references import PropertyReference
|
from systemrdl.rdltypes.references import PropertyReference
|
||||||
from systemrdl.node import Node, AddrmapNode
|
from systemrdl.node import Node, AddrmapNode
|
||||||
|
|
||||||
from .identifier_filter import kw_filter as kwf
|
from .identifier_filter import kw_filter as kwf
|
||||||
|
from .sv_int import SVInt
|
||||||
|
|
||||||
def get_indexed_path(top_node: Node, target_node: Node) -> str:
|
def get_indexed_path(top_node: Node, target_node: Node) -> str:
|
||||||
"""
|
"""
|
||||||
@@ -65,13 +66,36 @@ def ref_is_internal(top_node: AddrmapNode, ref: Union[Node, PropertyReference])
|
|||||||
# This is considerd internal for this exporter
|
# This is considerd internal for this exporter
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def get_sv_int(n: int, width: Optional[int]=None) -> str:
|
|
||||||
if width is not None:
|
def do_slice(value: Union[SVInt, str], high: int, low: int) -> Union[SVInt, str]:
|
||||||
# Explicit width
|
if isinstance(value, str):
|
||||||
return f"{width}'h{n:x}"
|
# If string, assume this is an identifier. Append bit-slice
|
||||||
elif n.bit_length() > 32:
|
if high == low:
|
||||||
# SV standard only enforces that unsized literals shall be at least 32-bits
|
return f"{value}[{low}]"
|
||||||
# To support larger literals, they need to be sized explicitly
|
else:
|
||||||
return f"{n.bit_length()}'h{n:x}"
|
return f"{value}[{high}:{low}]"
|
||||||
else:
|
else:
|
||||||
return f"'h{n:x}"
|
# it is an SVInt literal. Slice it down
|
||||||
|
mask = (1 << (high + 1)) - 1
|
||||||
|
v = (value.value & mask) >> low
|
||||||
|
|
||||||
|
if value.width is not None:
|
||||||
|
w = high - low + 1
|
||||||
|
else:
|
||||||
|
w = None
|
||||||
|
|
||||||
|
return SVInt(v, w)
|
||||||
|
|
||||||
|
def do_bitswap(value: Union[SVInt, str]) -> Union[SVInt, str]:
|
||||||
|
if isinstance(value, str):
|
||||||
|
# If string, assume this is an identifier. Wrap in a streaming operator
|
||||||
|
return "{<<{" + value + "}}"
|
||||||
|
else:
|
||||||
|
# it is an SVInt literal. bitswap it
|
||||||
|
assert value.width is not None # width must be known!
|
||||||
|
v = value.value
|
||||||
|
vswap = 0
|
||||||
|
for _ in range(value.width):
|
||||||
|
vswap = (vswap << 1) + (v & 1)
|
||||||
|
v >>= 1
|
||||||
|
return SVInt(vswap, value.width)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ from systemrdl.node import AddrmapNode, RegNode, FieldNode, SignalNode
|
|||||||
from .storage_generator import WBufStorageStructGenerator
|
from .storage_generator import WBufStorageStructGenerator
|
||||||
from .implementation_generator import WBufLogicGenerator
|
from .implementation_generator import WBufLogicGenerator
|
||||||
from ..utils import get_indexed_path
|
from ..utils import get_indexed_path
|
||||||
|
from ..sv_int import SVInt
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from ..exporter import RegblockExporter
|
from ..exporter import RegblockExporter
|
||||||
@@ -42,7 +43,7 @@ class WriteBuffering:
|
|||||||
prefix = self.get_wbuf_prefix(node)
|
prefix = self.get_wbuf_prefix(node)
|
||||||
return f"{prefix}.pending && {self.get_trigger(node)}"
|
return f"{prefix}.pending && {self.get_trigger(node)}"
|
||||||
|
|
||||||
def get_raw_trigger(self, node: 'RegNode') -> str:
|
def get_raw_trigger(self, node: 'RegNode') -> Union[SVInt, str]:
|
||||||
trigger = node.get_property('wbuffer_trigger')
|
trigger = node.get_property('wbuffer_trigger')
|
||||||
|
|
||||||
if isinstance(trigger, RegNode):
|
if isinstance(trigger, RegNode):
|
||||||
@@ -67,7 +68,7 @@ class WriteBuffering:
|
|||||||
# Trigger is a field or propref bit
|
# Trigger is a field or propref bit
|
||||||
return self.exp.dereferencer.get_value(trigger)
|
return self.exp.dereferencer.get_value(trigger)
|
||||||
|
|
||||||
def get_trigger(self, node: Union[RegNode, FieldNode]) -> str:
|
def get_trigger(self, node: Union[RegNode, FieldNode]) -> Union[SVInt, str]:
|
||||||
if isinstance(node, FieldNode):
|
if isinstance(node, FieldNode):
|
||||||
node = node.parent
|
node = node.parent
|
||||||
trigger = node.get_property('wbuffer_trigger')
|
trigger = node.get_property('wbuffer_trigger')
|
||||||
|
|||||||
@@ -90,4 +90,22 @@ addrmap top {
|
|||||||
} counter_reg;
|
} counter_reg;
|
||||||
counter_reg.f1_cnt->incr = r_reg2.f1->swacc;
|
counter_reg.f1_cnt->incr = r_reg2.f1->swacc;
|
||||||
counter_reg.f2_cnt->incr = r_reg2.f2->swacc;
|
counter_reg.f2_cnt->incr = r_reg2.f2->swacc;
|
||||||
|
|
||||||
|
reg {
|
||||||
|
regwidth = 32;
|
||||||
|
accesswidth = 16;
|
||||||
|
default sw=r;
|
||||||
|
default hw=r;
|
||||||
|
|
||||||
|
field {} f1[31:0] = 0x1234_5678;
|
||||||
|
} r_reg3;
|
||||||
|
|
||||||
|
reg {
|
||||||
|
regwidth = 32;
|
||||||
|
accesswidth = 16;
|
||||||
|
default sw=r;
|
||||||
|
default hw=r;
|
||||||
|
|
||||||
|
field {} f1[0:31] = 0x1234_5678;
|
||||||
|
} r_reg4;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -108,4 +108,14 @@
|
|||||||
// counter_reg
|
// counter_reg
|
||||||
cpuif.assert_read('h30, 16'h0204);
|
cpuif.assert_read('h30, 16'h0204);
|
||||||
|
|
||||||
|
// r_reg3
|
||||||
|
cpuif.assert_read('h34, 16'h5678);
|
||||||
|
cpuif.assert_read('h36, 16'h1234);
|
||||||
|
assert(cb.hwif_out.r_reg3.f1.value == 32'h12345678);
|
||||||
|
|
||||||
|
// r_reg4
|
||||||
|
cpuif.assert_read('h38, 16'h2C48);
|
||||||
|
cpuif.assert_read('h3A, 16'h1E6A);
|
||||||
|
assert(cb.hwif_out.r_reg4.f1.value == 32'h12345678);
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Reference in New Issue
Block a user