from nmigen.cli import main, verilog
from fpbase import FPNumIn, FPNumOut, FPOp, Overflow, FPBase, FPNumBase
-from fpbase import MultiShiftRMerge
+from fpbase import MultiShiftRMerge, Trigger
#from fpbase import FPNumShiftMultiRight
class FPState(FPBase):
m.d.sync += self.in_op.ack.eq(1)
+class FPGet2OpMod(Trigger):
+ def __init__(self, width):
+ Trigger.__init__(self)
+ self.in_op1 = Signal(width, reset_less=True)
+ self.in_op2 = Signal(width, reset_less=True)
+ self.out_op1 = FPNumIn(None, width)
+ self.out_op2 = FPNumIn(None, width)
+
+ def elaborate(self, platform):
+ m = Trigger.elaborate(self, platform)
+ #m.submodules.get_op_in = self.in_op
+ m.submodules.get_op1_out = self.out_op1
+ m.submodules.get_op2_out = self.out_op2
+ with m.If(self.trigger):
+ m.d.comb += [
+ self.out_op1.decode(self.in_op1),
+ self.out_op2.decode(self.in_op2),
+ ]
+ return m
+
+
+class FPGet2Op(FPState):
+ """ gets operands
+ """
+
+ def __init__(self, in_state, out_state, in_op1, in_op2, width):
+ FPState.__init__(self, in_state)
+ self.out_state = out_state
+ self.mod = FPGet2OpMod(width)
+ self.in_op1 = in_op1
+ self.in_op2 = in_op2
+ self.out_op1 = FPNumIn(None, width)
+ self.out_op2 = FPNumIn(None, width)
+ self.in_stb = Signal(reset_less=True)
+ self.out_ack = Signal(reset_less=True)
+ self.out_decode = Signal(reset_less=True)
+
+ def setup(self, m, in_op1, in_op2, in_stb):
+ """ links module to inputs and outputs
+ """
+ m.submodules.get_ops = self.mod
+ m.d.comb += self.mod.in_op1.eq(in_op1)
+ m.d.comb += self.mod.in_op2.eq(in_op2)
+ m.d.comb += self.mod.stb.eq(in_stb)
+ m.d.comb += self.out_ack.eq(self.mod.ack)
+ m.d.comb += self.out_decode.eq(self.mod.trigger)
+ #m.d.comb += self.out_op1.v.eq(self.mod.out_op1.v)
+ #m.d.comb += self.out_op2.v.eq(self.mod.out_op2.v)
+
+ def action(self, m):
+ with m.If(self.out_decode):
+ m.next = self.out_state
+ m.d.sync += [
+ self.mod.ack.eq(0),
+ #self.out_op1.v.eq(self.mod.out_op1.v),
+ #self.out_op2.v.eq(self.mod.out_op2.v),
+ self.out_op1.copy(self.mod.out_op1),
+ self.out_op2.copy(self.mod.out_op2)
+ ]
+ with m.Else():
+ m.d.sync += self.mod.ack.eq(1)
+
+
class FPAddSpecialCasesMod:
""" special cases: NaNs, infs, zeros, denormalised
NOTE: some of these are unique to add. see "Special Operations"
]
with m.If(self.out_z.stb & self.out_z.ack):
m.d.sync += self.out_z.stb.eq(0)
- m.next = "get_a"
+ m.next = "get_ops"
with m.Else():
m.d.sync += self.out_z.stb.eq(1)
-class FPADD(FPID):
+class FPADDBase(FPID):
def __init__(self, width, id_wid=None, single_cycle=False):
""" IEEE754 FP Add
self.width = width
self.single_cycle = single_cycle
- self.in_a = FPOp(width)
- self.in_b = FPOp(width)
+ self.in_t = Trigger()
+ self.in_a = Signal(width)
+ self.in_b = Signal(width)
self.out_z = FPOp(width)
self.states = []
""" creates the HDL code-fragment for FPAdd
"""
m = Module()
- m.submodules.in_a = self.in_a
- m.submodules.in_b = self.in_b
m.submodules.out_z = self.out_z
+ m.submodules.in_t = self.in_t
- geta = self.add_state(FPGetOp("get_a", "get_b",
- self.in_a, self.width))
- geta.setup(m, self.in_a)
- a = geta.out_op
-
- getb = self.add_state(FPGetOp("get_b", "special_cases",
- self.in_b, self.width))
- getb.setup(m, self.in_b)
- b = getb.out_op
+ get = self.add_state(FPGet2Op("get_ops", "special_cases",
+ self.in_a, self.in_b, self.width))
+ get.setup(m, self.in_a, self.in_b, self.in_t.stb)
+ m.d.comb += self.in_t.ack.eq(get.mod.ack)
+ a = get.out_op1
+ b = get.out_op2
sc = self.add_state(FPAddSpecialCases(self.width, self.id_wid))
sc.setup(m, a, b, self.in_mid)
return m
+class FPADD(FPID):
+
+ def __init__(self, width, id_wid=None, single_cycle=False):
+ """ IEEE754 FP Add
+
+ * width: bit-width of IEEE754. supported: 16, 32, 64
+ * id_wid: an identifier that is sync-connected to the input
+ * single_cycle: True indicates each stage to complete in 1 clock
+ """
+ FPID.__init__(self, id_wid)
+ self.width = width
+ self.single_cycle = single_cycle
+
+ self.in_a = FPOp(width)
+ self.in_b = FPOp(width)
+ self.out_z = FPOp(width)
+
+ self.states = []
+
+ def add_state(self, state):
+ self.states.append(state)
+ return state
+
+ def get_fragment(self, platform=None):
+ """ creates the HDL code-fragment for FPAdd
+ """
+ m = Module()
+ m.submodules.in_a = self.in_a
+ m.submodules.in_b = self.in_b
+ m.submodules.out_z = self.out_z
+
+ geta = self.add_state(FPGetOp("get_a", "get_b",
+ self.in_a, self.width))
+ geta.setup(m, self.in_a)
+ a = geta.out_op
+
+ getb = self.add_state(FPGetOp("get_b", "special_cases",
+ self.in_b, self.width))
+ getb.setup(m, self.in_b)
+ b = getb.out_op
+
+ ab = FPADDBase()
+ #pa = self.add_state(FPPack(self.width, self.id_wid))
+ #pa.setup(m, cor.out_z, rn.in_mid)
+
+ pz = self.add_state(FPPutZ("put_z", sc.out_z, self.out_z,
+ pa.in_mid, self.out_mid))
+
+ with m.FSM() as fsm:
+
+ for state in self.states:
+ with m.State(state.state_from):
+ state.action(m)
+
+ return m
+
+
if __name__ == "__main__":
- alu = FPADD(width=32, in_wid=5, single_cycle=True)
- main(alu, ports=alu.in_a.ports() + \
- alu.in_b.ports() + \
+ alu = FPADDBase(width=32, id_wid=5, single_cycle=True)
+ main(alu, ports=[alu.in_a, alu.in_b] + \
+ alu.in_t.ports() + \
alu.out_z.ports() + \
[alu.in_mid, alu.out_mid])
--- /dev/null
+from random import randint
+from operator import add
+
+from nmigen import Module, Signal
+from nmigen.compat.sim import run_simulation
+
+from nmigen_add_experiment import FPADDBase
+
+def get_case(dut, a, b, mid):
+ yield dut.in_mid.eq(mid)
+ yield dut.in_a.eq(a)
+ yield dut.in_b.eq(b)
+ yield dut.in_t.stb.eq(1)
+ yield
+ yield
+ yield
+ yield
+ ack = (yield dut.in_t.ack)
+ assert ack == 0
+
+ yield dut.in_t.stb.eq(0)
+
+ yield dut.out_z.ack.eq(1)
+
+ while True:
+ out_z_stb = (yield dut.out_z.stb)
+ if not out_z_stb:
+ yield
+ continue
+ out_z = yield dut.out_z.v
+ out_mid = yield dut.out_mid
+ yield dut.out_z.ack.eq(0)
+ yield
+ break
+
+ return out_z, out_mid
+
+def check_case(dut, a, b, z, mid=None):
+ if mid is None:
+ mid = randint(0, 6)
+ out_z, out_mid = yield from get_case(dut, a, b, mid)
+ assert out_z == z, "Output z 0x%x not equal to expected 0x%x" % (out_z, z)
+ assert out_mid == mid, "Output mid 0x%x != expected 0x%x" % (out_mid, mid)
+
+
+
+def testbench(dut):
+ yield from check_case(dut, 0x36093399, 0x7f6a12f1, 0x7f6a12f1)
+ yield from check_case(dut, 0x006CE3EE, 0x806CE3EC, 0x00000002)
+ yield from check_case(dut, 0x00000047, 0x80000048, 0x80000001)
+ yield from check_case(dut, 0x000116C2, 0x8001170A, 0x80000048)
+ yield from check_case(dut, 0x7ed01f25, 0xff559e2c, 0xfedb1d33)
+ yield from check_case(dut, 0, 0, 0)
+ yield from check_case(dut, 0xFFFFFFFF, 0xC63B800A, 0x7FC00000)
+ yield from check_case(dut, 0xFF800000, 0x7F800000, 0x7FC00000)
+ #yield from check_case(dut, 0xFF800000, 0x7F800000, 0x7FC00000)
+ yield from check_case(dut, 0x7F800000, 0xFF800000, 0x7FC00000)
+ yield from check_case(dut, 0x42540000, 0xC2540000, 0x00000000)
+ yield from check_case(dut, 0xC2540000, 0x42540000, 0x00000000)
+ yield from check_case(dut, 0xfe34f995, 0xff5d59ad, 0xff800000)
+ yield from check_case(dut, 0x82471f51, 0x243985f, 0x801c3790)
+ yield from check_case(dut, 0x40000000, 0xc0000000, 0x00000000)
+ yield from check_case(dut, 0x3F800000, 0x40000000, 0x40400000)
+ 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, 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, 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, 0x42500000, 0x51A7A358, 0x51A7A358)
+ yield from check_case(dut, 0x51A7A358, 0x42500000, 0x51A7A358)
+ yield from check_case(dut, 0x4E5693A4, 0x42500000, 0x4E5693A5)
+ yield from check_case(dut, 0x42500000, 0x4E5693A4, 0x4E5693A5)
+
+if __name__ == '__main__':
+ dut = FPADDBase(width=32, id_wid=5, single_cycle=True)
+ run_simulation(dut, testbench(dut), vcd_name="test_add.vcd")
+