allow rtlil file to be created in cordic
[ieee754fpu.git] / src / ieee754 / cordic / test / test_fp_pipe.py
1 from nmigen import Module, Signal
2 from nmigen.back.pysim import Simulator, Passive
3 from nmigen.test.utils import FHDLTestCase
4 from nmigen.cli import rtlil
5 from sfpy import Float32
6
7 from ieee754.cordic.fp_pipeline import FPCordicBasePipe
8 from ieee754.cordic.fp_pipe_data import FPCordicPipeSpec
9 import unittest
10 import math
11 import random
12
13
14 class SinCosTestCase(FHDLTestCase):
15 def run_test(self, inputs, outputs=iter([])):
16 m = Module()
17 pspec = FPCordicPipeSpec(width=32, rounds_per_stage=4, num_rows=1)
18 m.submodules.dut = dut = FPCordicBasePipe(pspec)
19
20 # write out module (useful for seeing what's going on)
21 vl = rtlil.convert(dut, ports=dut.ports())
22 with open("test_cordic_pipe_sin_cos.il", "w") as f:
23 f.write(vl)
24
25 z = Signal(dut.p.data_i.a.shape())
26 z_valid = Signal()
27 ready = Signal()
28
29 m.d.comb += [
30 dut.p.data_i.a.eq(z),
31 dut.p.valid_i.eq(z_valid),
32 dut.n.ready_i.eq(ready),
33 ]
34
35 sim = Simulator(m)
36 sim.add_clock(1e-6)
37
38 def writer_process():
39 for val in inputs:
40 yield z.eq(val.bits)
41 yield z_valid.eq(1)
42 yield ready.eq(1)
43 yield
44 for i in range(40):
45 yield
46 def reader_process():
47 while True:
48 yield
49 vld = yield dut.n.valid_o
50 if vld:
51 try:
52 sin, cos = outputs.__next__()
53 result = yield dut.n.data_o.x
54 result = Float32(result)
55 msg = f"cos: expected {cos} got {result}"
56 self.assertLess(abs(result - Float32(cos)),
57 Float32(2e-7), msg=msg)
58 result = yield dut.n.data_o.y
59 result = Float32(result)
60 msg = f"sin: expected {sin} got {result}"
61 self.assertLess(abs(result - Float32(sin)),
62 Float32(2e-7), msg=msg)
63 except StopIteration:
64 break
65
66 sim.add_sync_process(writer_process)
67 sim.add_sync_process(reader_process)
68 with sim.write_vcd("fp_pipeline.vcd", "fp_pipeline.gtkw", traces=[
69 z]):
70 sim.run()
71
72 def test_rand(self):
73 inputs = []
74 for i in range(20000):
75 x = random.uniform(-1, 1)
76 inputs.append(Float32(x))
77 sines = [math.sin(x * Float32(math.pi/2)) for x in inputs]
78 cosines = [math.cos(x * Float32(math.pi/2)) for x in inputs]
79 outputs = zip(sines, cosines)
80 self.run_test(iter(inputs), outputs=iter(outputs))
81
82 def test_pi_2(self):
83 inputs = [Float32(0.5), Float32(1/3), Float32(2/3),
84 Float32(-.5), Float32(0.001)]
85 sines = [math.sin(x * Float32(math.pi/2)) for x in inputs]
86 cosines = [math.cos(x * Float32(math.pi/2)) for x in inputs]
87 outputs = zip(sines, cosines)
88 self.run_test(iter(inputs), outputs=iter(outputs))
89
90
91 if __name__ == "__main__":
92 unittest.main()