-
Notifications
You must be signed in to change notification settings - Fork 7
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 PacketStream protocol. #85
base: main
Are you sure you want to change the base?
Conversation
0669c0c
to
ee9e485
Compare
e11179f
to
919bb9b
Compare
The motivation here is a bit unclear to me. The documentation says
However the "data" in question appears to be only bytes. Presumably there is a specific use-case in mind here but it is not clear to me what it is; network packets, perhaps? It seems to me like ideally protocols in |
This protocol was indeed specifically created for a hardware-based MAC/IP/UDP stack (which will soon be coming to |
@bgamari It was discussed with @lmbollen whether to make the payload polymorphic. In theory there isn't anything that currently really looks at the payload so it would not be super hard to do add a type variable for the payload. But in my experience working with packetized streams there usually is not a sane way to have an interior type. You are almost certainly only dealing with fragments, these will generally not have a clear structure at the scope of a single cycle. The structure comes from the fragments together. Do you have some concrete idea how you see a packet stream packet with a non-byte oriented payload? I'm not against the idea but just don't see the advantage. |
This is my experience too. In particular, any protocol that has byte enables (including the interface of block RAMs) are a pain to deal with if they're not having bits/bytes/bitvector as an interior type. Still, ADTs are the killer feature of Clash IMO, so perhaps we should also offer API compatible versions without byte enables. |
4d8758d
to
a38eadc
Compare
56ab0c0
to
dac1bc4
Compare
2e0e8df
to
bfe1baf
Compare
97b5f56
to
a90007a
Compare
* Support zero-byte transfers * Add utility that merges trailing zero-byte transfers * Make PacketStream test framework more flexible Now allows users to: - Set the distribution of abort generation themselves; - Choose whether to generate zero-byte packets; - Choose whether to generate trailing zero-byte transfers. * Converters: remove expensive operations `mod` and `*` are removed.
Reverted back to the old version where all M2S outputs are registered, but now also handles arbitrary metadata and output data widths bigger than 1 that divide the input data width. Zero-byte transfers are always preserved. This new version reduces the LUT resource usage by half compared to the old registered version, because of a mux with 1 selector bit (optimal) being inferred by synthesizers for the next state computation, instead of a mux with 2 selector bits.
Now correctly drops packets that are too big to fit in the content FIFO in 'Backpressure' mode.
Forcing bytes in PacketStream _data to be 0x00 turned out to be too restrictive. Allowing them to be undefined makes a lot of components more efficient: depacketizers, packetizers, dropTail, and upConverter. It also strengthens the test framework as we can now force un-enabled bytes to throw an error when evaluated.
6c02bde
to
2e9557d
Compare
Adds a generic component which enforces packets to be a certain length, which is extracted from the metadata. Packets that are too small are aborted. This is useful for higher-level network protocols such as IP and UDP.
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.
lgtm modulo some minor remarks.
-- Bitmask used for data equality. If the index of a data byte is larger | ||
-- than or equal to the size of `_data`, it is a null byte and must be | ||
-- disregarded in the equality check. | ||
mask = case _last t1 of | ||
Nothing -> repeat False | ||
Just size -> imap (\i _ -> resize i >= size) (_data t1) | ||
|
||
dataEq = case compareSNat (SNat @dataWidth) d0 of | ||
SNatLE -> True | ||
SNatGT -> | ||
leToPlus @1 @dataWidth | ||
$ fold (&&) | ||
$ zipWith3 (\b1 b2 isNull -> isNull || b1 == b2) (_data t1) (_data t2) mask |
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.
Why is the mask inverted?
__NB__: assumes that packets are longer than @ceil(n / dataWidth)@ transfers. | ||
If this is not the case, the behaviour of this component is undefined. | ||
-} |
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.
Behavior when this assumption is false should not affect other packets and at the least abort the packet.
forall (dwIn :: Nat) (dwOut :: Nat) (meta :: Type) (dom :: Domain) (n :: Nat). | ||
(HiddenClockResetEnable dom) => | ||
(1 <= dwIn) => | ||
(1 <= dwOut) => |
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.
Replace with dwIn * n
{- | Test the depacketizer with varying datawidth and number of bytes in the header, | ||
with metaIn = () and toMetaOut = const. | ||
-} | ||
depacketizerPropertyGenerator :: | ||
forall | ||
(dataWidth :: Nat) | ||
(headerBytes :: Nat). | ||
(1 <= dataWidth) => | ||
(1 <= headerBytes) => | ||
SNat dataWidth -> | ||
SNat headerBytes -> | ||
Property | ||
depacketizerPropertyGenerator SNat SNat = | ||
idWithModelSingleDomain | ||
@System | ||
defExpectOptions{eoSampleMax = 1000, eoStopAfterEmpty = 1000} | ||
(genPackets 1 4 (genValidPacket defPacketOptions (pure ()) (Range.linear 0 30))) | ||
(exposeClockResetEnable (depacketizerModel const)) | ||
(exposeClockResetEnable ckt) | ||
where | ||
ckt :: | ||
(HiddenClockResetEnable System) => | ||
Circuit | ||
(PacketStream System dataWidth ()) | ||
(PacketStream System dataWidth (Vec headerBytes (BitVector 8))) | ||
ckt = depacketizerC const |
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.
Can you also test the behavior of metadata fields?
-- | Collect mode for `packetArbiterC` | ||
data ArbiterMode | ||
= -- | Collect in a round-robin fashion. Fair and cheaper than `Parallel`. | ||
RoundRobin | ||
| -- | Check components in parallel. This mode has a higher throughput, but is | ||
-- biased towards the last source and also slightly more expensive. | ||
Parallel |
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.
Reuse existing type from Df
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.
Just checked it, it's not quite the same. roundrobinCollect
also has a NoSkip
mode:
Collect in a roundrobin fashion. If a component does not produce data, wait until it does.
We could add this mode to the arbiter as well.
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.
That would be nice, let's try to make it uniform
- Removed dangerous leZeroIsZero (could cause type checker to break) - Added source argument to nullByte - Improved documentation of unsafeAbortOnBackpressureC - Remove use of bitCoerce if only pack or unpack is required - Removed M2SNoMeta in favour of PacketStreamM2S n ()
f17fbcf
to
1d2f936
Compare
Todos:
forceResetSanity
to async fifo