Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 55 additions & 24 deletions crg.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,27 @@ def __init__(self, cd, async_reset):
rst_meta = Signal()
rst_unbuf = Signal()
self.specials += [
Instance("FDPE", p_INIT=1, i_D=0, i_PRE=async_reset,
i_CE=1, i_C=cd.clk, o_Q=rst_meta,
attr={"async_reg", "ars_ff1"}),
Instance("FDPE", p_INIT=1, i_D=rst_meta, i_PRE=async_reset,
i_CE=1, i_C=cd.clk, o_Q=rst_unbuf,
attr={"async_reg", "ars_ff2"}),
Instance("BUFG", i_I=rst_unbuf, o_O=cd.rst)
Instance(
"FDPE",
p_INIT=1,
i_D=0,
i_PRE=async_reset,
i_CE=1,
i_C=cd.clk,
o_Q=rst_meta,
attr={"async_reg", "ars_ff1"},
),
Instance(
"FDPE",
p_INIT=1,
i_D=rst_meta,
i_PRE=async_reset,
i_CE=1,
i_C=cd.clk,
o_Q=rst_unbuf,
attr={"async_reg", "ars_ff2"},
),
Instance("BUFG", i_I=rst_unbuf, o_O=cd.rst),
]


Expand All @@ -30,17 +44,19 @@ def __init__(self, platform, link=None):
self.clock_domains.cd_clk125 = ClockDomain(reset_less=True)

clk125 = platform.request("clk125_gtp")
platform.add_period_constraint(clk125, 8.)
platform.add_period_constraint(clk125, 8.0)
self.clk125 = Signal()
self.clk125_div2 = Signal()
self.specials += [
Instance("IBUFDS_GTE2",
Instance(
"IBUFDS_GTE2",
i_CEB=0,
i_I=clk125.p, i_IB=clk125.n,
i_I=clk125.p,
i_IB=clk125.n,
o_O=self.clk125,
o_ODIV2=self.clk125_div2),
Instance("BUFG",
i_I=self.clk125, o_O=self.cd_clk125.clk),
o_ODIV2=self.clk125_div2,
),
Instance("BUFG", i_I=self.clk125, o_O=self.cd_clk125.clk),
]
if link is not None:
self.clock_domains.cd_link = ClockDomain(reset_less=True)
Expand All @@ -54,27 +70,42 @@ def __init__(self, platform, link=None):
clk200 = Signal()
delay_rdy = Signal()
self.specials += [
Instance("MMCME2_BASE",
Instance(
"MMCME2_BASE",
p_BANDWIDTH="LOW",
p_CLKIN1_PERIOD=8. if link is None else 4.*8,
p_CLKFBOUT_MULT_F=8 if link is None else 4*8,
p_CLKIN1_PERIOD=8.0 if link is None else 4.0 * 8,
p_CLKFBOUT_MULT_F=8 if link is None else 4 * 8,
p_DIVCLK_DIVIDE=1,
i_CLKIN1=self.cd_clk125.clk if link is None else link,
i_CLKFBIN=self.cd_fb.clk, o_CLKFBOUT=fb,
i_CLKFBIN=self.cd_fb.clk,
o_CLKFBOUT=fb,
o_LOCKED=locked,
# p_CLKOUT0_DIVIDE_F=4, p_CLKOUT0_PHASE=0, o_CLKOUT0=sys,
p_CLKOUT1_DIVIDE=2, p_CLKOUT1_PHASE=0, o_CLKOUT1=sys2,
p_CLKOUT2_DIVIDE=2, p_CLKOUT2_PHASE=90, o_CLKOUT2=sys2q,
p_CLKOUT3_DIVIDE=4, p_CLKOUT3_PHASE=0, o_CLKOUT3=sys,
p_CLKOUT4_DIVIDE=5, p_CLKOUT4_PHASE=0, o_CLKOUT4=clk200,
p_CLKOUT1_DIVIDE=2,
p_CLKOUT1_PHASE=0,
o_CLKOUT1=sys2,
p_CLKOUT2_DIVIDE=2,
p_CLKOUT2_PHASE=90,
o_CLKOUT2=sys2q,
p_CLKOUT3_DIVIDE=4,
p_CLKOUT3_PHASE=0,
o_CLKOUT3=sys,
p_CLKOUT4_DIVIDE=5,
p_CLKOUT4_PHASE=0,
o_CLKOUT4=clk200,
),
Instance("BUFG", i_I=fb, o_O=self.cd_fb.clk),
Instance("BUFG", i_I=sys, o_O=self.cd_sys.clk),
Instance("BUFG", i_I=sys2, o_O=self.cd_sys2.clk),
Instance("BUFG", i_I=sys2q, o_O=self.cd_sys2q.clk),
Instance("BUFG", i_I=clk200, o_O=self.cd_clk200.clk),
Instance("IDELAYCTRL",
i_REFCLK=self.cd_clk200.clk, i_RST=~locked, o_RDY=delay_rdy),
Instance(
"IDELAYCTRL",
i_REFCLK=self.cd_clk200.clk,
i_RST=~locked,
o_RDY=delay_rdy,
),
]
self.submodules += AsyncResetSynchronizerBUFG(
self.cd_sys, ~(locked & delay_rdy))
self.cd_sys, ~(locked & delay_rdy)
)
44 changes: 27 additions & 17 deletions dac_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,13 @@ def parity(*x):
# synchronize frame marker to frame processing and to data_sync and thus to
# ISTR


class DacData(Module):
def __init__(self, pins, swap=((0, 3), (1, 8))):
self.data_sync = Signal() # at most every 8 samples (4 sys cycles)
self.sync_dly = Signal(max=8, reset_less=True)
# format as in the DS: A0:C0, B0:D0, A1:C1, B1:D1
self.data = [[
Signal(16, reset_less=True) for _ in range(2)
] for _ in range(4)]
self.data = [[Signal(16, reset_less=True) for _ in range(2)] for _ in range(4)]
self.istr = Signal(reset_less=True)

# buffer for parity calculation
Expand All @@ -42,12 +41,14 @@ def __init__(self, pins, swap=((0, 3), (1, 8))):
self.sync += [
i.eq(i + 1),
sync.eq(sync[2:]),
If(self.data_sync,
If(
self.data_sync,
i.eq(0),
sync.eq(0xf << self.sync_dly),
sync.eq(0xF << self.sync_dly),
),
self.istr.eq(0),
If(i == 4 - 1,
If(
i == 4 - 1,
self.istr.eq(1),
),
]
Expand All @@ -62,8 +63,7 @@ def __init__(self, pins, swap=((0, 3), (1, 8))):
self._oserdes([sync[0], sync[0], sync[1], sync[1]], pins.sync_p, pins.sync_n)

# ISTR for write pointer
self._oserdes([self.istr, 0, 0, 0],
pins.istr_parityab_p, pins.istr_parityab_n)
self._oserdes([self.istr, 0, 0, 0], pins.istr_parityab_p, pins.istr_parityab_n)

# 32 bit parity
self._oserdes(par, pins.paritycd_p, pins.paritycd_n)
Expand All @@ -72,9 +72,9 @@ def __init__(self, pins, swap=((0, 3), (1, 8))):
# not needed with SYNC+N-div+PLL generated internal OSTR
# self._oserdes([0, 0, 0, 0], pins.ostr_p, pins.ostr_n)

for i_port, port in enumerate([
(pins.data_a_p, pins.data_a_n),
(pins.data_b_p, pins.data_b_n)]):
for i_port, port in enumerate(
[(pins.data_a_p, pins.data_a_n), (pins.data_b_p, pins.data_b_n)]
):
for i_pin, pin in enumerate(zip(*port)):
bits = [words[i_word][i_port][i_pin] for i_word in range(4)]
if (i_port, i_pin) in swap: # sinara-hw/Phaser#102
Expand All @@ -85,15 +85,25 @@ def __init__(self, pins, swap=((0, 3), (1, 8))):
def _oserdes(self, data, pin_p, pin_n, clk="sys2", attr=set()):
pin = Signal()
self.specials += [
Instance("OSERDESE2", attr=attr,
p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF",
p_DATA_WIDTH=4, p_TRISTATE_WIDTH=1,
Instance(
"OSERDESE2",
attr=attr,
p_DATA_RATE_OQ="DDR",
p_DATA_RATE_TQ="BUF",
p_DATA_WIDTH=4,
p_TRISTATE_WIDTH=1,
i_RST=ResetSignal(),
i_CLK=ClockSignal(clk),
i_CLKDIV=ClockSignal(),
# LSB first, D1 is closest to Q
i_D1=data[0], i_D2=data[1], i_D3=data[2], i_D4=data[3],
i_TCE=1, i_OCE=1, i_T1=0,
o_OQ=pin),
i_D1=data[0],
i_D2=data[1],
i_D3=data[2],
i_D4=data[3],
i_TCE=1,
i_OCE=1,
i_T1=0,
o_OQ=pin,
),
DifferentialOutput(pin, pin_p, pin_n),
]
73 changes: 38 additions & 35 deletions decode.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,7 @@
from interpolate import SampleMux, InterpolateChannel


header_layout = [
("we", 1),
("addr", 7),
("data", 8),
("type", 4)
]
header_layout = [("we", 1), ("addr", 7), ("data", 8), ("type", 4)]

# straming gearbox
#
Expand All @@ -20,11 +15,13 @@
# 66666666666666666666666666666665666666656666666566666665666666656666666566666660
# 4 2 0 4 2 0 4 2 0 4 2 0 4


class SampleGearbox(Module):
"""Variable width input uneven ratio gearbox (e.g. 5/6 to 7)

`data_width <= sample_width`
"""

def __init__(self, data_width, sample_width):
self.data = Signal(data_width, reset_less=True)
self.data_short = Signal() # disregard data lsb
Expand All @@ -39,37 +36,43 @@ def __init__(self, data_width, sample_width):
outgoing = Signal(max=sample_width + 1)
full = Signal()
self.comb += [
If(self.data_stb,
If(self.data_short,
incoming.eq(data_width - 1),
).Else(
If(
self.data_stb,
If(self.data_short, incoming.eq(data_width - 1),).Else(
incoming.eq(data_width),
),
).Else(
incoming.eq(0),
),
full.eq(level >= sample_width),
If(full,
outgoing.eq(sample_width),
).Else(
If(full, outgoing.eq(sample_width),).Else(
outgoing.eq(0),
),
]
self.sync += [
If(self.data_stb,
buf.eq(Mux(self.data_short,
Cat(self.data[1:], buf),
Cat(self.data, buf),
)),
If(
self.data_stb,
buf.eq(
Mux(
self.data_short,
Cat(self.data[1:], buf),
Cat(self.data, buf),
)
),
),
self.sample_stb.eq(full),
If(full,
self.sample.eq(Case(level, {
sample_width + i: buf[i:] for i in range(data_width - 1)
})),
If(
full,
self.sample.eq(
Case(
level,
{sample_width + i: buf[i:] for i in range(data_width - 1)},
)
),
),
level.eq(level + incoming - outgoing),
If(self.clr,
If(
self.clr,
level.eq(0),
),
]
Expand All @@ -86,6 +89,7 @@ def __init__(self, data_width, sample_width):

class Register(Module):
"""Configuration/status register"""

def __init__(self, width=None, read=True, write=True, readback=True):
self.bus = Record(bus_layout)
if width is None:
Expand Down Expand Up @@ -115,8 +119,9 @@ def __init__(self):
def _check_intersection(self, adr, mask):
for _, b_adr, b_mask in self._slaves:
if intersection((b_adr, b_mask), (adr, mask)):
raise ValueError("{} intersects {}".format(
(adr, mask), (b_adr, b_mask)))
raise ValueError(
"{} intersects {}".format((adr, mask), (b_adr, b_mask))
)

def connect(self, bus, adr, mask):
adr &= mask
Expand All @@ -129,20 +134,19 @@ def connect(self, bus, adr, mask):
bus.dat_w.eq(self.bus.dat_w),
bus.we.eq(self.bus.we & stb),
bus.re.eq(self.bus.re & stb),
If(stb,
self.bus.dat_r.eq(bus.dat_r)
)
If(stb, self.bus.dat_r.eq(bus.dat_r)),
]


class Decode(Module):
"""Decode a frame into samples and metadata and drive
a bus of registers from the metadata.
"""

def __init__(self, b_sample, n_channel, n_mux, t_frame):
n_samples = n_mux*n_channel*2
n_samples = n_mux * n_channel * 2
header = Record(header_layout)
body = Signal(n_samples*b_sample)
body = Signal(n_samples * b_sample)
self.frame = Signal(len(body) + len(header))
self.stb = Signal()
self.response = Signal(8)
Expand All @@ -151,16 +155,15 @@ def __init__(self, b_sample, n_channel, n_mux, t_frame):
]

self.submodules.zoh = SampleMux(
b_sample=b_sample, n_channel=n_channel, n_mux=n_mux,
t_frame=t_frame)
b_sample=b_sample, n_channel=n_channel, n_mux=n_mux, t_frame=t_frame
)
self.comb += [
self.zoh.body.eq(body),
self.zoh.body_stb.eq(self.stb & (header.type == 1)),
]

self.interpolate = []
self.data = [[Record(complex(16)) for _ in range(n_channel)]
for _ in range(2)]
self.data = [[Record(complex(16)) for _ in range(n_channel)] for _ in range(2)]
for ch in range(n_channel):
for iq in "iq":
inter = InterpolateChannel()
Expand Down Expand Up @@ -194,7 +197,7 @@ def map_registers(self, registers):
assert name not in self.registers
self.registers[name] = regs
for i, reg in enumerate(regs):
self.bus.connect(reg.bus, addr, mask=0x7f)
self.bus.connect(reg.bus, addr, mask=0x7F)
assert addr not in self.mem_map
self.mem_map[addr] = (name, i)
self.submodules += reg
Expand Down
Loading