forked from M-Labs/artiq
phaser: ddb template, split crc
This commit is contained in:
parent
11c9def589
commit
bcefb06e19
|
@ -485,6 +485,18 @@ class PeripheralManager:
|
||||||
channel=rtio_offset)
|
channel=rtio_offset)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
def process_phaser(self, rtio_offset, peripheral):
|
||||||
|
self.gen("""
|
||||||
|
device_db["{name}"] = {{
|
||||||
|
"type": "local",
|
||||||
|
"module": "artiq.coredevice.phaser",
|
||||||
|
"class": "Phaser",
|
||||||
|
"arguments": {{"channel": 0x{channel:06x}}}
|
||||||
|
}}""",
|
||||||
|
name=self.get_name("phaser"),
|
||||||
|
channel=rtio_offset)
|
||||||
|
return 2
|
||||||
|
|
||||||
def process(self, rtio_offset, peripheral):
|
def process(self, rtio_offset, peripheral):
|
||||||
processor = getattr(self, "process_"+str(peripheral["type"]))
|
processor = getattr(self, "process_"+str(peripheral["type"]))
|
||||||
return processor(rtio_offset, peripheral)
|
return processor(rtio_offset, peripheral)
|
||||||
|
|
|
@ -30,6 +30,7 @@ class SerDes(Module):
|
||||||
n_marker = n_frame//2 + 1
|
n_marker = n_frame//2 + 1
|
||||||
n_body = n_word*n_frame - n_marker - n_crc
|
n_body = n_word*n_frame - n_marker - n_crc
|
||||||
t_miso = 0 # miso sampling latency TODO
|
t_miso = 0 # miso sampling latency TODO
|
||||||
|
assert n_crc % n_mosi == 0
|
||||||
|
|
||||||
# frame data
|
# frame data
|
||||||
self.payload = Signal(n_body)
|
self.payload = Signal(n_body)
|
||||||
|
@ -40,8 +41,10 @@ class SerDes(Module):
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
self.submodules.crc = LiteEthMACCRCEngine(
|
self.submodules.crca = LiteEthMACCRCEngine(
|
||||||
data_width=2*n_mosi, width=n_crc, polynom=poly)
|
data_width=n_mosi, width=n_crc, polynom=poly)
|
||||||
|
self.submodules.crcb = LiteEthMACCRCEngine(
|
||||||
|
data_width=n_mosi, width=n_crc, polynom=poly)
|
||||||
|
|
||||||
words_ = []
|
words_ = []
|
||||||
j = 0
|
j = 0
|
||||||
|
@ -71,15 +74,17 @@ class SerDes(Module):
|
||||||
# big shift register for mosi and
|
# big shift register for mosi and
|
||||||
sr = [Signal(t_frame, reset_less=True) for i in range(n_mosi)]
|
sr = [Signal(t_frame, reset_less=True) for i in range(n_mosi)]
|
||||||
assert len(Cat(sr)) == len(words)
|
assert len(Cat(sr)) == len(words)
|
||||||
sr_t = [sr[i % n_mosi][i//n_mosi] for i in range(len(words))]
|
crc_insert = ([d[1] for d in self.data[:-1]] +
|
||||||
data_t = ([d[0] for d in self.data[:-1]] +
|
[d[0] for d in self.data[:-1]])
|
||||||
[d[1] for d in self.data[:-1]])
|
crc_insert = Cat(crc_insert[-n_crc:])
|
||||||
miso_sr = Signal(t_frame, reset_less=True)
|
miso_sr = Signal(t_frame, reset_less=True)
|
||||||
miso_sr_next = Signal.like(miso_sr)
|
miso_sr_next = Signal.like(miso_sr)
|
||||||
self.comb += [
|
self.comb += [
|
||||||
self.stb.eq(i == t_frame//2 - 1),
|
self.stb.eq(i == t_frame//2 - 1),
|
||||||
# LiteETHMACCRCEngine takes data LSB first
|
# LiteETHMACCRCEngine takes data LSB first
|
||||||
self.crc.data.eq(Cat(reversed(sr_t[-2*n_mosi:]))),
|
self.crca.data.eq(Cat([sri[-1] for sri in sr[::-1]])),
|
||||||
|
self.crcb.data.eq(Cat([sri[-2] for sri in sr[::-1]])),
|
||||||
|
self.crcb.last.eq(self.crca.next),
|
||||||
miso_sr_next.eq(Cat(self.data[-1], miso_sr)),
|
miso_sr_next.eq(Cat(self.data[-1], miso_sr)),
|
||||||
]
|
]
|
||||||
self.sync.rio_phy += [
|
self.sync.rio_phy += [
|
||||||
|
@ -88,19 +93,20 @@ class SerDes(Module):
|
||||||
clk.eq(Cat(clk[-2:], clk)),
|
clk.eq(Cat(clk[-2:], clk)),
|
||||||
[sri.eq(Cat(C(0, 2), sri)) for sri in sr],
|
[sri.eq(Cat(C(0, 2), sri)) for sri in sr],
|
||||||
miso_sr.eq(miso_sr_next),
|
miso_sr.eq(miso_sr_next),
|
||||||
self.crc.last.eq(self.crc.next),
|
self.crca.last.eq(self.crcb.next),
|
||||||
i.eq(i + 1),
|
i.eq(i + 1),
|
||||||
If(self.stb,
|
If(self.stb,
|
||||||
i.eq(0),
|
i.eq(0),
|
||||||
clk.eq(clk.reset),
|
clk.eq(clk.reset),
|
||||||
self.crc.last.eq(0),
|
self.crca.last.eq(0),
|
||||||
# transpose, load
|
# transpose, load
|
||||||
[sri.eq(Cat(words[i::n_mosi])) for i, sri in enumerate(sr)],
|
[sri.eq(Cat(words[i::n_mosi])) for i, sri in enumerate(sr)],
|
||||||
# unload miso
|
# unload miso
|
||||||
self.readback.eq(Cat([miso_sr_next[t_miso + i*t_clk]
|
self.readback.eq(Cat([miso_sr_next[t_miso + i*t_clk]
|
||||||
for i in range(n_frame)])),
|
for i in range(n_frame)])),
|
||||||
# inject crc for the last cycle
|
# inject crc for the last cycle
|
||||||
Cat(data_t[-n_crc:]).eq(self.crc.next),
|
crc_insert.eq(self.crca.next if n_crc // n_mosi == 1
|
||||||
|
else self.crcb.next),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -114,14 +120,14 @@ class SerInterface(Module):
|
||||||
[pins_n.clk] + list(pins_n.mosi)):
|
[pins_n.clk] + list(pins_n.mosi)):
|
||||||
ddr = Signal()
|
ddr = Signal()
|
||||||
self.specials += [
|
self.specials += [
|
||||||
# d1 closer to q, LSB first
|
# d1 closer to q
|
||||||
DDROutput(d[1], d[0], ddr, ClockSignal("rio_phy")),
|
DDROutput(d[1], d[0], ddr, ClockSignal("rio_phy")),
|
||||||
DifferentialOutput(ddr, pp, pn),
|
DifferentialOutput(ddr, pp, pn),
|
||||||
]
|
]
|
||||||
ddr = Signal()
|
ddr = Signal()
|
||||||
self.specials += [
|
self.specials += [
|
||||||
DifferentialInput(pins.miso, pins_n.miso, ddr),
|
DifferentialInput(pins.miso, pins_n.miso, ddr),
|
||||||
# q1 closer to d, MSB first
|
# q1 closer to d
|
||||||
DDRInput(ddr, self.data[-1][1], self.data[-1][0],
|
DDRInput(ddr, self.data[-1][0], self.data[-1][1],
|
||||||
ClockSignal("rio_phy")),
|
ClockSignal("rio_phy")),
|
||||||
]
|
]
|
||||||
|
|
|
@ -16,27 +16,27 @@ class TestPhaser(unittest.TestCase):
|
||||||
def record_frame(self, frame):
|
def record_frame(self, frame):
|
||||||
clk = 0
|
clk = 0
|
||||||
marker = 0
|
marker = 0
|
||||||
state = "start"
|
stb = 0
|
||||||
while True:
|
while True:
|
||||||
|
if stb == 2:
|
||||||
|
frame.append((yield self.dut.data))
|
||||||
clk = (clk << 2) & 0xff
|
clk = (clk << 2) & 0xff
|
||||||
clk |= (yield self.dut.data[0])
|
clk |= (yield self.dut.data[0])
|
||||||
if clk == 0x0f:
|
if clk == 0x0f:
|
||||||
marker = (marker << 1) & 0x7f
|
marker = (marker << 1) & 0x7f
|
||||||
marker |= (yield self.dut.data[1]) & 1
|
marker |= (yield self.dut.data[1]) & 1
|
||||||
if marker >> 1 == 0x01:
|
if marker >> 1 == 0x01:
|
||||||
if state == "start":
|
stb += 1
|
||||||
state = "end"
|
if stb >= 3:
|
||||||
elif state == "end":
|
|
||||||
break
|
break
|
||||||
yield
|
yield
|
||||||
if state == "end":
|
|
||||||
data = yield from [(yield d) for d in self.dut.data]
|
|
||||||
frame.append(data)
|
|
||||||
|
|
||||||
def test_frame(self):
|
def test_frame(self):
|
||||||
frame = []
|
frame = []
|
||||||
|
self.dut.comb += self.dut.payload.eq((1 << len(self.dut.payload)) - 1)
|
||||||
run_simulation(self.dut, self.record_frame(frame),
|
run_simulation(self.dut, self.record_frame(frame),
|
||||||
clocks={n: 2 for n in ["sys", "rio", "rio_phy"]})
|
clocks={n: 2 for n in ["sys", "rio", "rio_phy"]},
|
||||||
|
vcd_name="fastlink.vcd")
|
||||||
self.assertEqual(len(frame), 8*10//2)
|
self.assertEqual(len(frame), 8*10//2)
|
||||||
self.assertEqual([d[0] for d in frame], [0, 0, 3, 3] * 10)
|
self.assertEqual([d[0] for d in frame], [0, 0, 3, 3] * 10)
|
||||||
self.assertEqual([d[1] & 1 for d in frame[4*4 - 1:10*4 - 1:4]],
|
self.assertEqual([d[1] & 1 for d in frame[4*4 - 1:10*4 - 1:4]],
|
||||||
|
|
Loading…
Reference in New Issue