from ieee754.part_mul_add.adder import PartitionedAdder
from ieee754.part_cmp.eq_gt_ge import PartitionedEqGtGe
+from ieee754.part_bits.xor import PartitionedXOR
from ieee754.part_shift.part_shift_dynamic import PartitionedDynamicShift
from ieee754.part_shift.part_shift_scalar import PartitionedScalarShift
-from ieee754.part_mul_add.partpoints import make_partition
+from ieee754.part_mul_add.partpoints import make_partition, PartitionPoints
from operator import or_, xor, and_, not_
from nmigen import (Signal, Const)
class PartitionedSignal:
def __init__(self, mask, *args, **kwargs):
self.sig = Signal(*args, **kwargs)
- width = self.sig.shape()[0] # get signal width
+ width = len(self.sig) # get signal width
# create partition points
- self.partpoints = make_partition(mask, width)
+ if isinstance(mask, PartitionPoints):
+ self.partpoints = mask
+ else:
+ self.partpoints = make_partition(mask, width)
self.modnames = {}
- for name in ['add', 'eq', 'gt', 'ge', 'ls']:
+ for name in ['add', 'eq', 'gt', 'ge', 'ls', 'xor']:
self.modnames[name] = 0
def set_module(self, m):
def get_modname(self, category):
self.modnames[category] += 1
- return "%s%d" % (category, self.modnames[category])
+ return "%s_%d" % (category, self.modnames[category])
def eq(self, val):
return self.sig.eq(getsig(val))
# unary ops that require partitioning
def __neg__(self):
- result, _ = self.add_op(self, ~0, carry=0) # TODO, subop
+ z = Const(0, len(self.sig))
+ result, _ = self.sub_op(z, self)
return result
# binary ops that don't require partitioning
# TODO: detect if the 2nd operand is a Const, a Signal or a
# PartitionedSignal. if it's a Const or a Signal, a global shift
# can occur. if it's a PartitionedSignal, that's much more interesting.
- def ls_op(self, op1, op2, carry):
+ def ls_op(self, op1, op2, carry, shr_flag=0):
op1 = getsig(op1)
if isinstance(op2, Const) or isinstance(op2, Signal):
- shape = op1.shape()
- pa = PartitionedScalarShift(shape[0], self.partpoints)
+ scalar = True
+ pa = PartitionedScalarShift(len(op1), self.partpoints)
else:
+ scalar = False
op2 = getsig(op2)
- shape = op1.shape()
- pa = PartitionedDynamicShift(shape[0], self.partpoints)
+ pa = PartitionedDynamicShift(len(op1), self.partpoints)
setattr(self.m.submodules, self.get_modname('ls'), pa)
comb = self.m.d.comb
- if isinstance(op2, Const) or isinstance(op2, Signal):
- comb += pa.a.eq(op1)
- comb += pa.b.eq(op2)
- else:
+ if scalar:
comb += pa.data.eq(op1)
comb += pa.shifter.eq(op2)
+ comb += pa.shift_right.eq(shr_flag)
+ else:
+ comb += pa.a.eq(op1)
+ comb += pa.b.eq(op2)
+ comb += pa.shift_right.eq(shr_flag)
# XXX TODO: carry-in, carry-out
#comb += pa.carry_in.eq(carry)
return (pa.output, 0)
def __lshift__(self, other):
- result, _ = self.ls_op(self, other, carry=0)
+ z = Const(0, len(self.partpoints)+1)
+ result, _ = self.ls_op(self, other, carry=z) # TODO, carry
return result
def __rlshift__(self, other):
return Operator("<<", [other, self])
def __rshift__(self, other):
- raise NotImplementedError
- return Operator(">>", [self, other])
+ z = Const(0, len(self.partpoints)+1)
+ result, _ = self.ls_op(self, other, carry=z, shr_flag=1) # TODO, carry
+ return result
def __rrshift__(self, other):
raise NotImplementedError
def add_op(self, op1, op2, carry):
op1 = getsig(op1)
op2 = getsig(op2)
- shape = op1.shape()
- pa = PartitionedAdder(shape[0], self.partpoints)
+ pa = PartitionedAdder(len(op1), self.partpoints)
setattr(self.m.submodules, self.get_modname('add'), pa)
comb = self.m.d.comb
comb += pa.a.eq(op1)
def sub_op(self, op1, op2, carry=~0):
op1 = getsig(op1)
op2 = getsig(op2)
- shape = op1.shape()
- pa = PartitionedAdder(shape[0], self.partpoints)
+ pa = PartitionedAdder(len(op1), self.partpoints)
setattr(self.m.submodules, self.get_modname('add'), pa)
comb = self.m.d.comb
comb += pa.a.eq(op1)
return pa.output
def __eq__(self, other):
- width = self.sig.shape()[0]
+ width = len(self.sig)
return self._compare(width, self, other, "eq", PartitionedEqGtGe.EQ)
def __ne__(self, other):
- width = self.sig.shape()[0]
+ width = len(self.sig)
eq = self._compare(width, self, other, "eq", PartitionedEqGtGe.EQ)
ne = Signal(eq.width)
self.m.d.comb += ne.eq(~eq)
return ne
def __gt__(self, other):
- width = self.sig.shape()[0]
+ width = len(self.sig)
return self._compare(width, self, other, "gt", PartitionedEqGtGe.GT)
def __lt__(self, other):
- width = self.sig.shape()[0]
+ width = len(self.sig)
+ # swap operands, use gt to do lt
return self._compare(width, other, self, "gt", PartitionedEqGtGe.GT)
def __ge__(self, other):
- width = self.sig.shape()[0]
+ width = len(self.sig)
return self._compare(width, self, other, "ge", PartitionedEqGtGe.GE)
def __le__(self, other):
- width = self.sig.shape()[0]
+ width = len(self.sig)
+ # swap operands, use ge to do le
return self._compare(width, other, self, "ge", PartitionedEqGtGe.GE)
# useful operators
Value, out
``1`` if any bits are set, ``0`` otherwise.
"""
- raise NotImplementedError
- return Operator("b", [self])
+ return self.any() # have to see how this goes
+ #return Operator("b", [self])
def any(self):
"""Check if any bits are ``1``.
Value, out
``1`` if any bits are set, ``0`` otherwise.
"""
- raise NotImplementedError
+ return self != Const(0) # leverage the __ne__ operator here
return Operator("r|", [self])
def all(self):
Value, out
``1`` if all bits are set, ``0`` otherwise.
"""
- raise NotImplementedError
- return Operator("r&", [self])
+ return self == Const(-1) # leverage the __eq__ operator here
def xor(self):
"""Compute pairwise exclusive-or of every bit.
``1`` if an odd number of bits are set, ``0`` if an
even number of bits are set.
"""
- # XXXX TODO: return partition-mask-sized set of bits
- raise NotImplementedError
- return Operator("r^", [self])
+ width = len(self.sig)
+ pa = PartitionedXOR(width, self.partpoints)
+ setattr(self.m.submodules, self.get_modname("xor"), pa)
+ self.m.d.comb += pa.a.eq(self.sig)
+ return pa.output
def implies(premise, conclusion):
"""Implication.
``1`` otherwise.
"""
# amazingly, this should actually work.
- return ~premise | conclusion
+ return conclusion | ~premise