X-Git-Url: https://git.libre-soc.org/?p=ieee754fpu.git;a=blobdiff_plain;f=src%2Fieee754%2Fpart%2Fpartsig.py;h=24fd80d4cb7985588a134a8789a1b2add2d480dd;hp=75417cfdb06c121613c0883a709779bd205131bd;hb=a91387d34bc1ce5807a5b8a33d919e1c78144fa8;hpb=881d9f14be2bc15d5102064054dd4e58063cc8e6 diff --git a/src/ieee754/part/partsig.py b/src/ieee754/part/partsig.py index 75417cfd..24fd80d4 100644 --- a/src/ieee754/part/partsig.py +++ b/src/ieee754/part/partsig.py @@ -18,9 +18,10 @@ nmigen.Case, or other constructs: only Mux and other logic. 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) @@ -39,11 +40,14 @@ def applyop(op1, op2, op): 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): @@ -56,15 +60,27 @@ class PartitionedSignal: def eq(self, val): return self.sig.eq(getsig(val)) + @staticmethod + def like(other, *args, **kwargs): + """Builds a new PartitionedSignal with the same PartitionPoints and + Signal properties as the other""" + result = PartitionedSignal(other.partpoints) + result.sig = Signal.like(other.sig, *args, **kwargs) + result.m = other.m + return result + # unary ops that do not require partitioning def __invert__(self): - return ~self.sig + result = PartitionedSignal.like(self) + self.m.d.comb += result.sig.eq(~self.sig) + return result # 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 @@ -92,31 +108,32 @@ class PartitionedSignal: # 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): scalar = True - shape = op1.shape() - pa = PartitionedScalarShift(shape[0], self.partpoints) + 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 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): @@ -124,8 +141,9 @@ class PartitionedSignal: 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 @@ -134,8 +152,7 @@ class PartitionedSignal: 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) @@ -146,8 +163,7 @@ class PartitionedSignal: 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) @@ -228,30 +244,32 @@ class PartitionedSignal: 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 @@ -264,8 +282,8 @@ class PartitionedSignal: 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``. @@ -275,7 +293,7 @@ class PartitionedSignal: 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): @@ -286,8 +304,7 @@ class PartitionedSignal: 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. @@ -298,9 +315,11 @@ class PartitionedSignal: ``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. @@ -312,4 +331,4 @@ class PartitionedSignal: ``1`` otherwise. """ # amazingly, this should actually work. - return ~premise | conclusion + return conclusion | ~premise