From c2ee2fbdefc7e323b869d9ececf964e645f9a71a Mon Sep 17 00:00:00 2001
From: Donald Sebastian Leung
Date: Thu, 8 Oct 2020 11:06:35 +0800
Subject: [PATCH] Add rtio.sed.layouts
---
README.md | 2 +-
rtio/sed/layouts.py | 77 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 78 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 14cf50f..f6708aa 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@ Formally verified implementation of the ARTIQ RTIO core in nMigen
- [ ] Implement the core in nMigen
- - [x] `rtio.cri` (`Interface` and `CRIDecoder` only)
- - [x] `rtio.rtlink`
-- - [ ] `rtio.sed.layouts`
+- - [x] `rtio.sed.layouts`
- - [ ] `rtio.sed.output_network`
- - [ ] `rtio.sed.output_driver`
- [ ] Add suitable assertions for verification (BMC / unbounded proof?)
diff --git a/rtio/sed/layouts.py b/rtio/sed/layouts.py
index 8b13789..bdfb453 100644
--- a/rtio/sed/layouts.py
+++ b/rtio/sed/layouts.py
@@ -1 +1,78 @@
+from nmigen import *
+from nmigen.utils import *
+from nmigen.hdl.rec import *
+from rtio import rtlink
+
+def fifo_payload(channels):
+ address_width = max(rtlink.get_address_width(channel.interface.o)
+ for channel in channels)
+ data_width = max(rtlink.get_data_width(channel.interface.o)
+ for channel in channels)
+
+ layout = [
+ ("channel", bits_for(len(channels)-1)),
+ ("timestamp", 64)
+ ]
+ if address_width:
+ layout.append(("address", address_width))
+ if data_width:
+ layout.append(("data", data_width))
+
+ return layout
+
+
+def seqn_width(lane_count, fifo_depth):
+ # There must be a unique sequence number for every possible event in every FIFO.
+ # Plus 2 bits to detect and handle wraparounds.
+ return bits_for(lane_count*fifo_depth-1) + 2
+
+
+def fifo_ingress(seqn_width, layout_payload):
+ return [
+ ("we", 1, DIR_FANOUT),
+ ("writable", 1, DIR_FANIN),
+ ("seqn", seqn_width, DIR_FANOUT),
+ ("payload", [(a, b, DIR_FANOUT) for a, b in layout_payload])
+ ]
+
+
+def fifo_egress(seqn_width, layout_payload):
+ return [
+ ("re", 1, DIR_FANIN),
+ ("readable", 1, DIR_FANOUT),
+ ("seqn", seqn_width, DIR_FANOUT),
+ ("payload", [(a, b, DIR_FANOUT) for a, b in layout_payload])
+ ]
+
+
+# We use glbl_fine_ts_width in the output network so that collisions due
+# to insufficiently increasing timestamps are always reliably detected.
+# We can still have undetected collisions on the address by making it wrap
+# around, but those are more rare and easier to debug, and addresses are
+# not normally exposed directly to the ARTIQ user.
+def output_network_payload(channels, glbl_fine_ts_width):
+ address_width = max(rtlink.get_address_width(channel.interface.o)
+ for channel in channels)
+ data_width = max(rtlink.get_data_width(channel.interface.o)
+ for channel in channels)
+
+ layout = [("channel", bits_for(len(channels)-1))]
+ if glbl_fine_ts_width:
+ layout.append(("fine_ts", glbl_fine_ts_width))
+ if address_width:
+ layout.append(("address", address_width))
+ if data_width:
+ layout.append(("data", data_width))
+
+ return layout
+
+
+def output_network_node(seqn_width, layout_payload):
+ return [
+ ("valid", 1),
+ ("seqn", seqn_width),
+ ("replace_occured", 1),
+ ("nondata_replace_occured", 1),
+ ("payload", layout_payload)
+ ]