artiq/artiq/gateware/dsp/tools.py

70 lines
2.1 KiB
Python

from operator import add
from functools import reduce
from migen import *
class Delay(Module):
def __init__(self, i, delay, o=None):
if isinstance(i, (int, tuple)):
z = [Signal(i) for j in range(delay + 1)]
elif isinstance(i, list):
z = [Record(i) for j in range(delay + 1)]
elif isinstance(i, Record):
z = [Record(i.layout) for j in range(delay + 1)]
else:
z = [Signal.like(i) for j in range(delay + 1)]
self.i = z[0]
self.o = z[-1]
if not isinstance(i, (int, list, tuple)):
self.comb += self.i.eq(i)
if o is not None:
self.comb += o.eq(self.o)
self.latency = delay
self.sync += [z[j + 1].eq(z[j]) for j in range(delay)]
def eqh(a, b):
return a[-len(b):].eq(b[-len(a):])
class SatAddMixin:
"""Signed saturating addition mixin"""
def sat_add(self, a, width, limits=None, clipped=None):
a = list(a)
# assert all(value_bits_sign(ai)[1] for ai in a)
max_width = max(value_bits_sign(ai)[0] for ai in a)
carry = log2_int(len(a), need_pow2=False)
full = Signal((max_width + carry, True))
limited = Signal((width, True))
carry = len(full) - width
assert carry >= 0
clip = Signal(2)
sign = Signal()
if clipped is not None:
self.comb += clipped.eq(clip)
self.comb += [
full.eq(reduce(add, a)),
sign.eq(full[-1]),
limited.eq(full)
]
if limits is None:
self.comb += [
If(full[-1-carry:] != Replicate(sign, carry + 1),
clip.eq(Cat(sign, ~sign)),
limited.eq(Cat(Replicate(~sign, width - 1), sign)),
)
]
else:
self.comb += [
If(full < limits[0],
clip.eq(0b01),
limited.eq(limits[0])
),
If(full > limits[1],
clip.eq(0b10),
limited.eq(limits[1]),
)
]
return limited