-
Notifications
You must be signed in to change notification settings - Fork 71
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for optional axis_tstrb #60
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,9 +35,10 @@ | |
|
||
|
||
class AxiStreamFrame: | ||
def __init__(self, tdata=b'', tkeep=None, tid=None, tdest=None, tuser=None, tx_complete=None): | ||
def __init__(self, tdata=b'', tkeep=None, tstrb=None, tid=None, tdest=None, tuser=None, tx_complete=None): | ||
self.tdata = bytearray() | ||
self.tkeep = None | ||
self.tstrb = None | ||
self.tid = None | ||
self.tdest = None | ||
self.tuser = None | ||
|
@@ -52,6 +53,8 @@ def __init__(self, tdata=b'', tkeep=None, tid=None, tdest=None, tuser=None, tx_c | |
self.tdata = list(tdata.tdata) | ||
if tdata.tkeep is not None: | ||
self.tkeep = list(tdata.tkeep) | ||
if tdata.tstrb is not None: | ||
self.tstrb = list(tdata.tstrb) | ||
if tdata.tid is not None: | ||
if type(tdata.tid) in (int, bool): | ||
self.tid = tdata.tid | ||
|
@@ -73,12 +76,14 @@ def __init__(self, tdata=b'', tkeep=None, tid=None, tdest=None, tuser=None, tx_c | |
elif type(tdata) in (bytes, bytearray): | ||
self.tdata = bytearray(tdata) | ||
self.tkeep = tkeep | ||
self.tstrb = tstrb | ||
self.tid = tid | ||
self.tdest = tdest | ||
self.tuser = tuser | ||
else: | ||
self.tdata = list(tdata) | ||
self.tkeep = tkeep | ||
self.tstrb = tstrb | ||
self.tid = tid | ||
self.tdest = tdest | ||
self.tuser = tuser | ||
|
@@ -95,6 +100,11 @@ def normalize(self): | |
else: | ||
self.tkeep = [1]*n | ||
|
||
if self.tstrb is not None: | ||
self.tstrb = self.tstrb[:n] + [self.tstrb[-1]]*(n-len(self.tstrb)) | ||
else: | ||
self.tstrb = self.tkeep | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is deliberate. If
It also means the invalid state of |
||
|
||
if self.tid is not None: | ||
if type(self.tid) in (int, bool): | ||
self.tid = [self.tid]*n | ||
|
@@ -128,6 +138,8 @@ def compact(self): | |
del self.tdata[k] | ||
if k < len(self.tkeep): | ||
del self.tkeep[k] | ||
if k < len(self.tstrb): | ||
del self.tstrb[k] | ||
if k < len(self.tid): | ||
del self.tid[k] | ||
if k < len(self.tdest): | ||
|
@@ -172,6 +184,10 @@ def __eq__(self, other): | |
if self.tkeep != other.tkeep: | ||
return False | ||
|
||
if self.tstrb is not None and other.tstrb is not None: | ||
if self.tstrb != other.tstrb: | ||
return False | ||
|
||
if self.tid is not None and other.tid is not None: | ||
if type(self.tid) in (int, bool) and type(other.tid) is list: | ||
for k in other.tid: | ||
|
@@ -214,6 +230,7 @@ def __repr__(self): | |
return ( | ||
f"{type(self).__name__}(tdata={self.tdata!r}, " | ||
f"tkeep={self.tkeep!r}, " | ||
f"tstrb={self.tstrb!r}, " | ||
f"tid={self.tid!r}, " | ||
f"tdest={self.tdest!r}, " | ||
f"tuser={self.tuser!r}, " | ||
|
@@ -234,7 +251,7 @@ def __bytes__(self): | |
class AxiStreamBus(Bus): | ||
|
||
_signals = ["tdata"] | ||
_optional_signals = ["tvalid", "tready", "tlast", "tkeep", "tid", "tdest", "tuser"] | ||
_optional_signals = ["tvalid", "tready", "tlast", "tkeep", "tstrb", "tid", "tdest", "tuser"] | ||
|
||
def __init__(self, entity=None, prefix=None, **kwargs): | ||
super().__init__(entity, prefix, self._signals, optional_signals=self._optional_signals, **kwargs) | ||
|
@@ -251,7 +268,7 @@ def from_prefix(cls, entity, prefix, **kwargs): | |
class AxiStreamBase(Reset): | ||
|
||
_signals = ["tdata"] | ||
_optional_signals = ["tvalid", "tready", "tlast", "tkeep", "tid", "tdest", "tuser"] | ||
_optional_signals = ["tvalid", "tready", "tlast", "tkeep", "tstrb", "tid", "tdest", "tuser"] | ||
|
||
_type = "base" | ||
|
||
|
@@ -306,6 +323,14 @@ def __init__(self, bus, clock, reset=None, reset_active_level=True, | |
self.byte_lanes = len(self.bus.tkeep) | ||
if byte_size is not None or byte_lanes is not None: | ||
raise ValueError("Cannot specify byte_size or byte_lanes if tkeep is connected") | ||
if hasattr(self.bus, "tstrb") and (len(self.bus.tstrb) != self.byte_lanes): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If both tkeep and tstrb are provided, then they should be the same size. |
||
raise ValueError("tstrb must be the same width as tkeep") | ||
|
||
elif hasattr(self.bus, "tstrb"): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tstrb only provided, we can use that to get byte_lanes. Also reflected in the docs |
||
self.byte_lanes = len(self.bus.tstrb) | ||
if byte_size is not None or byte_lanes is not None: | ||
raise ValueError("Cannot specify byte_size or byte_lanes if tstrb is connected") | ||
|
||
else: | ||
if byte_lanes is not None: | ||
self.byte_lanes = byte_lanes | ||
|
@@ -484,6 +509,8 @@ def _handle_reset(self, state): | |
self.bus.tlast.value = 0 | ||
if hasattr(self.bus, "tkeep"): | ||
self.bus.tkeep.value = 0 | ||
if hasattr(self.bus, "tstrb"): | ||
self.bus.tstrb.value = 0 | ||
if hasattr(self.bus, "tid"): | ||
self.bus.tid.value = 0 | ||
if hasattr(self.bus, "tdest"): | ||
|
@@ -505,6 +532,7 @@ async def _run(self): | |
has_tvalid = hasattr(self.bus, "tvalid") | ||
has_tlast = hasattr(self.bus, "tlast") | ||
has_tkeep = hasattr(self.bus, "tkeep") | ||
has_tstrb = hasattr(self.bus, "tstrb") | ||
has_tid = hasattr(self.bus, "tid") | ||
has_tdest = hasattr(self.bus, "tdest") | ||
has_tuser = hasattr(self.bus, "tuser") | ||
|
@@ -536,13 +564,15 @@ async def _run(self): | |
tdata_val = 0 | ||
tlast_val = 0 | ||
tkeep_val = 0 | ||
tstrb_val = 0 | ||
tid_val = 0 | ||
tdest_val = 0 | ||
tuser_val = 0 | ||
|
||
for offset in range(self.byte_lanes): | ||
tdata_val |= (frame.tdata[frame_offset] & self.byte_mask) << (offset * self.byte_size) | ||
tkeep_val |= (frame.tkeep[frame_offset] & 1) << offset | ||
tstrb_val |= (frame.tstrb[frame_offset] & 1) << offset | ||
tid_val = frame.tid[frame_offset] | ||
tdest_val = frame.tdest[frame_offset] | ||
tuser_val = frame.tuser[frame_offset] | ||
|
@@ -563,6 +593,8 @@ async def _run(self): | |
self.bus.tlast.value = tlast_val | ||
if has_tkeep: | ||
self.bus.tkeep.value = tkeep_val | ||
if has_tstrb: | ||
self.bus.tstrb.value = tstrb_val | ||
if has_tid: | ||
self.bus.tid.value = tid_val | ||
if has_tdest: | ||
|
@@ -673,6 +705,7 @@ async def _run(self): | |
has_tvalid = hasattr(self.bus, "tvalid") | ||
has_tlast = hasattr(self.bus, "tlast") | ||
has_tkeep = hasattr(self.bus, "tkeep") | ||
has_tstrb = hasattr(self.bus, "tstrb") | ||
has_tid = hasattr(self.bus, "tid") | ||
has_tdest = hasattr(self.bus, "tdest") | ||
has_tuser = hasattr(self.bus, "tuser") | ||
|
@@ -691,16 +724,18 @@ async def _run(self): | |
if tready_sample and tvalid_sample: | ||
if not frame: | ||
if self.byte_size == 8: | ||
frame = AxiStreamFrame(bytearray(), [], [], [], []) | ||
frame = AxiStreamFrame(bytearray(), [], [], [], [], []) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These caught me out, and may catch out users. the API change may justify a major version uplift There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I could mitigate this by adjusting the ordering of |
||
else: | ||
frame = AxiStreamFrame([], [], [], [], []) | ||
frame = AxiStreamFrame([], [], [], [], [], []) | ||
frame.sim_time_start = get_sim_time() | ||
self.active = True | ||
|
||
for offset in range(self.byte_lanes): | ||
frame.tdata.append((self.bus.tdata.value.integer >> (offset * self.byte_size)) & self.byte_mask) | ||
if has_tkeep: | ||
frame.tkeep.append((self.bus.tkeep.value.integer >> offset) & 1) | ||
if has_tstrb: | ||
frame.tstrb.append((self.bus.tstrb.value.integer >> offset) & 1) | ||
if has_tid: | ||
frame.tid.append(self.bus.tid.value.integer) | ||
if has_tdest: | ||
|
@@ -772,6 +807,7 @@ async def _run(self): | |
has_tvalid = hasattr(self.bus, "tvalid") | ||
has_tlast = hasattr(self.bus, "tlast") | ||
has_tkeep = hasattr(self.bus, "tkeep") | ||
has_tstrb = hasattr(self.bus, "tstrb") | ||
has_tid = hasattr(self.bus, "tid") | ||
has_tdest = hasattr(self.bus, "tdest") | ||
has_tuser = hasattr(self.bus, "tuser") | ||
|
@@ -792,16 +828,18 @@ async def _run(self): | |
if tready_sample and tvalid_sample: | ||
if not frame: | ||
if self.byte_size == 8: | ||
frame = AxiStreamFrame(bytearray(), [], [], [], []) | ||
frame = AxiStreamFrame(bytearray(), [], [], [], [], []) | ||
else: | ||
frame = AxiStreamFrame([], [], [], [], []) | ||
frame = AxiStreamFrame([], [], [], [], [], []) | ||
frame.sim_time_start = get_sim_time() | ||
self.active = True | ||
|
||
for offset in range(self.byte_lanes): | ||
frame.tdata.append((self.bus.tdata.value.integer >> (offset * self.byte_size)) & self.byte_mask) | ||
if has_tkeep: | ||
frame.tkeep.append((self.bus.tkeep.value.integer >> offset) & 1) | ||
if has_tstrb: | ||
frame.tstrb.append((self.bus.tstrb.value.integer >> offset) & 1) | ||
if has_tid: | ||
frame.tid.append(self.bus.tid.value.integer) | ||
if has_tdest: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The open question is if tstrb should be checked here, to validate the validity of the tkeep, tstrb combination.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely should check for protocol violations when possible. The question is what to do: I'm thinking logging a warning or error would be appropriate, but an exception or assert I suppose could also be reasonable. Perhaps the best solution would be to have an option for enabling protocol assertions somewhere, which would generate exceptions instead of log messages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But, I suppose what we could do is roll with the log messages for now and then think about some config options for this sort of thing separately.