Implement write buffering (#22)

This commit is contained in:
Alex Mykyta
2022-10-24 21:49:47 -07:00
parent 808067fac9
commit 279a3c5788
29 changed files with 968 additions and 93 deletions

View File

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