From ea0c304a0c91155d615031642df3798055c5a852 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 27 Oct 2016 01:00:42 +0200 Subject: [PATCH] phaser2: wip --- artiq/gateware/dsp/sawg.py | 290 +++++++++++++++++++++++++++++++- artiq/gateware/rtio/phy/sawg.py | 14 +- 2 files changed, 296 insertions(+), 8 deletions(-) diff --git a/artiq/gateware/dsp/sawg.py b/artiq/gateware/dsp/sawg.py index c9b5fa176..8b61ded8f 100644 --- a/artiq/gateware/dsp/sawg.py +++ b/artiq/gateware/dsp/sawg.py @@ -2,8 +2,9 @@ from migen import * from misoc.interconnect.stream import Endpoint from misoc.cores.cordic import Cordic -from .accu import PhasedAccu -from .tools import eqh +from .accu import PhasedAccu, Accu +from .tools import eqh, Delay +from .spline import Spline class DDSFast(Module): @@ -66,3 +67,288 @@ class DDSFast(Module): ] self.latency += c[0].latency self.gain = c[0].gain + + +class DDSFast(Module): + def __init__(self, width, t_width=None, + a_width=None, p_width=None, f_width=None, + a_order=4, p_order=1, f_order=2, parallelism=8): + if t_width is None: + t_width = width + if a_width is None: + a_width = width + (a_order - 1)*t_width + if p_width is None: + p_width = width + (p_order - 1)*t_width + if f_width is None: + f_width = width + (f_order + 1)*t_width + a = Spline(order=a_order, width=a_width) + p = Spline(order=p_order, width=p_width) + f = Spline(order=f_order, width=f_width) + self.submodules += a, p, f + + self.a = a.tri(t_width) + self.f = f.tri(t_width) + self.p = p.tri(t_width) + self.i = [self.a, self.f, self.p] + self.o = [[Signal((width, True)) for i in range(2)] + for i in range(parallelism)] + self.parallelism = parallelism + self.latency = 0 # will be accumulated + + ### + + self.latency += p.latency + q = PhasedAccu(f_width, parallelism) + self.submodules += q + self.latency += q.latency + da = [Signal((width, True)) for i in range(q.latency)] + + self.sync += [ + If(q.i.stb & q.i.ack, + eqh(da[0], a.o.a0), + [da[i + 1].eq(da[i]) for i in range(len(da) - 1)], + ), + If(p.o.stb & p.o.ack, + q.i.clr.eq(0), + ), + If(p.i.stb & p.i.ack, + q.i.clr.eq(self.clr), + ), + ] + self.comb += [ + a.o.ack.eq(self.ce), + p.o.ack.eq(self.ce), + f.o.ack.eq(self.ce), + q.i.stb.eq(self.ce), + eqh(q.i.p, p.o.a0), + q.i.f.eq(f.o.a0), + q.o.ack.eq(1), + ] + + c = [] + for i in range(parallelism): + ci = Cordic(width=width, widthz=p_width, + guard=None, eval_mode="pipelined") + self.submodules += ci + c.append(ci) + qoi = getattr(q.o, "z{}".format(i)) + self.comb += [ + ci.xi.eq(da[-1]), + ci.yi.eq(0), + eqh(ci.zi, qoi), + eqh(self.o[i][0], ci.xo), + eqh(self.o[i][1], ci.yo), + ] + self.latency += c[0].latency + self.gain = c[0].gain + + +class DDSSlow(Module): + def __init__(self, width, t_width, a_width, p_width, f_width, + a_order=4, p_order=1, f_order=2): + a = Spline(order=a_order, width=a_width) + p = Spline(order=p_order, width=p_width) + f = Spline(order=f_order, width=f_width) + self.submodules += a, p, f + + self.a = a.tri(t_width) + self.f = f.tri(t_width) + self.p = p.tri(t_width) + self.i = [self.a, self.f, self.p] + self.i_names = "a f p".split() + self.o = [Signal((width, True)) for i in range(2)] + self.ce = Signal() + self.clr = Signal() + self.latency = 0 # will be accumulated + + ### + + self.latency += p.latency + q = Accu(f_width) + self.latency += q.latency + da = CEInserter()(Delay)(width, q.latency) + c = Cordic(width=width, widthz=p_width, + guard=None, eval_mode="pipelined") + self.latency += c.latency + self.gain = c.gain + self.submodules += q, da, c + + self.sync += [ + If(p.o.stb & p.o.ack, + q.i.clr.eq(0), + ), + If(p.i.stb & p.i.ack, + q.i.clr.eq(self.clr), + ), + ] + self.comb += [ + da.ce.eq(q.i.stb & q.i.ack), + a.o.ack.eq(self.ce), + p.o.ack.eq(self.ce), + f.o.ack.eq(self.ce), + q.i.stb.eq(self.ce), + eqh(da.i, a.o.a0), + eqh(q.i.p, p.o.a0), + q.i.f.eq(f.o.a0), + q.o.ack.eq(1), + c.xi.eq(da.o), + c.yi.eq(0), + eqh(c.zi, q.o.z), + eqh(self.o[0], c.xo), + eqh(self.o[1], c.yo), + ] + + +class DDS(Module): + def __init__(self, width, t_width=None, + a_width=None, p_width=None, f_width=None, + a_order=4, p_order=1, f_order=2, parallelism=8): + if t_width is None: + t_width = width + if a_width is None: + a_width = width + (a_order - 1)*t_width + if p_width is None: + p_width = width + (p_order - 1)*t_width + if f_width is None: + f_width = width + (f_order + 1)*t_width + self.b = [DDSSlow(width, t_width, a_width, p_width, f_width, a_order, + p_order, f_order) for i in range(2)] + p = Spline(order=1, width=p_width) + f = Spline(order=1, width=f_width) + self.submodules += self.b, p, f + + self.f0 = f.tri(t_width) + self.p0 = p.tri(t_width) + self.i = [self.f0, self.p0] + self.i_names = "f0 p0".split() + for i, bi in enumerate(self.b): + self.i += bi.i + for ii in bi.i_names: + self.i_names.append("{}{}".format(ii, i + 1)) + for j in "afp": + setattr(self, "{}{}".format(j, i + 1), getattr(bi, j)) + self.o = [[Signal((width, True)) for i in range(2)] + for i in range(parallelism)] + self.ce = Signal() + self.clr = Signal() + self.parallelism = parallelism + self.latency = 0 # will be accumulated + + ### + + self.latency += self.b[0].latency # TODO: f0/p0, q.latency delta + q = PhasedAccu(f_width, parallelism) + self.submodules += q + + self.sync += [ + If(p.o.stb & p.o.ack, + q.i.clr.eq(0), + ), + If(p.i.stb & p.i.ack, + q.i.clr.eq(self.clr), + ), + ] + self.comb += [ + [bi.ce.eq(self.ce) for bi in self.b], + [bi.clr.eq(self.clr) for bi in self.b], + p.o.ack.eq(self.ce), + f.o.ack.eq(self.ce), + q.i.stb.eq(self.ce), + eqh(q.i.p, p.o.a0), + eqh(q.i.f, f.o.a0), + q.o.ack.eq(1), + ] + x = self.sat_add(bi.o[0] for bi in self.b) + y = self.sat_add(bi.o[1] for bi in self.b) + + c = [] + for i in range(parallelism): + ci = Cordic(width=width, widthz=p_width, + guard=None, eval_mode="pipelined") + self.submodules += ci + c.append(ci) + qoi = getattr(q.o, "z{}".format(i)) + self.comb += [ + ci.xi.eq(x), + ci.yi.eq(y), + eqh(ci.zi, qoi), + eqh(self.o[i][0], ci.xo), + eqh(self.o[i][1], ci.yo), + ] + self.latency += c[0].latency + self.gain = self.b[0].gain * c[0].gain + + +class Config(Module): + def __init__(self): + self.cfg = Record([("tap", 5), ("clr", 1), ("iq", 2)]) + self.i = Endpoint(self.cfg.layout) + self.ce = Signal() + + ### + + n = Signal(1 << len(self.i.tap)) + tap = Signal.like(self.i.tap) + clk = Signal() + clk0 = Signal() + + self.comb += [ + self.i.ack.eq(1), + clk.eq(Array(n)[tap]), + ] + self.sync += [ + clk0.eq(clk), + self.ce.eq(0), + If(clk0 ^ clk, + self.ce.eq(1), + ), + n.eq(n + 1), + If(self.i.stb, + n.eq(0), + self.cfg.eq(self.i.payload), + ), + ] + + +class Channel(Module): + def __init__(self, width=16, t_width=None, u_order=4, **kwargs): + if t_width is None: + t_width = width + du = Spline(width=width + (u_order - 1)*t_width, order=u_order) + da = DDS(width, t_width, **kwargs) + cfg = Config() + self.submodules += du, da, cfg + self.i = [cfg.i, du.tri(t_width)] + da.i + self.i_names = "cfg u".split() + da.i_names + self.q_i = [Signal((width, True)) for i in range(da.parallelism)] + self.q_o = [ai[1] for ai in da.o] + self.o = [Signal((width, True)) for i in range(da.parallelism)] + self.width = width + self.parallelism = da.parallelism + self.latency = da.latency + 1 + self.cordic_gain = da.gain + + ### + + # delay du to match da + ddu = Delay((width, True), da.latency - du.latency) + self.submodules += ddu + self.comb += [ + ddu.i.eq(du.o.a0[-width:]), + da.clr.eq(cfg.cfg.clr), + da.ce.eq(cfg.ce), + du.o.ack.eq(cfg.ce), + ] + # wire up outputs and q_{i,o} exchange + for oi, ai, qi in zip(self.o, da.o, self.q_i): + self.sync += [ + oi.eq(self.sat_add([ + ddu.o + + # du.o.a0[-width:], + Mux(cfg.cfg.iq[0], ai[0], 0), + Mux(cfg.cfg.iq[1], qi, 0)])), + ] + + def connect_q(self, buddy): + for i, qi in enumerate(self.q_i): + self.comb += qi.eq(buddy.q_o[i]) diff --git a/artiq/gateware/rtio/phy/sawg.py b/artiq/gateware/rtio/phy/sawg.py index fb520e968..b9abc64a5 100644 --- a/artiq/gateware/rtio/phy/sawg.py +++ b/artiq/gateware/rtio/phy/sawg.py @@ -3,20 +3,21 @@ from collections import namedtuple from migen import * from artiq.gateware.rtio import rtlink -from artiq.gateware.dsp.sawg import DDSFast +from artiq.gateware.dsp.sawg import Channel as _Channel _Phy = namedtuple("Phy", "rtlink probes overrides") -DDSFast_rtio = ClockDomainsRenamer("rio_phy")(DDSFast) +_ChannelPHY = ClockDomainsRenamer("rio_phy")(_Channel) -class Channel(DDSFast_rtio): +class Channel(_ChannelPHY): def __init__(self, *args, **kwargs): - DDSFast_rtio.__init__(self, *args, **kwargs) + _ChannelPHY.__init__(self, *args, **kwargs) self.phys = [] for i in self.i: - rl = rtlink.Interface(rtlink.OInterface(len(i.payload))) + rl = rtlink.Interface(rtlink.OInterface( + min(32, len(i.payload)))) # TODO: test/expand self.comb += [ i.stb.eq(rl.o.stb), rl.o.busy.eq(~i.ack), @@ -24,4 +25,5 @@ class Channel(DDSFast_rtio): ] # no probes, overrides self.phys.append(_Phy(rl, [], [])) - self.phys_names = dict(zip("afp", self.phys)) + self.phys_names = dict(zip("cfg f0 p0 a1 f1 p1 a2 f2 p2".split(), + self.phys))