From 51a14e0cd1245876b065be25d463c8e6509d30df Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Sun, 3 Mar 2019 23:13:51 +0000 Subject: [PATCH] unit test for multi-bit shift right with merge (sticky bit) --- src/add/fpbase.py | 36 +++++++++++-------------------- src/add/test_multishift.py | 43 +++++++++++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 25 deletions(-) diff --git a/src/add/fpbase.py b/src/add/fpbase.py index 58b4994a..d6a059e0 100644 --- a/src/add/fpbase.py +++ b/src/add/fpbase.py @@ -184,30 +184,19 @@ class FPNumOut(FPNumBase): return self.create(s, self.N127, 0) -class FPNumShiftMultiRight(FPNumBase): - """ shifts a mantissa down. exponent is increased to compensate - - accuracy is lost as a result in the mantissa however there are 3 - guard bits (the latter of which is the "sticky" bit) - - this code works by variable-shifting the mantissa by up to - its maximum bit-length: no point doing more (it'll still be - zero). - - the sticky bit is computed by shifting a batch of 1s by - the same amount, which will introduce zeros. it's then - inverted and used as a mask to get the LSBs of the mantissa. - those are then |'d into the sticky bit. +class MultiShiftRMerge: + """ shifts down (right) and merges lower bits into m[0]. + m[0] is the "sticky" bit, basically """ - def __init__(self, inp, diff, width): + def __init__(self, width): + self.smax = int(log(width) / log(2)) self.m = Signal(width, reset_less=True) - self.inp = inp - self.diff = diff + self.inp = Signal(width, reset_less=True) + self.diff = Signal(self.smax, reset_less=True) self.width = width def elaborate(self, platform): m = Module() - #m.submodules.inp = self.inp rs = Signal(self.width, reset_less=True) m_mask = Signal(self.width, reset_less=True) @@ -215,18 +204,17 @@ class FPNumShiftMultiRight(FPNumBase): stickybit = Signal(reset_less=True) sm = MultiShift(self.width-1) + m0s = Const(0, self.width-1) mw = Const(self.width-1, len(self.diff)) maxslen = Mux(self.diff > mw, mw, self.diff) maxsleni = mw - maxslen m.d.comb += [ # shift mantissa by maxslen, mask by inverse - rs.eq(sm.rshift(self.inp.m[1:], maxslen)), - m_mask.eq(sm.rshift(self.inp.m1s[1:], maxsleni)), - smask.eq(self.inp.m[1:] & m_mask), + rs.eq(sm.rshift(self.inp[1:], maxslen)), + m_mask.eq(sm.rshift(~m0s, maxsleni)), + smask.eq(self.inp[1:] & m_mask), # sticky bit combines all mask (and mantissa low bit) - stickybit.eq(smask.bool() | self.inp.m[0]), - #self.s.eq(self.inp.s), - #self.e.eq(self.inp.e + diff), + stickybit.eq(smask.bool() | self.inp[0]), # mantissa result contains m[0] already. self.m.eq(Cat(stickybit, rs)) ] diff --git a/src/add/test_multishift.py b/src/add/test_multishift.py index 5fa649ef..2aa6ba33 100644 --- a/src/add/test_multishift.py +++ b/src/add/test_multishift.py @@ -2,7 +2,7 @@ from random import randint from nmigen import Module, Signal from nmigen.compat.sim import run_simulation -from fpbase import MultiShift, MultiShiftR +from fpbase import MultiShift, MultiShiftR, MultiShiftRMerge class MultiShiftModL: def __init__(self, width): @@ -49,6 +49,24 @@ class MultiShiftModRMod: return m +class MultiShiftRMergeMod: + def __init__(self, width): + self.ms = MultiShiftRMerge(width) + self.a = Signal(width) + self.b = Signal(self.ms.smax) + self.x = Signal(width) + + def get_fragment(self, platform=None): + + m = Module() + m.submodules += self.ms + m.d.comb += self.ms.inp.eq(self.a) + m.d.comb += self.ms.diff.eq(self.b) + m.d.comb += self.x.eq(self.ms.m) + + return m + + def check_case(dut, width, a, b): yield dut.a.eq(a) yield dut.b.eq(b) @@ -69,6 +87,27 @@ def check_caser(dut, width, a, b): out_x = yield dut.x assert out_x == x, "Output x 0x%x not equal to expected 0x%x" % (out_x, x) + +def check_case_merge(dut, width, a, b): + yield dut.a.eq(a) + yield dut.b.eq(b) + yield + + x = (a >> b) & ((1<