import sys
import functools
-from nmigen import Module, Signal, Cat, Const, Elaboratable
+from nmigen import Module, Signal, Cat, Const, Mux, Elaboratable
from nmigen.cli import main, verilog
from nmutil.singlepipe import ControlBase
from nmutil.concurrentunit import ReservationStations, num_bits
+from ieee754.fpcommon.fpbase import Overflow
from ieee754.fpcommon.getop import FPADDBaseData
from ieee754.fpcommon.pack import FPPackData
from ieee754.fpcommon.normtopack import FPNormToPack
from ieee754.fpcommon.postcalc import FPAddStage1Data
from ieee754.fpcommon.msbhigh import FPMSBHigh
-from ieee754.fpcommon.fpbase import MultiShiftRMerge
+from ieee754.fpcommon.exphigh import FPEXPHigh
from nmigen import Module, Signal, Elaboratable
m.submodules.sc_decode_a = a1 = FPNumDecode(None, a1)
m.d.comb += a1.v.eq(self.i.a)
z1 = self.o.z
- mz = len(self.o.z)
+ mz = len(z1)
print("z1", mz)
me = a1.rmw
ms = mz - me
print("ms-me", ms, me)
- espec = (len(a1.e_width), True)
+ espec = (a1.e_width, True)
ediff_intwid = Signal(espec, reset_less=True)
# conversion can mostly be done manually...
- m.d.comb += self.o.z.s.eq(a1.s)
- m.d.comb += self.o.z.e.eq(a1.e)
- m.d.comb += self.o.z.m[ms:].eq(a1.m)
- m.d.comb += self.o.z.create(a1.s, a1.e, self.o.z.m) # ... here
+ #m.d.comb += self.o.z.s.eq(a1.s)
+ #m.d.comb += self.o.z.e.eq(a1.e)
+ #m.d.comb += self.o.z.m[ms:].eq(a1.m)
+ #m.d.comb += self.o.z.create(a1.s, a1.e, self.o.z.m) # ... here
signed = Signal(reset_less=True)
m.d.comb += signed.eq(self.i.ctx.op[0])
with m.Else(): # positive FP, so positive overrun (max INT)
m.d.comb += self.o.z.eq((1<<(mz)-1))
- # ok exp should be in range: shift it...
+ # ok exp should be in range: shift and round it
with m.Else():
- mantissa = Signal(z1, reset_less=True)
- l = [0] * ms + [1] + a1.m
- m.d.comb += mantissa.eq(Cat(*l) >> a1.e)
+ mantissa = Signal(mz, reset_less=True)
+ l = [0] * ms + [1] + [a1.m]
+ m.d.comb += mantissa.eq(Cat(*l))
m.d.comb += self.o.z.eq(mantissa)
+ # shift
+ msr = FPEXPHigh(mz+3, espec[0])
+ m.submodules.norm_exp = msr
+ m.d.comb += [msr.m_in[3:].eq(mantissa),
+ msr.e_in.eq(a1.e),
+ msr.ediff.eq(Mux(signed, mz-1, mz))
+ ]
+
+ of = Overflow()
+ m.d.comb += of.guard.eq(msr.m_out[2])
+ m.d.comb += of.round_bit.eq(msr.m_out[1])
+ m.d.comb += of.sticky.eq(msr.m_out[0])
+ m.d.comb += of.m0.eq(msr.m_out[3])
+ m.d.comb += self.o.z.eq(msr.m_out[3:])
+
# copy the context (muxid, operator)
- m.d.comb += self.o.oz.eq(self.o.z.v)
+ #m.d.comb += self.o.oz.eq(self.o.z.v)
m.d.comb += self.o.ctx.eq(self.i.ctx)
return m
self.out = self.ospec(None)
+class FPCVTFtoIntBasePipe(ControlBase):
+ def __init__(self, modkls, e_extra, in_pspec, out_pspec):
+ ControlBase.__init__(self)
+ self.pipe1 = FPCVTConvertDeNorm(modkls, in_pspec, out_pspec)
+ #self.pipe2 = FPNormToPack(out_pspec, e_extra=e_extra)
+
+ #self._eqs = self.connect([self.pipe1, self.pipe2])
+ self._eqs = self.connect([self.pipe1, ])
+
+ def elaborate(self, platform):
+ m = ControlBase.elaborate(self, platform)
+ m.submodules.down = self.pipe1
+ #m.submodules.normpack = self.pipe2
+ m.d.comb += self._eqs
+ return m
+
+
class FPCVTBasePipe(ControlBase):
def __init__(self, modkls, e_extra, in_pspec, out_pspec):
ControlBase.__init__(self)
"""
def __init__(self, modkls, e_extra, in_width, out_width,
- num_rows, op_wid=0):
+ num_rows, op_wid=0, pkls=FPCVTBasePipe):
self.op_wid = op_wid
self.id_wid = num_bits(in_width)
self.out_id_wid = num_bits(out_width)
self.in_pspec = PipelineSpec(in_width, self.id_wid, self.op_wid)
self.out_pspec = PipelineSpec(out_width, self.out_id_wid, op_wid)
- self.alu = FPCVTBasePipe(modkls, e_extra, self.in_pspec, self.out_pspec)
+ self.alu = pkls(modkls, e_extra, self.in_pspec, self.out_pspec)
ReservationStations.__init__(self, num_rows)
def i_specfn(self):
for (name, kls, e_extra) in muxfactoryinput:
fn = functools.partial(getkls, kls, e_extra)
setattr(sys.modules[__name__], name, fn)
+
+
+class FPCVTF2IntMuxInOut(FPCVTMuxInOutBase):
+ """ Reservation-Station version of FPCVT pipeline.
+
+ * fan-in on inputs (an array of FPADDBaseData: a,b,mid)
+ * 2-stage multiplier pipeline
+ * fan-out on outputs (an array of FPPackData: z,mid)
+
+ Fan-in and Fan-out are combinatorial.
+ """
+
+ def __init__(self, in_width, out_width, num_rows, op_wid=0):
+ FPCVTMuxInOutBase.__init__(self, FPCVTFloatToIntMod, False,
+ in_width, out_width,
+ num_rows, op_wid,
+ pkls=FPCVTFtoIntBasePipe)
+
--- /dev/null
+""" test of FPCVTMuxInOut
+"""
+
+from ieee754.fcvt.pipeline import (FPCVTF2IntMuxInOut,)
+from ieee754.fpcommon.test.fpmux import runfp
+
+import sfpy
+from sfpy import Float64, Float32, Float16
+
+def fcvt_f64_ui32(x):
+ return sfpy.float.f64_to_ui32(x)
+
+def fcvt_i16_f32(x):
+ print ("fcvt i16_f32", hex(x))
+ return sfpy.float.i32_to_f32(x) # XXX no i16_to_f32, it's ok though
+
+def fcvt_i32_f32(x):
+ print ("fcvt i32_f32", hex(x))
+ return sfpy.float.i32_to_f32(x)
+
+def fcvt_i32_f64(x):
+ print ("fcvt i32_f64", hex(x))
+ return sfpy.float.i32_to_f64(x)
+
+def fcvt_f32_ui32(x):
+ return sfpy.float.f32_to_ui32(x)
+
+def fcvt_64_to_32(x):
+ return sfpy.float.ui64_to_f32(x)
+
+def fcvt_f16_ui32(x):
+ return sfpy.float.f16_to_ui32(x)
+
+######################
+# signed int to fp
+######################
+
+def test_int_pipe_i16_f32():
+ # XXX softfloat-3 doesn't have i16_to_xxx so use ui32 instead.
+ # should be fine.
+ dut = FPCVTIntMuxInOut(16, 32, 4, op_wid=1)
+ runfp(dut, 16, "test_fcvt_int_pipe_i16_f32", to_int16, fcvt_i16_f32, True,
+ n_vals=100, opcode=0x1)
+
+def test_int_pipe_i32_f64():
+ dut = FPCVTIntMuxInOut(32, 64, 4, op_wid=1)
+ runfp(dut, 32, "test_fcvt_int_pipe_i32_f64", to_int32, fcvt_i32_f64, True,
+ n_vals=100, opcode=0x1)
+
+def test_int_pipe_i32_f32():
+ dut = FPCVTIntMuxInOut(32, 32, 4, op_wid=1)
+ runfp(dut, 32, "test_fcvt_int_pipe_i32_f32", to_int32, fcvt_i32_f32, True,
+ n_vals=100, opcode=0x1)
+
+######################
+# fp to unsigned int
+######################
+
+def test_int_pipe_f16_ui16():
+ # XXX softfloat-3 doesn't have ui16_to_xxx so use ui32 instead.
+ # should be fine.
+ dut = FPCVTF2IntMuxInOut(16, 32, 4, op_wid=1)
+ runfp(dut, 16, "test_fcvt_f2int_pipe_f16_ui16", Float16, fcvt_f16_ui32,
+ True, n_vals=100)
+
+def test_int_pipe_ui16_f64():
+ dut = FPCVTIntMuxInOut(16, 64, 4, op_wid=1)
+ runfp(dut, 16, "test_fcvt_int_pipe_ui16_f64", to_uint16, fcvt_64, True,
+ n_vals=100)
+
+def test_int_pipe_f32_ui32():
+ dut = FPCVTF2IntMuxInOut(32, 32, 4, op_wid=1)
+ runfp(dut, 32, "test_fcvt_f2int_pipe_f32_ui32", Float32, fcvt_f32_ui32,
+ True, n_vals=100)
+
+def test_int_pipe_ui32_f64():
+ dut = FPCVTIntMuxInOut(32, 64, 4, op_wid=1)
+ runfp(dut, 32, "test_fcvt_int_pipe_ui32_64", to_uint32, fcvt_64, True,
+ n_vals=100)
+
+def test_int_pipe_ui64_f32():
+ # ok, doing 33 bits here because it's pretty pointless (not entirely)
+ # to do random numbers statistically likely 99.999% of the time to be
+ # converted to Inf
+ dut = FPCVTIntMuxInOut(64, 32, 4, op_wid=1)
+ runfp(dut, 33, "test_fcvt_int_pipe_ui64_32", to_uint64, fcvt_64_to_32, True,
+ n_vals=100)
+
+def test_int_pipe_ui64_f16():
+ # ok, doing 17 bits here because it's pretty pointless (not entirely)
+ # to do random numbers statistically likely 99.999% of the time to be
+ # converted to Inf
+ dut = FPCVTIntMuxInOut(64, 16, 4, op_wid=1)
+ runfp(dut, 17, "test_fcvt_int_pipe_ui64_16", to_uint64, fcvt_16, True,
+ n_vals=100)
+
+def test_int_pipe_ui32_f16():
+ # ok, doing 17 bits here because it's pretty pointless (not entirely)
+ # to do random numbers statistically likely 99.999% of the time to be
+ # converted to Inf
+ dut = FPCVTIntMuxInOut(32, 16, 4, op_wid=1)
+ runfp(dut, 17, "test_fcvt_int_pipe_ui32_16", to_uint32, fcvt_16, True,
+ n_vals=100)
+
+if __name__ == '__main__':
+ for i in range(200):
+ test_int_pipe_f16_ui16()
+ test_int_pipe_f32_ui32()
+ continue
+ test_int_pipe_i32_f32()
+ test_int_pipe_i16_f32()
+ test_int_pipe_i32_f64()
+ continue
+ test_int_pipe_ui16_f32()
+ test_int_pipe_ui64_f32()
+ test_int_pipe_ui32_f16()
+ test_int_pipe_ui64_f16()
+ test_int_pipe_ui16_f64()
+ test_int_pipe_ui32_f64()
+
#print ("test", hex(op1), hex(op2))
res = self.fpop(self.fpkls(op1), self.fpkls(op2))
self.di[muxid][i] = (op1, op2)
- self.do[muxid].append(res.bits)
+ if hasattr(res, "bits"):
+ self.do[muxid].append(res.bits)
+ else:
+ self.do[muxid].append(res) # for FP to INT
def send(self, muxid):
for i in range(self.tlen):
if self.single_op:
fop1 = self.fpkls(op1)
res = self.fpop(fop1)
- print ("send", muxid, i, hex(op1), hex(res.bits),
+ if hasattr(res, "bits"):
+ r = res.bits
+ else:
+ r = res
+ print ("send", muxid, i, hex(op1), hex(r),
fop1, res)
else:
fop1 = self.fpkls(op1)