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.walker import WalkerAction
|
||||
|
||||
from .utils import get_indexed_path, get_sv_int
|
||||
from .utils import get_indexed_path
|
||||
from .struct_generator import RDLStructGenerator
|
||||
from .forloop_generator import RDLForLoopGenerator
|
||||
from .identifier_filter import kw_filter as kwf
|
||||
from .sv_int import SVInt
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .exporter import RegblockExporter
|
||||
@@ -149,7 +150,7 @@ class DecodeLogicGenerator(RDLForLoopGenerator):
|
||||
# Is an external block
|
||||
addr_str = self._get_address_str(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"is_external |= {rhs};")
|
||||
return WalkerAction.SkipDescendants
|
||||
@@ -158,12 +159,12 @@ class DecodeLogicGenerator(RDLForLoopGenerator):
|
||||
|
||||
|
||||
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,
|
||||
self.addr_decode.exp.ds.addr_width
|
||||
)
|
||||
))
|
||||
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
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ from typing import TYPE_CHECKING, Union, Optional
|
||||
from systemrdl.node import AddrmapNode, FieldNode, SignalNode, RegNode, AddressableNode
|
||||
from systemrdl.rdltypes import PropertyReference
|
||||
|
||||
from .utils import get_sv_int
|
||||
from .sv_int import SVInt
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .exporter import RegblockExporter, DesignState
|
||||
@@ -38,7 +38,7 @@ class Dereferencer:
|
||||
def top_node(self) -> AddrmapNode:
|
||||
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
|
||||
with the object.
|
||||
@@ -52,20 +52,20 @@ class Dereferencer:
|
||||
"""
|
||||
if isinstance(obj, int):
|
||||
# Is a simple scalar value
|
||||
return get_sv_int(obj, width)
|
||||
return SVInt(obj, width)
|
||||
|
||||
if isinstance(obj, FieldNode):
|
||||
if obj.implements_storage:
|
||||
return self.field_logic.get_storage_identifier(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
|
||||
# must be a constant value as defined by its reset value
|
||||
reset_value = obj.get_property('reset')
|
||||
if reset_value is not None:
|
||||
return self.get_value(reset_value)
|
||||
return self.get_value(reset_value, obj.width)
|
||||
else:
|
||||
# No reset value defined!
|
||||
obj.env.msg.warning(
|
||||
@@ -76,11 +76,11 @@ class Dereferencer:
|
||||
|
||||
if isinstance(obj, SignalNode):
|
||||
# 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.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):
|
||||
return self.get_reg_propref_value(obj.node, obj.name)
|
||||
else:
|
||||
@@ -89,7 +89,12 @@ class Dereferencer:
|
||||
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.
|
||||
# Wrap with the appropriate Verilog reduction operator
|
||||
if prop_name == "anded":
|
||||
@@ -115,7 +120,7 @@ class Dereferencer:
|
||||
'reset',
|
||||
'resetsignal',
|
||||
}:
|
||||
return self.get_value(field.get_property(prop_name))
|
||||
return self.get_value(field.get_property(prop_name), width)
|
||||
|
||||
# Field Next
|
||||
if prop_name == "next":
|
||||
@@ -124,7 +129,7 @@ class Dereferencer:
|
||||
# unset by the user, points to the implied internal signal
|
||||
return self.field_logic.get_field_combo_identifier(field, "next")
|
||||
else:
|
||||
return self.get_value(prop_value)
|
||||
return self.get_value(prop_value, width)
|
||||
|
||||
# References to another component value, or an implied input
|
||||
if prop_name in {'hwclr', 'hwset'}:
|
||||
@@ -163,7 +168,7 @@ class Dereferencer:
|
||||
else:
|
||||
return f"!({self.get_value(prop_value)})"
|
||||
else:
|
||||
return self.get_value(prop_value)
|
||||
return self.get_value(prop_value, width)
|
||||
|
||||
if prop_name == "swacc":
|
||||
return self.field_logic.get_swacc_identifier(field)
|
||||
@@ -232,7 +237,7 @@ class Dereferencer:
|
||||
if isinstance(obj, SignalNode):
|
||||
s = self.get_value(obj)
|
||||
if obj.get_property('activehigh'):
|
||||
return s
|
||||
return str(s)
|
||||
else:
|
||||
return f"~{s}"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, Union
|
||||
|
||||
from systemrdl.rdltypes import PrecedenceType, InterruptType
|
||||
|
||||
@@ -11,6 +11,7 @@ from . import hw_set_clr
|
||||
from . import hw_interrupts
|
||||
|
||||
from ..utils import get_indexed_path
|
||||
from ..sv_int import SVInt
|
||||
|
||||
from .generators import CombinationalStructGenerator, FieldStorageStructGenerator, FieldLogicGenerator
|
||||
|
||||
@@ -99,12 +100,12 @@ class FieldLogic:
|
||||
"""
|
||||
prop_value = field.get_property('incr')
|
||||
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
|
||||
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
|
||||
"""
|
||||
@@ -115,7 +116,7 @@ class FieldLogic:
|
||||
return self.exp.hwif.get_implied_prop_input_identifier(field, "incrvalue")
|
||||
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')
|
||||
if prop_value is True:
|
||||
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
|
||||
|
||||
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')
|
||||
if isinstance(prop_value, bool):
|
||||
# No explicit value set. use max
|
||||
@@ -140,12 +141,12 @@ class FieldLogic:
|
||||
"""
|
||||
prop_value = field.get_property('decr')
|
||||
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
|
||||
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
|
||||
"""
|
||||
@@ -156,7 +157,7 @@ class FieldLogic:
|
||||
return self.exp.hwif.get_implied_prop_input_identifier(field, "decrvalue")
|
||||
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')
|
||||
if prop_value is True:
|
||||
return f"{field.width}'d0"
|
||||
@@ -168,7 +169,7 @@ class FieldLogic:
|
||||
"""
|
||||
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')
|
||||
if isinstance(prop_value, bool):
|
||||
# No explicit value set. use min
|
||||
|
||||
@@ -17,7 +17,7 @@ class HWSet(NextStateConditional):
|
||||
identifier = self.exp.hwif.get_implied_prop_input_identifier(field, "hwset")
|
||||
else:
|
||||
# signal or field
|
||||
identifier = self.exp.dereferencer.get_value(prop)
|
||||
identifier = str(self.exp.dereferencer.get_value(prop))
|
||||
return identifier
|
||||
|
||||
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")
|
||||
else:
|
||||
# signal or field
|
||||
identifier = self.exp.dereferencer.get_value(prop)
|
||||
identifier = str(self.exp.dereferencer.get_value(prop))
|
||||
return identifier
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
|
||||
@@ -24,7 +24,7 @@ class AlwaysWrite(NextStateConditional):
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
hwmask = field.get_property('hwmask')
|
||||
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)
|
||||
if hwmask is not None:
|
||||
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")
|
||||
else:
|
||||
# signal or field
|
||||
identifier = self.exp.dereferencer.get_value(prop)
|
||||
identifier = str(self.exp.dereferencer.get_value(prop))
|
||||
return identifier
|
||||
|
||||
class WELWrite(AlwaysWrite):
|
||||
@@ -73,5 +73,5 @@ class WELWrite(AlwaysWrite):
|
||||
identifier = self.exp.hwif.get_implied_prop_input_identifier(field, "wel")
|
||||
else:
|
||||
# signal or field
|
||||
identifier = self.exp.dereferencer.get_value(prop)
|
||||
identifier = str(self.exp.dereferencer.get_value(prop))
|
||||
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.rdltypes import PropertyReference, UserEnum
|
||||
from systemrdl.rdltypes import PropertyReference
|
||||
|
||||
from ..utils import get_indexed_path
|
||||
from ..identifier_filter import kw_filter as kwf
|
||||
from ..sv_int import SVInt
|
||||
|
||||
from .generators import InputStructGenerator_Hier, OutputStructGenerator_Hier
|
||||
from .generators import InputStructGenerator_TypeScope, OutputStructGenerator_TypeScope
|
||||
@@ -127,7 +128,11 @@ class Hwif:
|
||||
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.
|
||||
|
||||
@@ -143,7 +148,7 @@ class Hwif:
|
||||
next_value = obj.get_property('next')
|
||||
if next_value is not None:
|
||||
# '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
|
||||
path = get_indexed_path(self.top_node, obj)
|
||||
return "hwif_in." + path + ".next"
|
||||
|
||||
@@ -5,7 +5,7 @@ from systemrdl.walker import WalkerAction
|
||||
|
||||
from ..struct_generator import RDLFlatStructGenerator
|
||||
from ..identifier_filter import kw_filter as kwf
|
||||
from ..utils import get_sv_int
|
||||
from ..sv_int import SVInt
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from systemrdl.node import Node, SignalNode, AddressableNode, RegfileNode
|
||||
@@ -289,7 +289,7 @@ class EnumGenerator:
|
||||
|
||||
lines = []
|
||||
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 (
|
||||
"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 .implementation_generator import RBufLogicGenerator
|
||||
from ..utils import get_indexed_path
|
||||
from ..sv_int import SVInt
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..exporter import RegblockExporter
|
||||
@@ -47,12 +48,12 @@ class ReadBuffering:
|
||||
elif isinstance(trigger, SignalNode):
|
||||
s = self.exp.dereferencer.get_value(trigger)
|
||||
if trigger.get_property('activehigh'):
|
||||
return s
|
||||
return str(s)
|
||||
else:
|
||||
return f"~{s}"
|
||||
else:
|
||||
# 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:
|
||||
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 ..utils import do_bitswap, do_slice
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..exporter import RegblockExporter
|
||||
|
||||
@@ -147,7 +149,7 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator):
|
||||
value = self.exp.dereferencer.get_value(field)
|
||||
if field.msb < field.lsb:
|
||||
# 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;")
|
||||
|
||||
@@ -223,9 +225,9 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator):
|
||||
f_low = field.width - 1 - f_low
|
||||
f_high = field.width - 1 - f_high
|
||||
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:
|
||||
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;")
|
||||
bidx = accesswidth
|
||||
@@ -234,7 +236,7 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator):
|
||||
value = self.exp.dereferencer.get_value(field)
|
||||
if field.msb < field.lsb:
|
||||
# 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;")
|
||||
bidx = field.high + 1
|
||||
|
||||
@@ -299,7 +301,7 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator):
|
||||
value = self.exp.dereferencer.get_value(field)
|
||||
if field.msb < field.lsb:
|
||||
# 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;")
|
||||
|
||||
@@ -328,9 +330,9 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator):
|
||||
f_high = field.width - 1 - f_high
|
||||
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:
|
||||
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;")
|
||||
|
||||
@@ -358,9 +360,9 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator):
|
||||
f_high = field.width - 1 - f_high
|
||||
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:
|
||||
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;")
|
||||
|
||||
|
||||
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
|
||||
from typing import Match, Union, Optional
|
||||
from typing import Match, Union
|
||||
|
||||
from systemrdl.rdltypes.references import PropertyReference
|
||||
from systemrdl.node import Node, AddrmapNode
|
||||
|
||||
from .identifier_filter import kw_filter as kwf
|
||||
from .sv_int import SVInt
|
||||
|
||||
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
|
||||
return True
|
||||
|
||||
def get_sv_int(n: int, width: Optional[int]=None) -> str:
|
||||
if width is not None:
|
||||
# Explicit width
|
||||
return f"{width}'h{n:x}"
|
||||
elif n.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"{n.bit_length()}'h{n:x}"
|
||||
|
||||
def do_slice(value: Union[SVInt, str], high: int, low: int) -> Union[SVInt, str]:
|
||||
if isinstance(value, str):
|
||||
# If string, assume this is an identifier. Append bit-slice
|
||||
if high == low:
|
||||
return f"{value}[{low}]"
|
||||
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)
|
||||
|
||||
@@ -5,6 +5,7 @@ from systemrdl.node import AddrmapNode, RegNode, FieldNode, SignalNode
|
||||
from .storage_generator import WBufStorageStructGenerator
|
||||
from .implementation_generator import WBufLogicGenerator
|
||||
from ..utils import get_indexed_path
|
||||
from ..sv_int import SVInt
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..exporter import RegblockExporter
|
||||
@@ -42,7 +43,7 @@ class WriteBuffering:
|
||||
prefix = self.get_wbuf_prefix(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')
|
||||
|
||||
if isinstance(trigger, RegNode):
|
||||
@@ -67,7 +68,7 @@ class WriteBuffering:
|
||||
# Trigger is a field or propref bit
|
||||
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):
|
||||
node = node.parent
|
||||
trigger = node.get_property('wbuffer_trigger')
|
||||
|
||||
@@ -90,4 +90,22 @@ addrmap top {
|
||||
} counter_reg;
|
||||
counter_reg.f1_cnt->incr = r_reg2.f1->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
|
||||
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 %}
|
||||
|
||||
Reference in New Issue
Block a user