From: Luke Kenneth Casson Leighton Date: Sun, 17 Feb 2019 07:16:22 +0000 (+0000) Subject: add beginning unit tests for 64-bit add X-Git-Tag: ls180-24jan2020~1934 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f68605ababcf961defbcf83005dff4699f83d373;p=ieee754fpu.git add beginning unit tests for 64-bit add --- diff --git a/src/add/fpbase.py b/src/add/fpbase.py index c10e5d9b..aba8c967 100644 --- a/src/add/fpbase.py +++ b/src/add/fpbase.py @@ -22,12 +22,19 @@ class FPNum: m_width = {32: 24, 64: 53}[width] e_width = {32: 10, 64: 13}[width] e_max = 1<<(e_width-3) + self.rmw = m_width # real mantissa width (not including extras) if m_extra: # mantissa extra bits (top,guard,round) - m_width += 3 - print (m_width, e_width, e_max) + self.m_extra = 3 + m_width += self.m_extra + else: + self.m_extra = 0 + print (m_width, e_width, e_max, self.rmw, self.m_extra) self.m_width = m_width self.e_width = e_width + self.e_start = self.rmw - 1 + self.e_end = self.rmw + self.e_width - 3 # for decoding + self.v = Signal(width) # Latched copy of value self.m = Signal(m_width) # Mantissa self.e = Signal((e_width, True)) # Exponent: 10 bits, signed @@ -47,10 +54,11 @@ class FPNum: is extended to 10 bits so that subtract 127 is done on a 10-bit number """ - args = [0] * (self.m_width-24) + [v[0:23]] # pad with extra zeros + args = [0] * self.m_extra + [v[0:self.e_start]] # pad with extra zeros + print (self.e_end) return [self.m.eq(Cat(*args)), # mantissa - self.e.eq(v[23:31] - self.P127), # exp (minus bias) - self.s.eq(v[31]), # sign + self.e.eq(v[self.e_start:self.e_end] - self.P127), # exp + self.s.eq(v[-1]), # sign ] def create(self, s, e, m): @@ -59,9 +67,9 @@ class FPNum: bias is added here, to the exponent """ return [ - self.v[31].eq(s), # sign - self.v[23:31].eq(e + self.P127), # exp (add on bias) - self.v[0:23].eq(m) # mantissa + self.v[-1].eq(s), # sign + self.v[self.e_start:self.e_end].eq(e + self.P127), # exp (add on bias) + self.v[0:self.e_start].eq(m) # mantissa ] def shift_down(self): @@ -75,7 +83,7 @@ class FPNum: ] def nan(self, s): - return self.create(s, self.P128, 1<<22) + return self.create(s, self.P128, 1<<(self.e_start-1)) def inf(self, s): return self.create(s, self.P128, 0) @@ -96,7 +104,7 @@ class FPNum: return (self.e > self.P127) def is_denormalised(self): - return (self.e == self.N126) & (self.m[23] == 0) + return (self.e == self.N126) & (self.m[self.e_start] == 0) class FPOp: @@ -144,7 +152,7 @@ class FPBase: """ denormalises a number """ with m.If(a.e == a.N127): - m.d.sync += a.e.eq(-126) # limit a exponent + m.d.sync += a.e.eq(a.N126) # limit a exponent with m.Else(): m.d.sync += a.m[-1].eq(1) # set top mantissa bit @@ -214,7 +222,7 @@ class FPBase: m.next = next_state # denormalised, correct exponent to zero with m.If(z.is_denormalised()): - m.d.sync += z.m.eq(-127) + m.d.sync += z.m.eq(z.N127) # FIX SIGN BUG: -a + a = +0. with m.If((z.e == z.N126) & (z.m[0:] == 0)): m.d.sync += z.s.eq(0) diff --git a/src/add/nmigen_add_experiment.py b/src/add/nmigen_add_experiment.py index efb0c8bf..da372682 100644 --- a/src/add/nmigen_add_experiment.py +++ b/src/add/nmigen_add_experiment.py @@ -2,7 +2,7 @@ # Copyright (C) Jonathan P Dawson 2013 # 2013-12-12 -from nmigen import Module, Signal +from nmigen import Module, Signal, Cat from nmigen.cli import main, verilog from fpbase import FPNum, FPOp, Overflow, FPBase @@ -28,7 +28,8 @@ class FPADD(FPBase): b = FPNum(self.width) z = FPNum(self.width, False) - tot = Signal(28) # sticky/round/guard bits, 23 result, 1 overflow + w = {32: 28, 64:57}[self.width] + tot = Signal(w) # sticky/round/guard, {mantissa} result, 1 overflow of = Overflow() @@ -74,17 +75,17 @@ class FPADD(FPBase): # if a is zero and b zero return signed-a/b with m.Elif(a.is_zero() & b.is_zero()): m.next = "put_z" - m.d.sync += z.create(a.s & b.s, b.e[0:8], b.m[3:-1]) + m.d.sync += z.create(a.s & b.s, b.e, b.m[3:-1]) # if a is zero return b with m.Elif(a.is_zero()): m.next = "put_z" - m.d.sync += z.create(b.s, b.e[0:8], b.m[3:-1]) + m.d.sync += z.create(b.s, b.e, b.m[3:-1]) # if b is zero return a with m.Elif(b.is_zero()): m.next = "put_z" - m.d.sync += z.create(a.s, a.e[0:8], a.m[3:-1]) + m.d.sync += z.create(a.s, a.e, a.m[3:-1]) # Denormalised Number checks with m.Else(): @@ -118,19 +119,19 @@ class FPADD(FPBase): # same-sign (both negative or both positive) add mantissas with m.If(a.s == b.s): m.d.sync += [ - tot.eq(a.m + b.m), + tot.eq(Cat(a.m, 0) + Cat(b.m, 0)), z.s.eq(a.s) ] # a mantissa greater than b, use a with m.Elif(a.m >= b.m): m.d.sync += [ - tot.eq(a.m - b.m), + tot.eq(Cat(a.m, 0) - Cat(b.m, 0)), z.s.eq(a.s) ] # b mantissa greater than a, use b with m.Else(): m.d.sync += [ - tot.eq(b.m - a.m), + tot.eq(Cat(b.m, 0) - Cat(a.m, 0)), z.s.eq(b.s) ] @@ -141,9 +142,9 @@ class FPADD(FPBase): with m.State("add_1"): m.next = "normalise_1" # tot[27] gets set when the sum overflows. shift result down - with m.If(tot[27]): + with m.If(tot[-1]): m.d.sync += [ - z.m.eq(tot[4:28]), + z.m.eq(tot[4:]), of.guard.eq(tot[3]), of.round_bit.eq(tot[2]), of.sticky.eq(tot[1] | tot[0]), @@ -152,7 +153,7 @@ class FPADD(FPBase): # tot[27] zero case with m.Else(): m.d.sync += [ - z.m.eq(tot[3:27]), + z.m.eq(tot[3:]), of.guard.eq(tot[2]), of.round_bit.eq(tot[1]), of.sticky.eq(tot[0]) diff --git a/src/add/test_add64.py b/src/add/test_add64.py new file mode 100644 index 00000000..c7977164 --- /dev/null +++ b/src/add/test_add64.py @@ -0,0 +1,90 @@ +from nmigen import Module, Signal +from nmigen.compat.sim import run_simulation + +from nmigen_add_experiment import FPADD + +class ORGate: + def __init__(self): + self.a = Signal() + self.b = Signal() + self.x = Signal() + + def get_fragment(self, platform=None): + + m = Module() + m.d.comb += self.x.eq(self.a | self.b) + + return m + +def check_case(dut, a, b, z): + yield dut.in_a.v.eq(a) + yield dut.in_a.stb.eq(1) + yield + yield + a_ack = (yield dut.in_a.ack) + assert a_ack == 0 + yield dut.in_b.v.eq(b) + yield dut.in_b.stb.eq(1) + b_ack = (yield dut.in_b.ack) + assert b_ack == 0 + + while True: + yield + out_z_stb = (yield dut.out_z.stb) + if not out_z_stb: + continue + yield dut.in_a.stb.eq(0) + yield dut.in_b.stb.eq(0) + yield dut.out_z.ack.eq(1) + yield + yield dut.out_z.ack.eq(0) + yield + yield + break + + out_z = yield dut.out_z.v + assert out_z == z, "Output z 0x%x not equal to expected 0x%x" % (out_z, z) + +def testbench(dut): + yield from check_case(dut, 0, 0, 0) + yield from check_case(dut, 0x3FF0000000000000, 0x4000000000000000, + 0x4008000000000000) + yield from check_case(dut, 0x4000000000000000, 0x3FF0000000000000, + 0x4008000000000000) + yield from check_case(dut, 0x4056C00000000000, 0x4042800000000000, + 0x4060000000000000) + yield from check_case(dut, 0x4056C00000000000, 0x4042EA3D70A3D70A, + 0x40601A8F5C28F5C2) + + if False: + yield from check_case(dut, 0x40000000, 0x3F800000, 0x40400000) + yield from check_case(dut, 0x447A0000, 0x4488B000, 0x4502D800) + yield from check_case(dut, 0x463B800A, 0x42BA8A3D, 0x463CF51E) + yield from check_case(dut, 0x42BA8A3D, 0x463B800A, 0x463CF51E) + yield from check_case(dut, 0x463B800A, 0xC2BA8A3D, 0x463A0AF6) + yield from check_case(dut, 0xC2BA8A3D, 0x463B800A, 0x463A0AF6) + yield from check_case(dut, 0xC63B800A, 0x42BA8A3D, 0xC63A0AF6) + yield from check_case(dut, 0x42BA8A3D, 0xC63B800A, 0xC63A0AF6) + yield from check_case(dut, 0xFFFFFFFF, 0xC63B800A, 0xFFC00000) + yield from check_case(dut, 0x7F800000, 0x00000000, 0x7F800000) + yield from check_case(dut, 0x00000000, 0x7F800000, 0x7F800000) + yield from check_case(dut, 0xFF800000, 0x00000000, 0xFF800000) + yield from check_case(dut, 0x00000000, 0xFF800000, 0xFF800000) + yield from check_case(dut, 0x7F800000, 0x7F800000, 0x7F800000) + yield from check_case(dut, 0xFF800000, 0xFF800000, 0xFF800000) + yield from check_case(dut, 0x7F800000, 0xFF800000, 0xFFC00000) + yield from check_case(dut, 0xFF800000, 0x7F800000, 0x7FC00000) + yield from check_case(dut, 0x00018643, 0x00FA72A4, 0x00FBF8E7) + yield from check_case(dut, 0x001A2239, 0x00FA72A4, 0x010A4A6E) + yield from check_case(dut, 0x3F7FFFFE, 0x3F7FFFFE, 0x3FFFFFFE) + yield from check_case(dut, 0x7EFFFFEE, 0x7EFFFFEE, 0x7F7FFFEE) + yield from check_case(dut, 0x7F7FFFEE, 0xFEFFFFEE, 0x7EFFFFEE) + yield from check_case(dut, 0x7F7FFFEE, 0x756CA884, 0x7F7FFFFD) + yield from check_case(dut, 0x7F7FFFEE, 0x758A0CF8, 0x7F7FFFFF) + #yield from check_case(dut, 1, 0, 1) + #yield from check_case(dut, 1, 1, 1) + +if __name__ == '__main__': + dut = FPADD(width=64) + run_simulation(dut, testbench(dut), vcd_name="test_add64.vcd") +