From: Michael Nolan Date: Tue, 28 Apr 2020 17:21:20 +0000 (-0400) Subject: Begin adding floating point cordic pipeline X-Git-Tag: ls180-24jan2020~77 X-Git-Url: https://git.libre-soc.org/?p=ieee754fpu.git;a=commitdiff_plain;h=bb2140955b8a7c836e061c14d75aff22f0d96bf2 Begin adding floating point cordic pipeline --- diff --git a/src/ieee754/cordic/fp_pipe_data.py b/src/ieee754/cordic/fp_pipe_data.py new file mode 100644 index 00000000..25c70ff3 --- /dev/null +++ b/src/ieee754/cordic/fp_pipe_data.py @@ -0,0 +1,20 @@ +from nmigen import Signal, Const +from nmutil.dynamicpipe import SimpleHandshakeRedir +from ieee754.fpcommon.fpbase import FPNumBaseRecord +from ieee754.pipeline import PipelineSpec +from nmutil.concurrentunit import num_bits +import math + +from ieee754.cordic.pipe_data import (CordicData, CordicInitialData, + CordicPipeSpec) + + +class FPCordicPipeSpec(CordicPipeSpec, PipelineSpec): + def __init__(self, width, rounds_per_stage, num_rows): + rec = FPNumBaseRecord(width, False) + fracbits = 2 * rec.m_width + self.width = width + id_wid = num_bits(num_rows) + CordicPipeSpec.__init__(self, fracbits, rounds_per_stage) + PipelineSpec.__init__(self, width, op_wid=1, n_ops=1, + id_width=id_wid) diff --git a/src/ieee754/cordic/fp_pipe_init_stages.py b/src/ieee754/cordic/fp_pipe_init_stages.py new file mode 100644 index 00000000..ab740064 --- /dev/null +++ b/src/ieee754/cordic/fp_pipe_init_stages.py @@ -0,0 +1,36 @@ +from nmigen import Module, Signal, Cat, Const, Mux +from nmigen.cli import main, verilog + +from ieee754.fpcommon.fpbase import FPNumDecode, FPNumBaseRecord + +from nmutil.pipemodbase import PipeModBase +from ieee754.fpcommon.basedata import FPBaseData +from ieee754.fpcommon.denorm import FPSCData + + +class FPCordicInitStage(PipeModBase): + def __init__(self, pspec): + super().__init__(pspec, "specialcases") + + def ispec(self): + return FPBaseData(self.pspec) + + def ospec(self): + return FPSCData(self.pspec, False) + + def elaborate(self, platform): + m = Module() + comb = m.d.comb + + # decode a/b + width = self.pspec.width + a1 = FPNumBaseRecord(width, False) + m.submodules.sc_decode_a = a1 = FPNumDecode(None, a1) + comb += [a1.v.eq(self.i.a), + self.o.a.eq(a1) + ] + + # pass through context + comb += self.o.ctx.eq(self.i.ctx) + + return m diff --git a/src/ieee754/cordic/fp_pipeline.py b/src/ieee754/cordic/fp_pipeline.py new file mode 100644 index 00000000..d6bf90a9 --- /dev/null +++ b/src/ieee754/cordic/fp_pipeline.py @@ -0,0 +1,41 @@ +from nmutil.singlepipe import ControlBase +from nmutil.pipemodbase import PipeModBaseChain + +from ieee754.fpcommon.denorm import FPAddDeNormMod +from ieee754.cordic.fp_pipe_init_stages import (FPCordicInitStage) + + +class CordicPipeChain(PipeModBaseChain): + def __init__(self, pspec, stages): + self.stages = stages + super().__init__(pspec) + + def get_chain(self): + return self.stages + + +class FPCordicBasePipe(ControlBase): + def __init__(self, pspec): + ControlBase.__init__(self) + self.pspec = pspec + + self.denorm = CordicPipeChain(pspec, + [FPCordicInitStage(self.pspec), + FPAddDeNormMod(self.pspec, False)]) + + self._eqs = self.connect([self.denorm]) + + def chunkify(self, initstage, stages): + chunks = [] + + for i in range(0, len(stages), self.pspec.rounds_per_stage): + chunks.append(stages[i:i + self.pspec.rounds_per_stage]) + chunks[0].insert(0, initstage) + + return chunks + + def elaborate(self, platform): + m = ControlBase.elaborate(self, platform) + m.submodules.denorm = self.denorm + m.d.comb += self._eqs + return m diff --git a/src/ieee754/cordic/test/test_fp_pipe.py b/src/ieee754/cordic/test/test_fp_pipe.py new file mode 100644 index 00000000..c75ef741 --- /dev/null +++ b/src/ieee754/cordic/test/test_fp_pipe.py @@ -0,0 +1,64 @@ +from nmigen import Module, Signal +from nmigen.back.pysim import Simulator, Passive +from nmigen.test.utils import FHDLTestCase +from nmigen.cli import rtlil +from sfpy import Float32 + +from ieee754.cordic.fp_pipeline import FPCordicBasePipe +from ieee754.cordic.fp_pipe_data import FPCordicPipeSpec +import unittest +import math +import random + + +class SinCosTestCase(FHDLTestCase): + def run_test(self, inputs): + m = Module() + pspec = FPCordicPipeSpec(width=32, rounds_per_stage=4, num_rows=1) + m.submodules.dut = dut = FPCordicBasePipe(pspec) + + for port in dut.ports(): + print ("port", port) + + # vl = rtlil.convert(dut, ports=dut.ports()) + # with open("test_cordic_pipe_sin_cos.il", "w") as f: + # f.write(vl) + + z = Signal(dut.p.data_i.a.shape()) + z_valid = Signal() + ready = Signal() + + m.d.comb += [ + dut.p.data_i.a.eq(z), + dut.p.valid_i.eq(z_valid), + dut.n.ready_i.eq(ready), + ] + + sim = Simulator(m) + sim.add_clock(1e-6) + + def writer_process(): + for val in inputs: + print(val) + yield z.eq(val.bits) + yield z_valid.eq(1) + yield ready.eq(1) + yield + + sim.add_sync_process(writer_process) + with sim.write_vcd("fp_pipeline.vcd", "fp_pipeline.gtkw", traces=[ + z]): + sim.run() + + def test_rand(self): + fracbits = 16 + M = (1 << fracbits) + ZMAX = int(round(M * math.pi/2)) + inputs = [] + for i in range(10): + inputs.append(Float32(1.0*i)) + self.run_test(iter(inputs)) + + +if __name__ == "__main__": + unittest.main()