forked from M-Labs/artiq
189 lines
6.1 KiB
Python
189 lines
6.1 KiB
Python
from collections import namedtuple
|
|
|
|
from migen import *
|
|
from misoc.interconnect.stream import Endpoint
|
|
from misoc.cores.cordic import Cordic
|
|
|
|
from .accu import PhasedAccu, Accu
|
|
from .tools import eqh, Delay, SatAddMixin
|
|
from .spline import Spline
|
|
|
|
|
|
_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)])
|
|
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)
|
|
self.p = p.tri(widths.t)
|
|
self.submodules += p, f
|
|
self.ce = Signal(reset=1)
|
|
self.clr = Signal()
|
|
super().__init__(widths._replace(p=len(self.f.a0), f=len(self.f.a0)),
|
|
**kwargs)
|
|
self.latency += f.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),
|
|
]
|
|
|
|
assert p.latency == 1
|
|
self.sync += [
|
|
self.i.clr.eq(0),
|
|
If(p.i.stb,
|
|
self.i.clr.eq(self.clr),
|
|
),
|
|
]
|
|
|
|
|
|
class SplineParallelDDS(SplineParallelDUC):
|
|
def __init__(self, widths, orders, **kwargs):
|
|
a = Spline(order=orders.a, width=widths.a)
|
|
self.a = a.tri(widths.t)
|
|
self.submodules += a
|
|
super().__init__(widths._replace(a=len(self.a.a0)),
|
|
orders, **kwargs)
|
|
|
|
###
|
|
|
|
self.comb += [
|
|
a.o.ack.eq(self.ce),
|
|
eqh(self.i.x, a.o.a0),
|
|
self.i.y.eq(0),
|
|
]
|
|
|
|
|
|
class Config(Module):
|
|
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, reset=0)
|
|
n = Signal.like(div)
|
|
pad = Signal()
|
|
|
|
reg = Array([Cat(div, n), self.clr, self.iq_en, pad] +
|
|
sum(self.limit, []))
|
|
|
|
self.comb += [
|
|
self.i.ack.eq(1),
|
|
self.ce.eq(n == 0),
|
|
]
|
|
self.sync += [
|
|
n.eq(n - 1),
|
|
If(self.ce,
|
|
n.eq(div),
|
|
),
|
|
If(self.i.stb,
|
|
reg[self.i.addr].eq(self.i.data),
|
|
),
|
|
]
|
|
|
|
|
|
class Channel(Module, SatAddMixin):
|
|
def __init__(self, width=16, parallelism=4, widths=None, orders=None):
|
|
if orders is None:
|
|
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=(orders.f + 2)*width)
|
|
|
|
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, u, du
|
|
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()
|
|
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
|
|
self.latency = a1.latency + b.latency + 1
|
|
self.cordic_gain = a1.gain*b.gain
|
|
|
|
###
|
|
|
|
self.comb += [
|
|
a1.ce.eq(cfg.ce),
|
|
a2.ce.eq(cfg.ce),
|
|
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(self.sat_add([a1.xo[0], a2.xo[0]])),
|
|
b.i.y.eq(self.sat_add([a1.yo[0], a2.yo[0]])),
|
|
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)])),
|
|
]
|
|
|
|
def connect_y(self, buddy):
|
|
self.comb += Cat(buddy.y_in).eq(Cat(self.b.yo))
|