From 49684c1990d0cf271f388664b65f0f4c8793f3c1 Mon Sep 17 00:00:00 2001
From: Donald Sebastian Leung
Date: Fri, 25 Sep 2020 16:27:56 +0800
Subject: [PATCH] Add partial implementation of CRI interface
---
rtio/cri.py | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 126 insertions(+)
diff --git a/rtio/cri.py b/rtio/cri.py
index e69de29..edd8701 100644
--- a/rtio/cri.py
+++ b/rtio/cri.py
@@ -0,0 +1,126 @@
+from nmigen import *
+from nmigen.utils import *
+from nmigen.hdl.rec import *
+
+"""Common RTIO Interface"""
+
+# CRI write happens in 3 cycles:
+# 1. set timestamp and channel
+# 2. set other payload elements and issue write command
+# 3. check status
+
+commands = {
+ "nop": 0,
+ "write": 1,
+ # i_status should have the "wait for status" bit set until
+ # an event is available, or timestamp is reached.
+ "read": 2,
+ # targets must assert o_buffer_space_valid in response
+ # to this command
+ "get_buffer_space": 3
+}
+
+
+layout = [
+ ("cmd", 2, DIR_FANOUT),
+ # 8 MSBs of chan_sel = routing destination
+ # 16 LSBs of chan_sel = channel within the destination
+ ("chan_sel", 24, DIR_FANOUT),
+
+ ("o_timestamp", 64, DIR_FANOUT),
+ ("o_data", 512, DIR_FANOUT),
+ ("o_address", 8, DIR_FANOUT),
+ # o_status bits:
+ # <0:wait> <1:underflow> <2:destination unreachable>
+ ("o_status", 3, DIR_FANIN),
+
+ # pessimistic estimate of the number of outputs events that can be
+ # written without waiting.
+ # this feature may be omitted on systems without DRTIO.
+ ("o_buffer_space_valid", 1, DIR_FANIN),
+ ("o_buffer_space", 16, DIR_FANIN),
+
+ ("i_timeout", 64, DIR_FANOUT),
+ ("i_data", 32, DIR_FANIN),
+ ("i_timestamp", 64, DIR_FANIN),
+ # i_status bits:
+ # <0:wait for event (command timeout)> <1:overflow> <2:wait for status>
+ # <3:destination unreachable>
+ # <0> and <1> are mutually exclusive. <1> has higher priority.
+ ("i_status", 4, DIR_FANIN),
+]
+
+class Interface(Record):
+ def __init__(self, **kwargs):
+ super().__init__(layout, **kwargs)
+
+# Skip KernelInitiator for now
+
+class CRIDecoder(Elaboratable):
+ def __init__(self, slaves=2, master=None, mode="async", enable_routing=False):
+ if isinstance(slaves, int):
+ slaves = [Interface() for _ in range(slaves)]
+ if master is None:
+ master = Interface()
+ self.slaves = slaves
+ self.master = master
+ self.mode = mode
+ self.enable_routing = enable_routing
+
+ def elaborate(self, platform):
+ m = Module()
+
+ # routing
+ if self.enable_routing:
+ destination_unreachable = Interface()
+ m.d.comb += destination_unreachable.o_status.eq(4)
+ m.d.comb += destination_unreachable.i_status.eq(8)
+ self.slaves = self.slaves[:]
+ self.slaves.append(destination_unreachable)
+ target_len = 2 ** (len(slaves) - 1).bit_length()
+ self.slaves += [destination_unreachable] * (target_len - len(slaves))
+
+ slave_bits = bits_for(len(self.slaves) - 1)
+ selected = Signal(slave_bits)
+
+ if self.enable_routing:
+ routing_table = Memory(slave_bits, 256)
+
+ if self.mode == "async":
+ rtp_decoder_rdport = routing_table.read_port()
+ rtp_decoder_wrport = routing_table.write_port()
+ elif self.mode == "sync":
+ rtp_decoder_rdport = routing_table.read_port(clock_domain="rtio")
+ rtp_decoder_wrport = routing_tables.write_port(clock_domain="rtio")
+ else:
+ raise ValueError
+ m.submodules.rtp_decoder_rdport = rtp_decoder_rdport
+ m.submodules.rtp_decoder_wrport = rtp_decoder_wrport
+ m.d.comb += rtp_decoder_rdport.addr.eq(self.master.chan_sel[16:])
+ m.d.comb += selected.eq(rtp_decoder_rdport.data)
+ else:
+ m.d.sync += selected.eq(self.master.chan_sel[16:])
+
+ # master -> slave
+ for n, slave in enumerate(self.slaves):
+ for name, size, direction in layout:
+ if direction == DIR_FANOUT and name != "cmd":
+ m.d.comb += getattr(slave, name).eq(getattr(self.master, name))
+ with m.If(selected == n):
+ m.d.comb += slave.cmd.eq(self.master.cmd)
+
+ # slave -> master
+ with m.Switch(selected):
+ for n, slave in enumerate(self.slaves):
+ with m.Case(n):
+ for name, size, direction in layout:
+ if direction == DIR_FANIN:
+ m.d.comb += getattr(self.master, name).eq(getattr(slave, name))
+
+ return m
+
+# TODO: CRISwitch
+
+# TODO: CRIInterconnectShared
+
+# TODO: RoutingTableAccess