Implement write buffering (#22)
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from systemrdl.rdltypes import PropertyReference, PrecedenceType, InterruptType
|
||||
from systemrdl.node import Node
|
||||
from systemrdl.rdltypes import PrecedenceType, InterruptType
|
||||
|
||||
from .bases import AssignmentPrecedence, NextStateConditional
|
||||
from . import sw_onread
|
||||
@@ -186,19 +185,35 @@ class FieldLogic:
|
||||
"""
|
||||
w_modifiable = field.is_sw_writable
|
||||
r_modifiable = (field.get_property('onread') is not None)
|
||||
strb = self.exp.dereferencer.get_access_strobe(field)
|
||||
buffer_writes = field.parent.get_property('buffer_writes')
|
||||
|
||||
if w_modifiable and not r_modifiable:
|
||||
# assert swmod only on sw write
|
||||
return f"{strb} && decoded_req_is_wr"
|
||||
if buffer_writes:
|
||||
# Write strobe arrives from buffer layer instead
|
||||
wstrb = self.exp.write_buffering.get_write_strobe(field)
|
||||
return wstrb
|
||||
else:
|
||||
# Unbuffered. Use decoder strobe directly
|
||||
astrb = self.exp.dereferencer.get_access_strobe(field)
|
||||
return f"{astrb} && decoded_req_is_wr"
|
||||
|
||||
if w_modifiable and r_modifiable:
|
||||
# assert swmod on all sw actions
|
||||
return strb
|
||||
# assert swmod on both sw read and write
|
||||
if buffer_writes:
|
||||
astrb = self.exp.dereferencer.get_access_strobe(field)
|
||||
wstrb = self.exp.write_buffering.get_write_strobe(field)
|
||||
rstrb = f"{astrb} && !decoded_req_is_wr"
|
||||
return f"{wstrb} || {rstrb}"
|
||||
else:
|
||||
# Unbuffered. Use decoder strobe directly
|
||||
astrb = self.exp.dereferencer.get_access_strobe(field)
|
||||
return astrb
|
||||
|
||||
if not w_modifiable and r_modifiable:
|
||||
# assert swmod only on sw read
|
||||
return f"{strb} && !decoded_req_is_wr"
|
||||
astrb = self.exp.dereferencer.get_access_strobe(field)
|
||||
return f"{astrb} && !decoded_req_is_wr"
|
||||
|
||||
# Not sw modifiable
|
||||
return "1'b0"
|
||||
|
||||
@@ -85,7 +85,7 @@ class FieldLogicGenerator(RDLForLoopGenerator):
|
||||
super().__init__()
|
||||
self.field_logic = field_logic
|
||||
self.exp = field_logic.exp
|
||||
self.field_storage_template = self.field_logic.exp.jj_env.get_template(
|
||||
self.field_storage_template = self.exp.jj_env.get_template(
|
||||
"field_logic/templates/field_storage.sv"
|
||||
)
|
||||
self.intr_fields = [] # type: List[FieldNode]
|
||||
|
||||
@@ -15,60 +15,104 @@ class _OnWrite(NextStateConditional):
|
||||
return field.is_sw_writable and field.get_property('onwrite') == self.onwritetype
|
||||
|
||||
def get_predicate(self, field: 'FieldNode') -> str:
|
||||
strb = self.exp.dereferencer.get_access_strobe(field)
|
||||
if field.parent.get_property('buffer_writes'):
|
||||
# Is buffered write. Use alternate strobe
|
||||
wstrb = self.exp.write_buffering.get_write_strobe(field)
|
||||
|
||||
if field.get_property('swwe') or field.get_property('swwel'):
|
||||
# dereferencer will wrap swwel complement if necessary
|
||||
qualifier = self.exp.dereferencer.get_field_propref_value(field, 'swwe')
|
||||
return f"{strb} && decoded_req_is_wr && {qualifier}"
|
||||
if field.get_property('swwe') or field.get_property('swwel'):
|
||||
# dereferencer will wrap swwel complement if necessary
|
||||
qualifier = self.exp.dereferencer.get_field_propref_value(field, 'swwe')
|
||||
return f"{wstrb} && {qualifier}"
|
||||
|
||||
return f"{strb} && decoded_req_is_wr"
|
||||
return wstrb
|
||||
else:
|
||||
# is regular register
|
||||
strb = self.exp.dereferencer.get_access_strobe(field)
|
||||
|
||||
def _wbus_bitslice(self, field: 'FieldNode', subword_idx: int) -> str:
|
||||
if field.get_property('swwe') or field.get_property('swwel'):
|
||||
# dereferencer will wrap swwel complement if necessary
|
||||
qualifier = self.exp.dereferencer.get_field_propref_value(field, 'swwe')
|
||||
return f"{strb} && decoded_req_is_wr && {qualifier}"
|
||||
|
||||
return f"{strb} && decoded_req_is_wr"
|
||||
|
||||
def _wbus_bitslice(self, field: 'FieldNode', subword_idx: int = 0) -> str:
|
||||
# Get the source bitslice range from the internal cpuif's data bus
|
||||
# For normal fields this ends up passing-through the field's low/high
|
||||
# values unchanged.
|
||||
# For fields within a wide register (accesswidth < regwidth), low/high
|
||||
# may be shifted down and clamped depending on which sub-word is being accessed
|
||||
accesswidth = field.parent.get_property('accesswidth')
|
||||
if field.parent.get_property('buffer_writes'):
|
||||
# register is buffered.
|
||||
# write buffer is the full width of the register. no need to deal with subwords
|
||||
high = field.high
|
||||
low = field.low
|
||||
if field.msb < field.lsb:
|
||||
# slice is for an msb0 field.
|
||||
# mirror it
|
||||
regwidth = field.parent.get_property('regwidth')
|
||||
low = regwidth - 1 - low
|
||||
high = regwidth - 1 - high
|
||||
low, high = high, low
|
||||
else:
|
||||
# Regular non-buffered register
|
||||
# For normal fields this ends up passing-through the field's low/high
|
||||
# values unchanged.
|
||||
# For fields within a wide register (accesswidth < regwidth), low/high
|
||||
# may be shifted down and clamped depending on which sub-word is being accessed
|
||||
accesswidth = field.parent.get_property('accesswidth')
|
||||
|
||||
# Shift based on subword
|
||||
high = field.high - (subword_idx * accesswidth)
|
||||
low = field.low - (subword_idx * accesswidth)
|
||||
# Shift based on subword
|
||||
high = field.high - (subword_idx * accesswidth)
|
||||
low = field.low - (subword_idx * accesswidth)
|
||||
|
||||
# clamp to accesswidth
|
||||
high = max(min(high, accesswidth), 0)
|
||||
low = max(min(low, accesswidth), 0)
|
||||
# clamp to accesswidth
|
||||
high = max(min(high, accesswidth), 0)
|
||||
low = max(min(low, accesswidth), 0)
|
||||
|
||||
if field.msb < field.lsb:
|
||||
# slice is for an msb0 field.
|
||||
# mirror it
|
||||
bus_width = self.exp.cpuif.data_width
|
||||
low = bus_width - 1 - low
|
||||
high = bus_width - 1 - high
|
||||
low, high = high, low
|
||||
if field.msb < field.lsb:
|
||||
# slice is for an msb0 field.
|
||||
# mirror it
|
||||
bus_width = self.exp.cpuif.data_width
|
||||
low = bus_width - 1 - low
|
||||
high = bus_width - 1 - high
|
||||
low, high = high, low
|
||||
|
||||
return f"[{high}:{low}]"
|
||||
|
||||
def _wr_data(self, field: 'FieldNode', subword_idx: int=0) -> str:
|
||||
bslice = self._wbus_bitslice(field, subword_idx)
|
||||
|
||||
if field.msb < field.lsb:
|
||||
# Field gets bitswapped since it is in [low:high] orientation
|
||||
value = f"decoded_wr_data_bswap{bslice}"
|
||||
if field.parent.get_property('buffer_writes'):
|
||||
# Is buffered. Use value from write buffer
|
||||
# No need to check msb0 ordering. Bus is pre-swapped, and bitslice
|
||||
# accounts for it
|
||||
bslice = self._wbus_bitslice(field)
|
||||
wbuf_prefix = self.exp.write_buffering.get_wbuf_prefix(field)
|
||||
return wbuf_prefix + ".data" + bslice
|
||||
else:
|
||||
value = f"decoded_wr_data{bslice}"
|
||||
return value
|
||||
# Regular non-buffered register
|
||||
bslice = self._wbus_bitslice(field, subword_idx)
|
||||
|
||||
if field.msb < field.lsb:
|
||||
# Field gets bitswapped since it is in [low:high] orientation
|
||||
value = "decoded_wr_data_bswap" + bslice
|
||||
else:
|
||||
value = "decoded_wr_data" + bslice
|
||||
return value
|
||||
|
||||
def _wr_biten(self, field: 'FieldNode', subword_idx: int=0) -> str:
|
||||
bslice = self._wbus_bitslice(field, subword_idx)
|
||||
|
||||
if field.msb < field.lsb:
|
||||
# Field gets bitswapped since it is in [low:high] orientation
|
||||
value = f"decoded_wr_biten_bswap{bslice}"
|
||||
if field.parent.get_property('buffer_writes'):
|
||||
# Is buffered. Use value from write buffer
|
||||
# No need to check msb0 ordering. Bus is pre-swapped, and bitslice
|
||||
# accounts for it
|
||||
bslice = self._wbus_bitslice(field)
|
||||
wbuf_prefix = self.exp.write_buffering.get_wbuf_prefix(field)
|
||||
return wbuf_prefix + ".biten" + bslice
|
||||
else:
|
||||
value = f"decoded_wr_biten{bslice}"
|
||||
return value
|
||||
# Regular non-buffered register
|
||||
bslice = self._wbus_bitslice(field, subword_idx)
|
||||
|
||||
if field.msb < field.lsb:
|
||||
# Field gets bitswapped since it is in [low:high] orientation
|
||||
value = "decoded_wr_biten_bswap" + bslice
|
||||
else:
|
||||
value = "decoded_wr_biten" + bslice
|
||||
return value
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
accesswidth = field.parent.get_property("accesswidth")
|
||||
@@ -92,6 +136,7 @@ class _OnWrite(NextStateConditional):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
class WriteOneSet(_OnWrite):
|
||||
comment = "SW write 1 set"
|
||||
onwritetype = OnWriteType.woset
|
||||
|
||||
Reference in New Issue
Block a user