diff --git a/artiq/gateware/dsp/sawg.py b/artiq/gateware/dsp/sawg.py index 14c16d41f..2615d2018 100644 --- a/artiq/gateware/dsp/sawg.py +++ b/artiq/gateware/dsp/sawg.py @@ -36,8 +36,8 @@ class ParallelDDS(Module): self.comb += [ xy_delay.i.eq(Cat(self.i.x, self.i.y)), - z_delay.i.eq(Cat([zi[-widths.p:] - for zi in accu.o.payload.flatten()])), + z_delay.i.eq(Cat(zi[-widths.p:] + for zi in accu.o.payload.flatten())), eqh(accu.i.p, self.i.p), accu.i.f.eq(self.i.f), accu.i.clr.eq(self.i.clr), @@ -45,7 +45,7 @@ class ParallelDDS(Module): self.i.ack.eq(accu.i.ack), accu.o.ack.eq(1), [Cat(c.xi, c.yi).eq(xy_delay.o) for c in cordic], - Cat([c.zi for c in cordic]).eq(z_delay.o), + Cat(c.zi for c in cordic).eq(z_delay.o), ] @@ -71,8 +71,15 @@ class SplineParallelDUC(ParallelDDS): f.o.ack.eq(self.ce), eqh(self.i.f, f.o.a0), eqh(self.i.p, p.o.a0), - self.i.clr.eq(self.clr), - self.i.stb.eq(p.o.stb & f.o.stb), + self.i.stb.eq(p.o.stb | f.o.stb), + ] + + assert p.latency == 1 + self.sync += [ + self.i.clr.eq(0), + If(p.i.stb, + self.i.clr.eq(self.clr), + ), ] @@ -94,20 +101,24 @@ class SplineParallelDDS(SplineParallelDUC): class Config(Module): - def __init__(self): - self.clr = Signal(4) - self.iq_en = Signal(2) - limit = [Signal((16, True)) for i in range(2*2)] - self.limit = [limit[i:i + 2] for i in range(0, len(limit), 2)] - self.i = Endpoint([("addr", bits_for(len(limit) + 2)), ("data", 16)]) + def __init__(self, width): + self.clr = Signal(4, reset=0b1111) + self.iq_en = Signal(2, reset=0b01) + self.limit = [[Signal((width, True), reset=-(1 << width - 1)), + Signal((width, True), reset=(1 << width - 1) - 1)] + for i in range(2)] + self.i = Endpoint([("addr", bits_for(4 + 2*len(self.limit))), + ("data", 16)]) self.ce = Signal() ### - div = Signal(16) + div = Signal(16, reset=0) n = Signal.like(div) + pad = Signal() - reg = Array([Cat(self.clr, self.iq_en), Cat(div, n)] + self.limit) + reg = Array([Cat(div, n), self.clr, self.iq_en, pad] + + sum(self.limit, [])) self.comb += [ self.i.ack.eq(1), @@ -130,22 +141,22 @@ class Channel(Module, SatAddMixin): orders = _Orders(a=4, f=2, p=1) if widths is None: widths = _Widths(t=width, a=orders.a*width, p=orders.p*width, - f=3*width + (orders.f - 1)*width) + f=(orders.f + 2)*width) - cfg = Config() - a1 = SplineParallelDDS(widths, orders) - a2 = SplineParallelDDS(widths, orders) - b = SplineParallelDUC(widths, orders, parallelism=parallelism, - a_delay=-a1.latency) + self.submodules.a1 = a1 = SplineParallelDDS(widths, orders) + self.submodules.a2 = a2 = SplineParallelDDS(widths, orders) + self.submodules.b = b = SplineParallelDUC( + widths, orders, parallelism=parallelism, a_delay=-a1.latency) + cfg = Config(widths.a) u = Spline(width=widths.a, order=orders.a) du = Delay(widths.a, a1.latency + b.latency - u.latency) - self.submodules += cfg, a1, a2, b, u, du - self.cfg = cfg.i + self.submodules += cfg, u, du self.u = u.tri(widths.t) - self.i = [self.cfg, self.u, a1.a, a1.f, a1.p, a2.a, a2.f, a2.p, b.f, b.p] - self.y_in = [Signal((width, True)) for i in range(b.parallelism)] - self.y_out = b.yo - self.o = [Signal((width, True)) for i in range(b.parallelism)] + self.i = [cfg.i, self.u, a1.a, a1.f, a1.p, a2.a, a2.f, a2.p, b.f, b.p] + self.i_names = "cfg u a1 f1 p1 a2 f2 p2 f0 p0".split() + self.i_named = dict(zip(self.i_names, self.i)) + self.y_in = [Signal((width, True)) for i in range(parallelism)] + self.o = [Signal((width, True)) for i in range(parallelism)] self.widths = widths self.orders = orders self.parallelism = parallelism @@ -167,10 +178,11 @@ class Channel(Module, SatAddMixin): # wire up outputs and q_{i,o} exchange for o, x, y in zip(self.o, b.xo, self.y_in): self.sync += [ - o.eq(self.sat_add([du.o, + o.eq(self.sat_add([ + du.o, Mux(cfg.iq_en[0], x, 0), Mux(cfg.iq_en[1], y, 0)])), ] - def connect_q_from(self, buddy): - self.comb += Cat(self.y_in).eq(Cat(buddy.y_out)) + def connect_y(self, buddy): + self.comb += Cat(buddy.y_in).eq(Cat(self.b.yo)) diff --git a/artiq/gateware/rtio/phy/sawg.py b/artiq/gateware/rtio/phy/sawg.py index b9abc64a5..84094f5a2 100644 --- a/artiq/gateware/rtio/phy/sawg.py +++ b/artiq/gateware/rtio/phy/sawg.py @@ -16,14 +16,12 @@ class Channel(_ChannelPHY): _ChannelPHY.__init__(self, *args, **kwargs) self.phys = [] for i in self.i: - rl = rtlink.Interface(rtlink.OInterface( - min(32, len(i.payload)))) # TODO: test/expand + rl = rtlink.Interface(rtlink.OInterface(len(i.payload))) self.comb += [ i.stb.eq(rl.o.stb), rl.o.busy.eq(~i.ack), - Cat(i.payload.flatten()).eq(rl.o.data), + i.payload.raw_bits().eq(rl.o.data), ] - # no probes, overrides + # TODO probes, overrides self.phys.append(_Phy(rl, [], [])) - self.phys_names = dict(zip("cfg f0 p0 a1 f1 p1 a2 f2 p2".split(), - self.phys)) + self.phys_named = dict(zip(self.i_names, self.phys)) diff --git a/artiq/test/gateware/test_sawg.py b/artiq/test/gateware/test_sawg.py index 00e5f8c3f..a5eea31bd 100644 --- a/artiq/test/gateware/test_sawg.py +++ b/artiq/test/gateware/test_sawg.py @@ -3,23 +3,25 @@ import numpy as np from migen import * from migen.fhdl.verilog import convert -from artiq.gateware.dsp.sawg import DDSFast +from artiq.gateware.dsp import sawg from .tools import xfer def _test_gen_dds(dut, o): yield from xfer(dut, - a=dict(a=10), - p=dict(p=0), - f=dict(f=1 << 8), + a=dict(a0=10), + p=dict(a0=0), + f=dict(a0=1), ) for i in range(256//dut.parallelism): yield - o.append((yield from [(yield _) for _ in dut.o])) + o.append((yield from [(yield _) for _ in dut.xo])) def _test_channel(): - dut = DDSFast(width=8, parallelism=2) + widths = sawg._Widths(t=8, a=4*8, p=8, f=16) + orders = sawg._Orders(a=4, p=1, f=2) + dut = sawg.SplineParallelDDS(widths, orders, parallelism=2) if False: print(convert(dut)) diff --git a/artiq/test/gateware/test_sawg_phy.py b/artiq/test/gateware/test_sawg_phy.py index 4f2617c7a..35666a5f6 100644 --- a/artiq/test/gateware/test_sawg_phy.py +++ b/artiq/test/gateware/test_sawg_phy.py @@ -1,25 +1,32 @@ import numpy as np +from operator import or_ from migen import * from migen.fhdl.verilog import convert from artiq.gateware.rtio.phy.sawg import Channel -from .tools import xfer, szip +from .tools import rtio_xfer -def rtio_xfer(dut, **kwargs): - yield from szip(*( - xfer(dut.phys_names[k].rtlink, o={"data": v}) - for k, v in kwargs.items())) +def pack_tri(port, *v): + r = 0 + w = 0 + for vi, p in zip(v, port.payload.flatten()): + w += len(p) + r |= int(vi*(1 << w)) + return r def gen_rtio(dut): - width = dut.width yield yield from rtio_xfer( - dut, a=int(.1 * (1 << width)), - f=int(.01234567 * (1 << 2*width)), - p=0) + dut, + a1=pack_tri(dut.a1.a, .1), + f0=pack_tri(dut.b.f, .01234567), + f1=pack_tri(dut.a1.f, .01234567), + a2=pack_tri(dut.a1.a, .05), + f2=pack_tri(dut.a1.f, .00534567), + ) def gen_log(dut, o, n): @@ -28,10 +35,12 @@ def gen_log(dut, o, n): for i in range(n): yield o.append((yield from [(yield _) for _ in dut.o])) + #o.append([(yield dut.a1.xo[0])]) def _test_channel(): width = 16 + dut = ClockDomainsRenamer({"rio_phy": "sys"})( Channel(width=width, parallelism=4) ) @@ -43,8 +52,8 @@ def _test_channel(): o = [] run_simulation( dut, - [gen_rtio(dut), gen_log(dut, o, 256 * 2)], - ) # vcd_name="dds.vcd") + [gen_rtio(dut), gen_log(dut, o, 128)], + vcd_name="dds.vcd") o = np.array(o)/(1 << (width - 1)) o = o.ravel() np.savez_compressed("dds.npz", o=o) diff --git a/artiq/test/gateware/tools.py b/artiq/test/gateware/tools.py index ca9451e78..8d22ad475 100644 --- a/artiq/test/gateware/tools.py +++ b/artiq/test/gateware/tools.py @@ -41,3 +41,9 @@ def szip(*iters): val = (yield None) for it in active: active[it] = val + + +def rtio_xfer(dut, **kwargs): + yield from szip(*( + xfer(dut.phys_named[k].rtlink, o={"data": v}) + for k, v in kwargs.items()))