diff --git a/artiq/gateware/dsp/sawg.py b/artiq/gateware/dsp/sawg.py index 540751be0..2be9a795a 100644 --- a/artiq/gateware/dsp/sawg.py +++ b/artiq/gateware/dsp/sawg.py @@ -5,7 +5,7 @@ from misoc.interconnect.stream import Endpoint from misoc.cores.cordic import Cordic from .accu import PhasedAccu -from .tools import eqh, Delay, SatAddMixin +from .tools import eqh, SatAddMixin from .spline import Spline from .fir import ParallelHBFUpsampler, halfgen4_cascade @@ -14,44 +14,10 @@ _Widths = namedtuple("_Widths", "t a p f") _Orders = namedtuple("_Orders", "a p f") -class ParallelDDS(Module): - def __init__(self, widths, parallelism=1, a_delay=0): - self.i = Endpoint([("x", widths.a), ("y", widths.a), - ("f", widths.f), ("p", widths.f), ("clr", 1)]) +class SplineParallelDUC(Module): + def __init__(self, widths, orders, parallelism=1, **kwargs): self.parallelism = parallelism self.widths = widths - - ### - - accu = PhasedAccu(widths.f, parallelism) - cordic = [Cordic(width=widths.a, widthz=widths.p, guard=None, - eval_mode="pipelined") for i in range(parallelism)] - self.xo = [c.xo for c in cordic] - self.yo = [c.yo for c in cordic] - a_delay += accu.latency - xy_delay = Delay(2*widths.a, max(0, a_delay)) - z_delay = Delay(parallelism*widths.p, max(0, -a_delay)) - self.submodules += accu, xy_delay, z_delay, cordic - self.latency = max(0, a_delay) + cordic[0].latency - self.gain = cordic[0].gain - - 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())), - eqh(accu.i.p, self.i.p), - accu.i.f.eq(self.i.f), - accu.i.clr.eq(self.i.clr), - accu.i.stb.eq(self.i.stb), - 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), - ] - - -class SplineParallelDUC(ParallelDDS): - def __init__(self, widths, orders, **kwargs): p = Spline(order=orders.p, width=widths.p) f = Spline(order=orders.f, width=widths.f) self.f = f.tri(widths.t) @@ -59,27 +25,41 @@ class SplineParallelDUC(ParallelDDS): self.submodules += p, f self.ce = Signal(reset=1) self.clr = Signal() - super().__init__(widths._replace(p=len(self.p.a0), f=len(self.f.a0)), - **kwargs) - self.latency += f.latency + + ### + accu = PhasedAccu(len(self.f.a0), parallelism) + cordic = [Cordic(width=widths.a, widthz=len(self.p.a0), guard=None, + eval_mode="pipelined") for i in range(parallelism)] + self.submodules += accu, cordic + + self.xi = [c.xi for c in cordic] + self.yi = [c.yi for c in cordic] + self.xo = [c.xo for c in cordic] + self.yo = [c.yo for c in cordic] + self.latency = cordic[0].latency + self.gain = cordic[0].gain + self.f.latency += accu.latency + self.latency + self.p.latency += accu.latency + self.latency ### assert p.latency == f.latency - self.comb += [ p.o.ack.eq(self.ce), f.o.ack.eq(self.ce), - eqh(self.i.f, f.o.a0), - eqh(self.i.p, p.o.a0), - self.i.stb.eq(p.o.stb | f.o.stb), + eqh(accu.i.f, f.o.a0), + eqh(accu.i.p, p.o.a0), + accu.i.stb.eq(p.o.stb | f.o.stb), + accu.o.ack.eq(1), + [eqh(c.zi, zi) for c, zi in + zip(cordic, accu.o.payload.flatten())] ] assert p.latency == 1 self.sync += [ - self.i.clr.eq(0), + accu.i.clr.eq(0), If(p.i.stb, - self.i.clr.eq(self.clr), + accu.i.clr.eq(self.clr), ), ] @@ -91,12 +71,14 @@ class SplineParallelDDS(SplineParallelDUC): self.submodules += a super().__init__(widths._replace(a=len(self.a.a0)), orders, **kwargs) + self.a.latency += self.latency + ### self.comb += [ a.o.ack.eq(self.ce), - eqh(self.i.x, a.o.a0), - self.i.y.eq(0), + [eqh(x, a.o.a0) for x in self.xi], + [y.eq(0) for y in self.yi], ] @@ -151,12 +133,11 @@ class Channel(Module, SatAddMixin): hbf = [ParallelHBFUpsampler(coeff, width=width, shift=17) for i in range(2)] self.submodules.b = b = SplineParallelDUC( - widths._replace(a=len(a1.xo[0]), f=widths.f - width), orders, - parallelism=parallelism, a_delay=-a1.latency-hbf[0].latency) + widths._replace(a=len(hbf[0].o[0]), f=widths.f - width), orders, + parallelism=parallelism) cfg = Config(widths.a) u = Spline(width=widths.a, order=orders.a) - du = Delay(width, a1.latency + hbf[0].latency + b.latency - u.latency) - self.submodules += cfg, u, du, hbf + self.submodules += cfg, u, hbf self.u = u.tri(widths.t) 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() @@ -166,9 +147,23 @@ class Channel(Module, SatAddMixin): self.widths = widths self.orders = orders self.parallelism = parallelism - self.latency = a1.latency + hbf[0].latency + b.latency + 2 self.cordic_gain = a1.gain*b.gain + self.u.latency += 1 + b.p.latency += 2 + b.f.latency += 2 + a_latency_delta = hbf[0].latency + b.latency + 2 + for a in a1, a2: + a.a.latency += a_latency_delta + a.p.latency += a_latency_delta + a.f.latency += a_latency_delta + + self.latency = max(_.latency for _ in self.i[1:]) + for i in self.i[1:]: + i.latency -= self.latency + assert i.latency <= 0 + cfg.i.latency = 0 + ### self.comb += [ @@ -177,8 +172,8 @@ class Channel(Module, SatAddMixin): b.ce.eq(cfg.ce), u.o.ack.eq(cfg.ce), Cat(a1.clr, a2.clr, b.clr).eq(cfg.clr), - b.i.x.eq(hbf[0].o[0]), # FIXME: rip up - b.i.y.eq(hbf[1].o[0]), + Cat(b.xi).eq(Cat(hbf[0].o)), + Cat(b.yi).eq(Cat(hbf[1].o)), ] self.sync += [ hbf[0].i.eq(self.sat_add(a1.xo[0], a2.xo[0], @@ -187,14 +182,16 @@ class Channel(Module, SatAddMixin): hbf[1].i.eq(self.sat_add(a1.yo[0], a2.yo[0], limits=cfg.limits[1], clipped=cfg.clipped[1])), - eqh(du.i, u.o.a0), ] # 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, Mux(cfg.iq_en[0], x, 0), Mux(cfg.iq_en[1], y, 0), - limits=cfg.limits[2], clipped=cfg.clipped[2])), + u.o.a0[-len(o):], + Mux(cfg.iq_en[0], x, 0), + Mux(cfg.iq_en[1], y, 0), + limits=cfg.limits[2], + clipped=cfg.clipped[2])), ] def connect_y(self, buddy): diff --git a/artiq/gateware/dsp/spline.py b/artiq/gateware/dsp/spline.py index 0061653dc..8185ae856 100644 --- a/artiq/gateware/dsp/spline.py +++ b/artiq/gateware/dsp/spline.py @@ -37,6 +37,7 @@ class Spline(Module): enumerate(self.i.payload.layout[::-1])] layout.reverse() i = Endpoint(layout) + i.latency = self.latency self.comb += [ self.i.stb.eq(i.stb), i.ack.eq(self.i.ack), diff --git a/artiq/gateware/rtio/phy/sawg.py b/artiq/gateware/rtio/phy/sawg.py index 84094f5a2..9bbce3c04 100644 --- a/artiq/gateware/rtio/phy/sawg.py +++ b/artiq/gateware/rtio/phy/sawg.py @@ -16,7 +16,8 @@ class Channel(_ChannelPHY): _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(len(i.payload), + delay=-i.latency)) self.comb += [ i.stb.eq(rl.o.stb), rl.o.busy.eq(~i.ack),