From 1bddf9ebf6dc0a4c8dd6f53a71fd3afba5aff7d7 Mon Sep 17 00:00:00 2001 From: Michael Nolan Date: Tue, 31 Mar 2020 16:35:50 -0400 Subject: [PATCH] sin/cos cordic partially working --- src/ieee754/cordic/sin_cos.py | 32 ++++++++++------- src/ieee754/cordic/test/python_sin_cos.py | 36 +++++++++++++++++++ src/ieee754/cordic/test/test_sincos.py | 42 ++++++++++++++++++++--- 3 files changed, 94 insertions(+), 16 deletions(-) create mode 100644 src/ieee754/cordic/test/python_sin_cos.py diff --git a/src/ieee754/cordic/sin_cos.py b/src/ieee754/cordic/sin_cos.py index 7e72808b..911880db 100644 --- a/src/ieee754/cordic/sin_cos.py +++ b/src/ieee754/cordic/sin_cos.py @@ -1,4 +1,4 @@ -from nmigen import Module, Elaboratable, Signal, Memory +from nmigen import Module, Elaboratable, Signal, Memory, signed from nmigen.cli import rtlil import math from enum import Enum, unique @@ -41,15 +41,15 @@ class CORDIC(Elaboratable): self.ZMAX = ZMAX = int(round(self.M * math.pi/2)) # sin/cos output in 0.ffffff format - self.cos = Signal(range(-M, M-1)) - self.sin = Signal(range(-M, M-1)) + self.cos = Signal(range(-M, M-1), reset=0) + self.sin = Signal(range(-M, M-1), reset=0) # angle input self.z0 = Signal(range(-ZMAX, ZMAX), reset_less=True) # cordic start flag self.start = Signal(reset_less=True) # cordic done/ready for input - self.ready = Signal() + self.ready = Signal(reset=True) self.width = self.z0.width self.iterations = self.width - 1 @@ -73,13 +73,16 @@ class CORDIC(Elaboratable): dy = Signal(self.sin.shape()) dz = Signal(self.z0.shape()) i = Signal(range(self.iterations)) - - state = Signal(CordicState) + state = Signal(CordicState, reset=CordicState.WAITING) m.submodules.anglerom = anglerom = \ CordicROM(self.fracbits, self.iterations) - comb += anglerom.addr.eq(i) + comb += dx.eq(y >> i) + comb += dy.eq(x >> i) + comb += dz.eq(anglerom.data) + comb += self.cos.eq(x) + comb += self.sin.eq(y) with m.If(state == CordicState.WAITING): with m.If(self.start): sync += x.eq(X0) @@ -88,17 +91,22 @@ class CORDIC(Elaboratable): sync += i.eq(0) sync += self.ready.eq(0) sync += state.eq(CordicState.RUNNING) + sync += anglerom.addr.eq(1) with m.If(state == CordicState.RUNNING): - sync += dx.eq(x >> i) - sync += dx.eq(y >> i) - sync += dz.eq(anglerom.data) + with m.If(z >= 0): + sync += x.eq(x - dx) + sync += y.eq(y + dy) + sync += z.eq(z - dz) + with m.Else(): + sync += x.eq(x + dx) + sync += y.eq(y - dy) + sync += z.eq(z + dz) with m.If(i == self.iterations - 1): - sync += self.cos.eq(x) - sync += self.sin.eq(y) sync += state.eq(CordicState.WAITING) sync += self.ready.eq(1) with m.Else(): sync += i.eq(i+1) + sync += anglerom.addr.eq(i+2) return m def ports(self): diff --git a/src/ieee754/cordic/test/python_sin_cos.py b/src/ieee754/cordic/test/python_sin_cos.py new file mode 100644 index 00000000..771e8a81 --- /dev/null +++ b/src/ieee754/cordic/test/python_sin_cos.py @@ -0,0 +1,36 @@ +import math + + +def run_cordic(z0, fracbits=8, log=True): + M = 1<> i + dy = x >> i + dz = angles[i] + + + if z >= 0: + x -= dx + y += dy + z -= dz + else: + x += dx + y -= dy + z += dz + if log: + print("iteration {}".format(i)) + print("dx: {}, dy: {}, dz: {}".format(dx, dy, dz)) + print("x: {}, y: {}, z: {}".format(x, y, z)) + return (y, x) diff --git a/src/ieee754/cordic/test/test_sincos.py b/src/ieee754/cordic/test/test_sincos.py index 07ebc80a..c17b86fa 100644 --- a/src/ieee754/cordic/test/test_sincos.py +++ b/src/ieee754/cordic/test/test_sincos.py @@ -3,13 +3,15 @@ from nmigen.back.pysim import Simulator, Delay from nmigen.test.utils import FHDLTestCase from ieee754.cordic.sin_cos import CORDIC +from python_sin_cos import run_cordic import unittest +import math +import random class SinCosTestCase(FHDLTestCase): - def test_sincos(self): - m = Module() + def run_test(self, zin=0, fracbits=8, expected_sin=0, expected_cos=0): - fracbits = 8 + m = Module() m.submodules.dut = dut = CORDIC(fracbits) z = Signal(dut.z0.shape()) @@ -30,12 +32,44 @@ class SinCosTestCase(FHDLTestCase): sim.add_clock(1e-6) def process(): + yield z.eq(zin) + yield start.eq(1) + + yield + yield start.eq(0) + yield for i in range(10): - yield + rdy = yield ready + if rdy == 1: + result = yield sin + msg = "sin: {}, expected {}".format(result, expected_sin) + assert result == expected_sin, msg + result = yield cos + msg = "cos: {}, expected {}".format(result, expected_cos) + assert result == expected_cos, msg + else: + yield + sim.add_sync_process(process) with sim.write_vcd("sin_cos.vcd", "sin_cos.gtkw", traces=[ z, cos, sin, ready, start]): sim.run() + def run_test_assert(self, z, fracbits=8): + (sin, cos) = run_cordic(z, fracbits=8, log=False) + self.run_test(zin=z, fracbits=8, + expected_sin=sin, expected_cos=cos) + def test_0(self): + self.run_test_assert(0) + def test_rand(self): + fracbits = 8 + M = (1 << fracbits) + ZMAX = int(round(M * math.pi/2)) + for i in range(100): + z = random.randrange(-ZMAX, ZMAX-1) + self.run_test_assert(z, fracbits=fracbits) + + + if __name__ == "__main__": unittest.main() -- 2.30.2