forked from M-Labs/artiq
suservo: refactor, constrain
* remove DiffMixin, move pad layout handling to pads * add input delay constraints, IDELAYs
This commit is contained in:
parent
d0258b9b2d
commit
37c186a0fc
|
@ -5,8 +5,6 @@ from collections import namedtuple
|
||||||
from migen import *
|
from migen import *
|
||||||
from migen.genlib import io
|
from migen.genlib import io
|
||||||
|
|
||||||
from .tools import DiffMixin
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -28,7 +26,7 @@ ADCParams = namedtuple("ADCParams", [
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
class ADC(Module, DiffMixin):
|
class ADC(Module):
|
||||||
"""Multi-lane, multi-channel, triggered, source-synchronous, serial
|
"""Multi-lane, multi-channel, triggered, source-synchronous, serial
|
||||||
ADC interface.
|
ADC interface.
|
||||||
|
|
||||||
|
@ -49,7 +47,7 @@ class ADC(Module, DiffMixin):
|
||||||
# collect sdo lines
|
# collect sdo lines
|
||||||
sdo = []
|
sdo = []
|
||||||
for i in string.ascii_lowercase[:p.lanes]:
|
for i in string.ascii_lowercase[:p.lanes]:
|
||||||
sdo.append(self._diff(pads, "sdo" + i))
|
sdo.append(getattr(pads, "sdo" + i))
|
||||||
assert p.lanes == len(sdo)
|
assert p.lanes == len(sdo)
|
||||||
|
|
||||||
# set up counters for the four states CNVH, CONV, READ, RTT
|
# set up counters for the four states CNVH, CONV, READ, RTT
|
||||||
|
@ -71,13 +69,6 @@ class ADC(Module, DiffMixin):
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
sck_en = Signal()
|
|
||||||
if hasattr(pads, "sck_en"):
|
|
||||||
self.sync += pads.sck_en.eq(sck_en) # ODDR delay
|
|
||||||
self.specials += io.DDROutput(0, sck_en,
|
|
||||||
self._diff(pads, "sck", output=True))
|
|
||||||
cnv_b = Signal()
|
|
||||||
self.comb += self._diff(pads, "cnv_b", output=True).eq(cnv_b)
|
|
||||||
self.submodules.fsm = fsm = FSM("IDLE")
|
self.submodules.fsm = fsm = FSM("IDLE")
|
||||||
fsm.act("IDLE",
|
fsm.act("IDLE",
|
||||||
self.done.eq(1),
|
self.done.eq(1),
|
||||||
|
@ -88,7 +79,7 @@ class ADC(Module, DiffMixin):
|
||||||
)
|
)
|
||||||
fsm.act("CNVH",
|
fsm.act("CNVH",
|
||||||
count_load.eq(p.t_conv - 2), # account for sck ODDR delay
|
count_load.eq(p.t_conv - 2), # account for sck ODDR delay
|
||||||
cnv_b.eq(1),
|
pads.cnv.eq(1),
|
||||||
If(count_done,
|
If(count_done,
|
||||||
NextState("CONV")
|
NextState("CONV")
|
||||||
)
|
)
|
||||||
|
@ -102,7 +93,7 @@ class ADC(Module, DiffMixin):
|
||||||
fsm.act("READ",
|
fsm.act("READ",
|
||||||
self.reading.eq(1),
|
self.reading.eq(1),
|
||||||
count_load.eq(p.t_rtt), # account for sck ODDR delay
|
count_load.eq(p.t_rtt), # account for sck ODDR delay
|
||||||
sck_en.eq(1),
|
pads.sck_en.eq(1),
|
||||||
If(count_done,
|
If(count_done,
|
||||||
NextState("RTT")
|
NextState("RTT")
|
||||||
)
|
)
|
||||||
|
@ -118,22 +109,25 @@ class ADC(Module, DiffMixin):
|
||||||
sck_en_ret = pads.sck_en_ret
|
sck_en_ret = pads.sck_en_ret
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
sck_en_ret = 1
|
sck_en_ret = 1
|
||||||
self.clkout_io = Signal()
|
|
||||||
|
self.clock_domains.cd_ret = ClockDomain("ret", reset_less=True)
|
||||||
|
self.comb += [
|
||||||
|
# falling clkout makes two bits available
|
||||||
|
self.cd_ret.clk.eq(~pads.clkout)
|
||||||
|
]
|
||||||
|
|
||||||
k = p.channels//p.lanes
|
k = p.channels//p.lanes
|
||||||
assert 2*t_read == k*p.width
|
assert 2*t_read == k*p.width
|
||||||
for i, sdo in enumerate(sdo):
|
for i, sdo in enumerate(sdo):
|
||||||
sdo_sr0 = Signal(t_read - 1)
|
sdo_sr0 = Signal(t_read - 1)
|
||||||
sdo_sr1 = Signal(t_read - 1)
|
sdo_sr1 = Signal(t_read - 1)
|
||||||
sdo_ddr = Signal(2)
|
|
||||||
self.specials += io.DDRInput(sdo, sdo_ddr[1], sdo_ddr[0],
|
|
||||||
~self.clkout_io)
|
|
||||||
self.sync.ret += [
|
self.sync.ret += [
|
||||||
If(self.reading & sck_en_ret,
|
If(self.reading & sck_en_ret,
|
||||||
sdo_sr0.eq(Cat(sdo_ddr[0], sdo_sr0)),
|
sdo_sr0.eq(Cat(sdo[0], sdo_sr0)),
|
||||||
sdo_sr1.eq(Cat(sdo_ddr[1], sdo_sr1))
|
sdo_sr1.eq(Cat(sdo[1], sdo_sr1))
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
self.comb += [
|
self.comb += [
|
||||||
Cat(reversed([self.data[i*k + j] for j in range(k)])).eq(
|
Cat(reversed([self.data[i*k + j] for j in range(k)])).eq(
|
||||||
Cat(sdo_ddr, zip(sdo_sr0, sdo_sr1)))
|
Cat(sdo, zip(sdo_sr0, sdo_sr1)))
|
||||||
]
|
]
|
||||||
|
|
|
@ -36,7 +36,7 @@ class DDS(spi.SPISimple):
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
io_update = self._diff(pads, "io_update", output=True)
|
io_update = pads.io_update
|
||||||
# this assumes that the cycle time (1/125 MHz = 8 ns) is >1 SYNC_CLK
|
# this assumes that the cycle time (1/125 MHz = 8 ns) is >1 SYNC_CLK
|
||||||
# cycle (1/250 MHz = 4ns)
|
# cycle (1/250 MHz = 4ns)
|
||||||
done = Signal()
|
done = Signal()
|
||||||
|
|
|
@ -1,24 +1,77 @@
|
||||||
from migen import *
|
from migen import *
|
||||||
from migen.genlib.io import DifferentialOutput
|
from migen.genlib.io import DifferentialOutput, DifferentialInput, DDROutput
|
||||||
|
|
||||||
|
|
||||||
class SamplerPads(Module):
|
class SamplerPads(Module):
|
||||||
def __init__(self, platform, eem0, eem1):
|
def __init__(self, platform, eem0, eem1):
|
||||||
self.sck_p, self.sck_n = [
|
self.sck_en = Signal()
|
||||||
platform.request("{}_adc_spi_{}".format(eem0, pol), 0).clk
|
self.cnv = Signal()
|
||||||
for pol in "pn"]
|
self.clkout = Signal()
|
||||||
pads = platform.request("{}_cnv".format(eem0), 0)
|
|
||||||
self.cnv_b_p, self.cnv_b_n = pads.p, pads.n
|
spip = platform.request("{}_adc_spi_p".format(eem0))
|
||||||
pads = platform.request("{}_sdr".format(eem0), 0)
|
spin = platform.request("{}_adc_spi_n".format(eem0))
|
||||||
self.specials += DifferentialOutput(0, pads.p, pads.n)
|
cnv = platform.request("{}_cnv".format(eem0))
|
||||||
dp, dn = [
|
sdr = platform.request("{}_sdr".format(eem0))
|
||||||
platform.request("{}_adc_data_{}".format(eem0, pol), 0)
|
dp = platform.request("{}_adc_data_p".format(eem0))
|
||||||
for pol in "pn"]
|
dn = platform.request("{}_adc_data_n".format(eem0))
|
||||||
self.clkout_p, self.clkout_n = dp.clkout, dn.clkout
|
|
||||||
self.sdoa_p, self.sdoa_n = dp.sdoa, dn.sdoa
|
clkout_se = Signal()
|
||||||
self.sdob_p, self.sdob_n = dp.sdob, dn.sdob
|
clkout_d = Signal()
|
||||||
self.sdoc_p, self.sdoc_n = dp.sdoc, dn.sdoc
|
sck = Signal()
|
||||||
self.sdod_p, self.sdod_n = dp.sdod, dn.sdod
|
|
||||||
|
self.specials += [
|
||||||
|
DifferentialOutput(self.cnv, cnv.p, cnv.n),
|
||||||
|
DifferentialOutput(1, sdr.p, sdr.n),
|
||||||
|
DDROutput(0, self.sck_en, sck),
|
||||||
|
DifferentialOutput(sck, spip.clk, spin.clk),
|
||||||
|
DifferentialInput(dp.clkout, dn.clkout, clkout_se),
|
||||||
|
Instance(
|
||||||
|
"IDELAYE2",
|
||||||
|
p_HIGH_PERFORMANCE_MODE="TRUE", p_IDELAY_TYPE="FIXED",
|
||||||
|
p_SIGNAL_PATTERN="CLOCK", p_IDELAY_VALUE=0,
|
||||||
|
p_REFCLK_FREQUENCY=200.,
|
||||||
|
i_IDATAIN=clkout_se, o_DATAOUT=clkout_d),
|
||||||
|
Instance("BUFR", i_I=clkout_d, o_O=self.clkout)
|
||||||
|
]
|
||||||
|
|
||||||
|
# here to be early before the input delays below to have the clock
|
||||||
|
# available
|
||||||
|
self.clkout_p = dp.clkout # availabel for false paths
|
||||||
|
platform.add_platform_command(
|
||||||
|
"create_clock -name {clk} -period 8 [get_nets {clk}]",
|
||||||
|
clk=dp.clkout)
|
||||||
|
# platform.add_period_constraint(sampler_pads.clkout_p, 8.)
|
||||||
|
for i in "abcd":
|
||||||
|
sdo_se = Signal()
|
||||||
|
sdo_d = Signal()
|
||||||
|
sdo = Signal(2)
|
||||||
|
setattr(self, "sdo{}".format(i), sdo)
|
||||||
|
sdop = getattr(dp, "sdo{}".format(i))
|
||||||
|
sdon = getattr(dn, "sdo{}".format(i))
|
||||||
|
self.specials += [
|
||||||
|
DifferentialInput(sdop, sdon, sdo_se),
|
||||||
|
Instance(
|
||||||
|
"IDELAYE2",
|
||||||
|
p_HIGH_PERFORMANCE_MODE="TRUE", p_IDELAY_TYPE="FIXED",
|
||||||
|
p_SIGNAL_PATTERN="DATA", p_IDELAY_VALUE=31,
|
||||||
|
p_REFCLK_FREQUENCY=200.,
|
||||||
|
i_IDATAIN=sdo_se, o_DATAOUT=sdo_d),
|
||||||
|
Instance("IDDR",
|
||||||
|
p_DDR_CLK_EDGE="SAME_EDGE",
|
||||||
|
i_C=~self.clkout, i_CE=1, i_S=0, i_R=0,
|
||||||
|
i_D=sdo_d, o_Q1=sdo[0], o_Q2=sdo[1]) # sdo[1] older
|
||||||
|
]
|
||||||
|
# 4, -0+1.5 hold (t_HSDO_DDR), -0.2+0.2 skew
|
||||||
|
platform.add_platform_command(
|
||||||
|
"set_input_delay -clock {clk} "
|
||||||
|
"-max 1.6 [get_ports {port}]\n"
|
||||||
|
"set_input_delay -clock {clk} "
|
||||||
|
"-min -0.1 [get_ports {port}]\n"
|
||||||
|
"set_input_delay -clock {clk} "
|
||||||
|
"-max 1.6 [get_ports {port}] -clock_fall -add_delay\n"
|
||||||
|
"set_input_delay -clock {clk} "
|
||||||
|
"-min -0.1 [get_ports {port}] -clock_fall -add_delay",
|
||||||
|
clk=dp.clkout, port=sdop)
|
||||||
|
|
||||||
|
|
||||||
class UrukulPads(Module):
|
class UrukulPads(Module):
|
||||||
|
@ -37,7 +90,10 @@ class UrukulPads(Module):
|
||||||
DifferentialOutput(self.io_update, ioup[i].p, ioup[i].n))
|
DifferentialOutput(self.io_update, ioup[i].p, ioup[i].n))
|
||||||
for i in range(2)]
|
for i in range(2)]
|
||||||
for i in range(8):
|
for i in range(8):
|
||||||
setattr(self, "mosi{}_p".format(i),
|
mosi = Signal()
|
||||||
getattr(spip[i // 4], "mosi{}".format(i % 4)))
|
setattr(self, "mosi{}".format(i), mosi)
|
||||||
setattr(self, "mosi{}_n".format(i),
|
self.specials += [
|
||||||
|
DifferentialOutput(mosi,
|
||||||
|
getattr(spip[i // 4], "mosi{}".format(i % 4)),
|
||||||
getattr(spin[i // 4], "mosi{}".format(i % 4)))
|
getattr(spin[i // 4], "mosi{}".format(i % 4)))
|
||||||
|
]
|
||||||
|
|
|
@ -5,8 +5,6 @@ from migen import *
|
||||||
from migen.genlib.fsm import FSM, NextState
|
from migen.genlib.fsm import FSM, NextState
|
||||||
from migen.genlib import io
|
from migen.genlib import io
|
||||||
|
|
||||||
from .tools import DiffMixin
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -19,7 +17,7 @@ SPIParams = namedtuple("SPIParams", [
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
class SPISimple(Module, DiffMixin):
|
class SPISimple(Module):
|
||||||
"""Simple reduced SPI interface.
|
"""Simple reduced SPI interface.
|
||||||
|
|
||||||
* Multiple MOSI lines
|
* Multiple MOSI lines
|
||||||
|
@ -39,9 +37,8 @@ class SPISimple(Module, DiffMixin):
|
||||||
|
|
||||||
assert p.clk >= 1
|
assert p.clk >= 1
|
||||||
|
|
||||||
cs_n = self._diff(pads, "cs_n", output=True)
|
cs_n = pads.cs_n
|
||||||
|
clk = pads.clk
|
||||||
clk = self._diff(pads, "clk", output=True)
|
|
||||||
cnt = Signal(max=max(2, p.clk), reset_less=True)
|
cnt = Signal(max=max(2, p.clk), reset_less=True)
|
||||||
cnt_done = Signal()
|
cnt_done = Signal()
|
||||||
cnt_next = Signal()
|
cnt_next = Signal()
|
||||||
|
@ -58,7 +55,7 @@ class SPISimple(Module, DiffMixin):
|
||||||
|
|
||||||
for i, d in enumerate(self.data):
|
for i, d in enumerate(self.data):
|
||||||
self.comb += [
|
self.comb += [
|
||||||
self._diff(pads, "mosi{}".format(i), output=True).eq(d[-1])
|
getattr(pads, "mosi{}".format(i)).eq(d[-1])
|
||||||
]
|
]
|
||||||
|
|
||||||
bits = Signal(max=p.width + 1, reset_less=True)
|
bits = Signal(max=p.width + 1, reset_less=True)
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
from migen import *
|
|
||||||
from migen.genlib import io
|
|
||||||
|
|
||||||
|
|
||||||
class DiffMixin:
|
|
||||||
def _diff(self, pads, name, output=False):
|
|
||||||
"""Retrieve the single-ended ``Signal()`` ``name`` from
|
|
||||||
``pads`` and in its absence retrieve the differential signal with the
|
|
||||||
pin pairs ``name_p`` and ``name_n``. Do so as an output if ``output``,
|
|
||||||
otherwise make a differential input."""
|
|
||||||
if hasattr(pads, name):
|
|
||||||
return getattr(pads, name)
|
|
||||||
sig = Signal()
|
|
||||||
p, n = (getattr(pads, name + "_" + s) for s in "pn")
|
|
||||||
if output:
|
|
||||||
self.specials += io.DifferentialOutput(sig, p, n)
|
|
||||||
else:
|
|
||||||
self.specials += io.DifferentialInput(p, n, sig)
|
|
||||||
return sig
|
|
|
@ -540,20 +540,6 @@ class SUServo(_StandaloneBase):
|
||||||
su = ClockDomainsRenamer({"sys": "rio_phy"})(su)
|
su = ClockDomainsRenamer({"sys": "rio_phy"})(su)
|
||||||
self.submodules += sampler_pads, urukul_pads, su
|
self.submodules += sampler_pads, urukul_pads, su
|
||||||
|
|
||||||
self.clock_domains.cd_ret = ClockDomain("ret", reset_less=True)
|
|
||||||
clkout = Signal()
|
|
||||||
clkout_fabric = Signal()
|
|
||||||
self.specials += [
|
|
||||||
DifferentialInput(
|
|
||||||
sampler_pads.clkout_p, sampler_pads.clkout_n, clkout),
|
|
||||||
Instance("BUFH", i_I=clkout, o_O=clkout_fabric),
|
|
||||||
Instance("BUFIO", i_I=clkout, o_O=su.adc.clkout_io)
|
|
||||||
]
|
|
||||||
self.comb += [
|
|
||||||
# falling clkout makes two bits available
|
|
||||||
self.cd_ret.clk.eq(~clkout_fabric)
|
|
||||||
]
|
|
||||||
|
|
||||||
ctrls = [rtservo.RTServoCtrl(ctrl) for ctrl in su.iir.ctrl]
|
ctrls = [rtservo.RTServoCtrl(ctrl) for ctrl in su.iir.ctrl]
|
||||||
self.submodules += ctrls
|
self.submodules += ctrls
|
||||||
rtio_channels.extend(rtio.Channel.from_phy(ctrl) for ctrl in ctrls)
|
rtio_channels.extend(rtio.Channel.from_phy(ctrl) for ctrl in ctrls)
|
||||||
|
@ -603,29 +589,12 @@ class SUServo(_StandaloneBase):
|
||||||
|
|
||||||
self.add_rtio(rtio_channels)
|
self.add_rtio(rtio_channels)
|
||||||
|
|
||||||
platform.add_period_constraint(sampler_pads.clkout_p, 8.)
|
|
||||||
platform.add_false_path_constraints(
|
platform.add_false_path_constraints(
|
||||||
sampler_pads.clkout_p,
|
sampler_pads.clkout_p,
|
||||||
self.rtio_crg.cd_rtio.clk)
|
self.rtio_crg.cd_rtio.clk)
|
||||||
platform.add_false_path_constraints(
|
platform.add_false_path_constraints(
|
||||||
sampler_pads.clkout_p,
|
sampler_pads.clkout_p,
|
||||||
self.crg.cd_sys.clk)
|
self.crg.cd_sys.clk)
|
||||||
for i in "abcd":
|
|
||||||
port = getattr(sampler_pads, "sdo{}_p".format(i))
|
|
||||||
platform.add_platform_command(
|
|
||||||
"set_input_delay -clock [get_clocks "
|
|
||||||
"-include_generated_clocks -of [get_nets {clk}]] "
|
|
||||||
"-max 6 [get_ports {port}]\n"
|
|
||||||
"set_input_delay -clock [get_clocks "
|
|
||||||
"-include_generated_clocks -of [get_nets {clk}]] "
|
|
||||||
"-min 3.5 [get_ports {port}]\n"
|
|
||||||
"set_input_delay -clock [get_clocks "
|
|
||||||
"-include_generated_clocks -of [get_nets {clk}]] "
|
|
||||||
"-max 6 [get_ports {port}] -clock_fall -add_delay\n"
|
|
||||||
"set_input_delay -clock [get_clocks "
|
|
||||||
"-include_generated_clocks -of [get_nets {clk}]] "
|
|
||||||
"-min 3.5 [get_ports {port}] -clock_fall -add_delay",
|
|
||||||
clk=sampler_pads.clkout_p, port=port)
|
|
||||||
|
|
||||||
|
|
||||||
class SYSU(_StandaloneBase):
|
class SYSU(_StandaloneBase):
|
||||||
|
|
|
@ -8,57 +8,6 @@ from migen.genlib import io
|
||||||
from artiq.gateware.suservo.adc_ser import ADC, ADCParams
|
from artiq.gateware.suservo.adc_ser import ADC, ADCParams
|
||||||
|
|
||||||
|
|
||||||
class DDROutputImpl(Module):
|
|
||||||
def __init__(self, i1, i2, o, clk):
|
|
||||||
do_clk0 = Signal(reset_less=True)
|
|
||||||
do_j1 = Signal(reset_less=True)
|
|
||||||
do_j2 = Signal(reset_less=True)
|
|
||||||
do_j3 = Signal(reset_less=True)
|
|
||||||
self.sync.async += [
|
|
||||||
do_clk0.eq(clk),
|
|
||||||
do_j1.eq(i1),
|
|
||||||
do_j2.eq(i2),
|
|
||||||
If(Cat(do_clk0, clk) == 0b10,
|
|
||||||
o.eq(do_j1),
|
|
||||||
do_j3.eq(do_j2),
|
|
||||||
).Elif(Cat(do_clk0, clk) == 0b01,
|
|
||||||
o.eq(do_j3),
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class DDROutput:
|
|
||||||
@staticmethod
|
|
||||||
def lower(dr):
|
|
||||||
return DDROutputImpl(dr.i1, dr.i2, dr.o, dr.clk)
|
|
||||||
|
|
||||||
|
|
||||||
class DDRInputImpl(Module):
|
|
||||||
def __init__(self, i, o1, o2, clk):
|
|
||||||
di_clk0 = Signal(reset_less=True)
|
|
||||||
# SAME_EDGE_PIPELINED is effectively one register for o1
|
|
||||||
# (during rising clock)
|
|
||||||
di_j1 = Signal(reset_less=True)
|
|
||||||
di_j2 = Signal(reset_less=True)
|
|
||||||
di_j3 = Signal(reset_less=True)
|
|
||||||
self.sync.async += [
|
|
||||||
di_clk0.eq(clk),
|
|
||||||
di_j1.eq(i),
|
|
||||||
If(Cat(di_clk0, clk) == 0b10,
|
|
||||||
di_j3.eq(di_j1),
|
|
||||||
o1.eq(di_j3),
|
|
||||||
o2.eq(di_j2)
|
|
||||||
).Elif(Cat(di_clk0, clk) == 0b01,
|
|
||||||
di_j2.eq(di_j1)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class DDRInput:
|
|
||||||
@staticmethod
|
|
||||||
def lower(dr):
|
|
||||||
return DDRInputImpl(dr.i, dr.o1, dr.o2, dr.clk)
|
|
||||||
|
|
||||||
|
|
||||||
class TB(Module):
|
class TB(Module):
|
||||||
def __init__(self, params):
|
def __init__(self, params):
|
||||||
|
@ -66,7 +15,7 @@ class TB(Module):
|
||||||
|
|
||||||
self.sck = Signal()
|
self.sck = Signal()
|
||||||
self.clkout = Signal(reset_less=True)
|
self.clkout = Signal(reset_less=True)
|
||||||
self.cnv_b = Signal()
|
self.cnv = Signal()
|
||||||
|
|
||||||
self.sck_en = Signal()
|
self.sck_en = Signal()
|
||||||
self.sck_en_ret = Signal()
|
self.sck_en_ret = Signal()
|
||||||
|
@ -75,12 +24,6 @@ class TB(Module):
|
||||||
cd_adc = ClockDomain("adc", reset_less=True)
|
cd_adc = ClockDomain("adc", reset_less=True)
|
||||||
self.clock_domains += cd_adc
|
self.clock_domains += cd_adc
|
||||||
|
|
||||||
self.clock_domains.cd_ret = ClockDomain("ret", reset_less=True)
|
|
||||||
self.comb += [
|
|
||||||
# falling clkout makes two bits available
|
|
||||||
self.cd_ret.clk.eq(~self.clkout)
|
|
||||||
]
|
|
||||||
|
|
||||||
self.sdo = []
|
self.sdo = []
|
||||||
self.data = [Signal((p.width, True), reset_less=True)
|
self.data = [Signal((p.width, True), reset_less=True)
|
||||||
for i in range(p.channels)]
|
for i in range(p.channels)]
|
||||||
|
@ -88,23 +31,21 @@ class TB(Module):
|
||||||
srs = []
|
srs = []
|
||||||
for i in range(p.lanes):
|
for i in range(p.lanes):
|
||||||
name = "sdo" + string.ascii_lowercase[i]
|
name = "sdo" + string.ascii_lowercase[i]
|
||||||
sdo = Signal(name=name, reset_less=True)
|
sdo = Signal(2, name=name, reset_less=True)
|
||||||
self.sdo.append(sdo)
|
self.sdo.append(sdo)
|
||||||
setattr(self, name, sdo)
|
setattr(self, name, sdo)
|
||||||
sr = Signal(p.width*p.channels//p.lanes, reset_less=True)
|
sr = Signal(p.width*p.channels//p.lanes, reset_less=True)
|
||||||
srs.append(sr)
|
srs.append(sr)
|
||||||
self.specials += io.DDROutput(
|
|
||||||
# one for async
|
|
||||||
self._dly(sr[-1], -1), self._dly(sr[-2], -1), sdo)
|
|
||||||
self.sync.adc += [
|
self.sync.adc += [
|
||||||
|
sdo.eq(Cat(self._dly(sr[-1], 3), self._dly(sr[-2], 3))),
|
||||||
If(adc_sck_en,
|
If(adc_sck_en,
|
||||||
sr[2:].eq(sr)
|
sr[2:].eq(sr)
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
cnv_b_old = Signal(reset_less=True)
|
cnv_old = Signal(reset_less=True)
|
||||||
self.sync.async += [
|
self.sync.async += [
|
||||||
cnv_b_old.eq(self.cnv_b),
|
cnv_old.eq(self.cnv),
|
||||||
If(Cat(cnv_b_old, self.cnv_b) == 0b10,
|
If(Cat(cnv_old, self.cnv) == 0b10,
|
||||||
sr.eq(Cat(reversed(self.data[2*i:2*i + 2]))),
|
sr.eq(Cat(reversed(self.data[2*i:2*i + 2]))),
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
@ -130,7 +71,6 @@ def main():
|
||||||
tb = TB(params)
|
tb = TB(params)
|
||||||
adc = ADC(tb, params)
|
adc = ADC(tb, params)
|
||||||
tb.submodules += adc
|
tb.submodules += adc
|
||||||
tb.comb += adc.clkout_io.eq(tb.clkout)
|
|
||||||
|
|
||||||
def run(tb):
|
def run(tb):
|
||||||
dut = adc
|
dut = adc
|
||||||
|
@ -156,10 +96,7 @@ def main():
|
||||||
"ret": (8, 0),
|
"ret": (8, 0),
|
||||||
"async": (2, 0),
|
"async": (2, 0),
|
||||||
},
|
},
|
||||||
special_overrides={
|
)
|
||||||
io.DDROutput: DDROutput,
|
|
||||||
io.DDRInput: DDRInput
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
class ADCTest(unittest.TestCase):
|
class ADCTest(unittest.TestCase):
|
||||||
|
|
|
@ -23,7 +23,6 @@ class ServoSim(servo.Servo):
|
||||||
|
|
||||||
servo.Servo.__init__(self, self.adc_tb, self.dds_tb,
|
servo.Servo.__init__(self, self.adc_tb, self.dds_tb,
|
||||||
adc_p, iir_p, dds_p)
|
adc_p, iir_p, dds_p)
|
||||||
self.adc_tb.comb += self.adc.clkout_io.eq(self.adc_tb.clkout)
|
|
||||||
|
|
||||||
def test(self):
|
def test(self):
|
||||||
assert (yield self.done)
|
assert (yield self.done)
|
||||||
|
|
Loading…
Reference in New Issue