Add partial implementation of CRI interface
This commit is contained in:
parent
1a83778590
commit
49684c1990
126
rtio/cri.py
126
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
|
Loading…
Reference in New Issue