[libre-riscv-dev] [Bug 208] implement CORDIC in a general way sufficient to do transcendentals

bugzilla-daemon at libre-soc.org bugzilla-daemon at libre-soc.org
Mon Apr 13 18:23:10 BST 2020


--- Comment #4 from Luke Kenneth Casson Leighton <lkcl at lkcl.net> ---
(In reply to Michael Nolan from comment #3)
> I was able to translate the linked myhdl code to nmigen and implement both a
> state machine based and pipelined cordic here:
> https://git.libre-soc.org/?p=ieee754fpu.git;a=tree;f=src/ieee754/cordic;
> h=3f06900baa42651410d661739fb616e4b3020c52;
> hb=77f150cff440bed025e2487b6f0fcda9f529290b

cool!  well that was easy :)

> You can configure the width, as well as the number of cordic rounds per
> pipeline stage. There are some accuracy issues with it though - it exactly
> matches the behavior of the myhdl one, but the results it gives can be off
> by 1% or so from that obtained using sin() or cos() on 16 bit numbers.

yes.  i believe it's well-known that to get 16-bit accuracy you need
32-bit registers.

i made a couple of corrections btw - frickin well done for working out
the pipeline API with zero assistance - that's deeply impressive given
that, other than the docstring comments, there's no "documentation" on

CordicInitialData needed to "yield self.z0" (not self.z)

"yield from" is reserved for a way to yield *from* something that is
itself iteratable (such as another function).  self.z0 is in fact
iterable, so what would be returned by "yield from" would be first
self.z0[0], then on the next iteration self.z0[1] and so on which
would be very painful.

"yield" just returns "that object".

however... we have a bit of a problem back in nmutil.iocontrol NextControl
and PrevControl iteration, in that it can't actually properly work out
if the *object* that you are iterating should be yielded or yielded *from*.
so i added a hack "check if data has a ports function".

however i've just right now worked out that we could detect if the object
is iterable with isinstance(self.data_o, Iterable).
so that's just been committed.

i also added an rtlil test because i was fascinated to see what the
graphviz looks like.

--- a/src/ieee754/cordic/pipe_data.py
+++ b/src/ieee754/cordic/pipe_data.py
@@ -10,11 +10,14 @@ class CordicInitialData:
         self.z0 = Signal(range(-ZMAX, ZMAX), name="z")     # denormed result

     def __iter__(self):
-        yield from self.z
+        yield self.z0

     def eq(self, i):
         return [self.z0.eq(i.z0)]

 class CordicData:

@@ -27,9 +30,12 @@ class CordicData:
         self.z = Signal(range(-ZMAX, ZMAX), name="z")     # denormed result

     def __iter__(self):
-        yield from self.x
-        yield from self.y
-        yield from self.z
+        yield self.x
+        yield self.y
+        yield self.z

     def eq(self, i):
         ret = [self.z.eq(i.z), self.x.eq(i.x), self.y.eq(i.y)]
diff --git a/src/ieee754/cordic/test/test_pipe.py
index 880351a..b7eaf8a 100644
--- a/src/ieee754/cordic/test/test_pipe.py
+++ b/src/ieee754/cordic/test/test_pipe.py
@@ -1,6 +1,7 @@
 from nmigen import Module, Signal
 from nmigen.back.pysim import Simulator, Passive
 from nmigen.test.utils import FHDLTestCase
+from nmigen.cli import rtlil

 from ieee754.cordic.sin_cos_pipeline import CordicBasePipe
 from ieee754.cordic.pipe_data import CordicPipeSpec
@@ -16,6 +17,13 @@ class SinCosTestCase(FHDLTestCase):
         pspec = CordicPipeSpec(fracbits=fracbits, rounds_per_stage=4)
         m.submodules.dut = dut = CordicBasePipe(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.z0.shape())
         z_valid = Signal()
         ready = Signal()

You are receiving this mail because:
You are on the CC list for the bug.

More information about the libre-riscv-dev mailing list