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:
Alex Mykyta
2023-10-24 22:50:41 -07:00
parent b5b1ba790e
commit 62518b318b
14 changed files with 147 additions and 62 deletions

View File

@@ -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

View File

@@ -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}"

View File

@@ -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

View File

@@ -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]:

View File

@@ -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}"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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;")

View 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}"

View File

@@ -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
return f"{n.bit_length()}'h{n:x}"
else: else:
return f"'h{n:x}" return f"{value}[{high}:{low}]"
else:
# 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)

View File

@@ -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')

View File

@@ -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;
}; };

View File

@@ -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 %}