2019-09-17 01:28:36 +08:00
|
|
|
from migen import *
|
|
|
|
from migen.genlib.cdc import MultiReg
|
|
|
|
from migen.genlib.io import DifferentialOutput, DifferentialInput, DDROutput
|
|
|
|
from misoc.cores.liteeth_mini.mac.crc import LiteEthMACCRCEngine
|
|
|
|
|
|
|
|
from artiq.gateware.rtio import rtlink
|
2020-08-22 19:47:01 +08:00
|
|
|
from .fastlink import SerDes, SerInterface
|
2019-09-17 01:28:36 +08:00
|
|
|
|
|
|
|
|
|
|
|
class Fastino(Module):
|
2020-03-06 00:13:40 +08:00
|
|
|
def __init__(self, pins, pins_n, log2_width=0):
|
|
|
|
width = 1 << log2_width
|
2019-09-17 01:28:36 +08:00
|
|
|
self.rtlink = rtlink.Interface(
|
2020-03-06 00:13:40 +08:00
|
|
|
rtlink.OInterface(data_width=max(16*width, 32),
|
|
|
|
address_width=8,
|
2019-09-17 01:28:36 +08:00
|
|
|
enable_replace=False),
|
2020-08-22 19:47:01 +08:00
|
|
|
rtlink.IInterface(data_width=14))
|
2019-09-17 01:28:36 +08:00
|
|
|
|
2020-08-22 19:47:01 +08:00
|
|
|
self.submodules.serializer = SerDes(
|
|
|
|
n_data=8, t_clk=7, d_clk=0b1100011,
|
|
|
|
n_frame=14, n_crc=12, poly=0x80f)
|
|
|
|
self.submodules.intf = SerInterface(pins, pins_n)
|
|
|
|
self.comb += [
|
|
|
|
Cat(self.intf.data[:-1]).eq(Cat(self.serializer.data[:-1])),
|
|
|
|
self.serializer.data[-1].eq(self.intf.data[-1]),
|
|
|
|
]
|
|
|
|
|
|
|
|
# dac data words
|
|
|
|
dacs = [Signal(16) for i in range(32)]
|
2021-10-07 21:47:08 +08:00
|
|
|
|
2020-08-22 19:47:01 +08:00
|
|
|
header = Record([
|
|
|
|
("cfg", 4),
|
|
|
|
("leds", 8),
|
2021-10-07 21:47:08 +08:00
|
|
|
("typ", 1),
|
|
|
|
("reserved", 7),
|
2020-08-22 19:47:01 +08:00
|
|
|
("addr", 4),
|
|
|
|
("enable", len(dacs)),
|
|
|
|
])
|
2021-10-07 21:47:08 +08:00
|
|
|
assert len(Cat(header.raw_bits(), dacs)) == len(self.serializer.payload)
|
2020-08-22 19:47:01 +08:00
|
|
|
|
|
|
|
# # #
|
2019-09-17 01:28:36 +08:00
|
|
|
|
|
|
|
# Support staging DAC data (in `dacs`) by writing to the
|
2020-03-06 00:13:40 +08:00
|
|
|
# DAC RTIO addresses, if a channel is not "held" by its
|
2019-09-17 01:28:36 +08:00
|
|
|
# bit in `hold` the next frame will contain the update.
|
|
|
|
# For the DACs held, the update is triggered by setting the
|
|
|
|
# corresponding bit in `update`. Update is self-clearing.
|
|
|
|
# This enables atomic DAC updates synchronized to a frame edge.
|
|
|
|
#
|
2020-03-06 00:13:40 +08:00
|
|
|
# The `log2_width=0` RTIO layout uses one DAC channel per RTIO address
|
|
|
|
# and a dense RTIO address space. The RTIO words are narrow.
|
|
|
|
# (32 bit compared to 512) and few-channel updates are efficient.
|
|
|
|
# There is the least amount of DAC state tracking in kernels,
|
2019-09-17 01:28:36 +08:00
|
|
|
# at the cost of more DMA and RTIO data ((n*(32+32+64) vs
|
|
|
|
# 32+32*16+64))
|
2020-03-06 00:13:40 +08:00
|
|
|
#
|
|
|
|
# Other `log2_width` (up to `log2_width=5) settings pack multiple
|
|
|
|
# (in powers of two) DAC channels into one group and
|
|
|
|
# into one RTIO write.
|
|
|
|
# The RTIO data width increases accordingly. The `log2_width`
|
|
|
|
# LSBs of the RTIO address for a DAC channel write must be zero and the
|
|
|
|
# address space is sparse.
|
2019-09-17 01:28:36 +08:00
|
|
|
|
2020-08-22 19:47:01 +08:00
|
|
|
hold = Signal.like(header.enable)
|
2021-10-07 21:47:08 +08:00
|
|
|
continuous = Signal.like(header.enable)
|
|
|
|
cic_config = Signal(16)
|
2019-09-17 01:28:36 +08:00
|
|
|
|
2020-08-22 19:47:01 +08:00
|
|
|
read_regs = Array([Signal.like(self.serializer.readback)
|
|
|
|
for _ in range(1 << len(header.addr))])
|
2019-09-17 01:28:36 +08:00
|
|
|
|
|
|
|
cases = {
|
|
|
|
# update
|
2021-10-07 21:47:08 +08:00
|
|
|
0x20: [
|
|
|
|
header.enable.eq(self.rtlink.o.data),
|
|
|
|
header.typ.eq(0),
|
|
|
|
],
|
2019-09-17 01:28:36 +08:00
|
|
|
# hold
|
|
|
|
0x21: hold.eq(self.rtlink.o.data),
|
|
|
|
# cfg
|
2020-08-22 19:47:01 +08:00
|
|
|
0x22: header.cfg.eq(self.rtlink.o.data),
|
2019-09-17 01:28:36 +08:00
|
|
|
# leds
|
2020-08-22 19:47:01 +08:00
|
|
|
0x23: header.leds.eq(self.rtlink.o.data),
|
2021-10-07 21:47:08 +08:00
|
|
|
# reserved bits
|
2020-08-22 19:47:01 +08:00
|
|
|
0x24: header.reserved.eq(self.rtlink.o.data),
|
2021-10-07 21:47:08 +08:00
|
|
|
# force continuous DAC updates
|
|
|
|
0x25: continuous.eq(self.rtlink.o.data),
|
|
|
|
# interpolator configuration stage
|
|
|
|
0x26: cic_config.eq(self.rtlink.o.data),
|
|
|
|
# interpolator update flags
|
|
|
|
0x27: [
|
|
|
|
header.enable.eq(self.rtlink.o.data),
|
|
|
|
header.typ.eq(1),
|
|
|
|
],
|
2019-09-17 01:28:36 +08:00
|
|
|
}
|
2020-08-22 19:47:01 +08:00
|
|
|
for i in range(0, len(dacs), width):
|
2019-09-17 01:28:36 +08:00
|
|
|
cases[i] = [
|
2020-08-22 19:47:01 +08:00
|
|
|
Cat(dacs[i:i + width]).eq(self.rtlink.o.data),
|
2021-10-07 21:47:08 +08:00
|
|
|
[If(~hold[i + j] & (header.typ == 0),
|
2020-08-22 19:47:01 +08:00
|
|
|
header.enable[i + j].eq(1),
|
2020-03-06 00:13:40 +08:00
|
|
|
) for j in range(width)]
|
2019-09-17 01:28:36 +08:00
|
|
|
]
|
|
|
|
|
2021-10-07 21:47:08 +08:00
|
|
|
self.comb += [
|
|
|
|
If(header.typ == 0,
|
|
|
|
self.serializer.payload.eq(Cat(header.raw_bits(), dacs)),
|
|
|
|
).Else(
|
|
|
|
self.serializer.payload.eq(Cat(header.raw_bits(), Replicate(cic_config, len(dacs)))),
|
|
|
|
),
|
|
|
|
]
|
|
|
|
|
2019-09-17 01:28:36 +08:00
|
|
|
self.sync.rio_phy += [
|
|
|
|
If(self.serializer.stb,
|
2021-10-07 21:47:08 +08:00
|
|
|
header.typ.eq(0),
|
|
|
|
header.enable.eq(continuous),
|
2020-08-22 19:47:01 +08:00
|
|
|
read_regs[header.addr].eq(self.serializer.readback),
|
|
|
|
header.addr.eq(header.addr + 1),
|
2019-09-17 01:28:36 +08:00
|
|
|
),
|
2021-10-07 21:47:08 +08:00
|
|
|
If(self.rtlink.o.stb,
|
|
|
|
Case(self.rtlink.o.address, cases),
|
2019-09-17 01:28:36 +08:00
|
|
|
),
|
|
|
|
]
|
|
|
|
|
|
|
|
self.sync.rtio += [
|
|
|
|
self.rtlink.i.stb.eq(self.rtlink.o.stb &
|
|
|
|
self.rtlink.o.address[-1]),
|
|
|
|
self.rtlink.i.data.eq(
|
|
|
|
read_regs[self.rtlink.o.address[:-1]]),
|
|
|
|
]
|