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
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):
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):
]
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)
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:
""" 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
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)
# 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
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()
# 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():
# 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)
]
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]),
# 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])
--- /dev/null
+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")
+