add sv.fdmadds unit test
[openpower-isa.git] / src / openpower / decoder / isa / test_caller_svp64_dct.py
1 from nmigen import Module, Signal
2 from nmigen.back.pysim import Simulator, Delay, Settle
3 from nmutil.formaltest import FHDLTestCase
4 import unittest
5 from openpower.decoder.power_decoder import (create_pdecode)
6 from openpower.simulator.program import Program
7 from openpower.decoder.isa.caller import SVP64State
8 from openpower.decoder.selectable_int import SelectableInt
9 from openpower.decoder.isa.test_caller import run_tst
10 from openpower.sv.trans.svp64 import SVP64Asm
11 from copy import deepcopy
12 from openpower.decoder.helpers import fp64toselectable, SINGLE
13 from openpower.decoder.isafunctions.double2single import DOUBLE2SINGLE
14
15
16 class DCTTestCase(FHDLTestCase):
17
18 def _check_regs(self, sim, expected):
19 for i in range(32):
20 self.assertEqual(sim.gpr(i), SelectableInt(expected[i], 64))
21
22 def test_sv_ffadds_dct(self):
23 """>>> lst = ["sv.fdmadds 0.v, 8.v, 0.v, 0.v"
24 ]
25 four in-place vector adds, four in-place vector mul-subs
26
27 SVP64 "DCT" mode will *automatically* offset FRB and an implicit
28 FRS to perform the two multiplies. one add, one subtract.
29
30 sv.fdadds FRT, FRA, FRC, FRB actually does:
31 fadds FRT , FRB, FRA
32 fsubs FRT+vl, FRA, FRB+vl
33 """
34 lst = SVP64Asm(["sv.fdmadds 0.v, 8.v, 0.v, 0.v"
35 ])
36 lst = list(lst)
37
38 fprs = [0] * 32
39 av = [7.0, -9.8, 2.0, -32.3] # first half of array 0..3
40 bv = [-2.0, 2.0, -9.8, 32.3] # second half of array 4..7
41 cv = [-1.0, 0.5, 2.3, -3.2] # coefficients
42 res = []
43 # work out the results with the twin add-sub
44 for i, (a, b, c) in enumerate(zip(av, bv, cv)):
45 fprs[i+0] = fp64toselectable(a)
46 fprs[i+4] = fp64toselectable(b)
47 fprs[i+8] = fp64toselectable(c)
48 t = b + a
49 u = (b - a) * c
50 t = DOUBLE2SINGLE(fp64toselectable(t)) # convert to Power single
51 u = DOUBLE2SINGLE(fp64toselectable(u)) # from double
52 res.append((t, u))
53 print ("FFT", i, "in", a, b, "c", c, "res", t, u)
54
55 # SVSTATE (in this case, VL=2)
56 svstate = SVP64State()
57 svstate.vl = 4 # VL
58 svstate.maxvl = 4 # MAXVL
59 print ("SVSTATE", bin(svstate.asint()))
60
61 with Program(lst, bigendian=False) as program:
62 sim = self.run_tst_program(program, svstate=svstate,
63 initial_fprs=fprs)
64 # confirm that the results are as expected
65 for i, (t, u) in enumerate(res):
66 a = float(sim.fpr(i+0))
67 b = float(sim.fpr(i+4))
68 t = float(t)
69 u = float(u)
70 print ("FFT", i, "in", a, b, "res", t, u)
71 for i, (t, u) in enumerate(res):
72 self.assertEqual(sim.fpr(i+2), t)
73 self.assertEqual(sim.fpr(i+6), u)
74
75 def tst_sv_remap_fpmadds_dct(self):
76 """>>> lst = ["svshape 4, 1, 1, 2, 0",
77 "svremap 31, 1, 0, 2, 0, 1, 0",
78 "sv.ffmadds 0.v, 0.v, 0.v, 8.v"
79 ]
80 runs a full in-place O(N log2 N) butterfly schedule for
81 DCT
82
83 SVP64 "REMAP" in Butterfly Mode is applied to a twin +/- FMAC
84 (3 inputs, 2 outputs)
85 """
86 lst = SVP64Asm( ["svshape 4, 1, 1, 2, 0",
87 "svremap 31, 1, 0, 2, 0, 1, 0",
88 "sv.ffmadds 0.v, 0.v, 0.v, 8.v"
89 ])
90 lst = list(lst)
91
92 # array and coefficients to test
93 av = [7.0, -9.8, 3.0, -32.3]
94 coe = [-0.25, 0.5, 3.1, 6.2, 0.1, -0.2] # 6 coefficients
95
96 # store in regfile
97 fprs = [0] * 32
98 for i, c in enumerate(coe):
99 fprs[i+8] = fp64toselectable(c)
100 for i, a in enumerate(av):
101 fprs[i+0] = fp64toselectable(a)
102
103 with Program(lst, bigendian=False) as program:
104 sim = self.run_tst_program(program, initial_fprs=fprs)
105 print ("spr svshape0", sim.spr['SVSHAPE0'])
106 print (" xdimsz", sim.spr['SVSHAPE0'].xdimsz)
107 print (" ydimsz", sim.spr['SVSHAPE0'].ydimsz)
108 print (" zdimsz", sim.spr['SVSHAPE0'].zdimsz)
109 print ("spr svshape1", sim.spr['SVSHAPE1'])
110 print ("spr svshape2", sim.spr['SVSHAPE2'])
111 print ("spr svshape3", sim.spr['SVSHAPE3'])
112
113 return
114
115 # work out the results with the twin mul/add-sub
116 res = transform_radix2(av, coe)
117
118 for i, expected in enumerate(res):
119 print ("i", i, float(sim.fpr(i)), "expected", expected)
120 for i, expected in enumerate(res):
121 # convert to Power single
122 expected = DOUBLE2SINGLE(fp64toselectable(expected))
123 expected = float(expected)
124 actual = float(sim.fpr(i))
125 # approximate error calculation, good enough test
126 # reason: we are comparing FMAC against FMUL-plus-FADD-or-FSUB
127 # and the rounding is different
128 err = abs(actual - expected) / expected
129 self.assertTrue(err < 1e-7)
130
131 def run_tst_program(self, prog, initial_regs=None,
132 svstate=None,
133 initial_mem=None,
134 initial_fprs=None):
135 if initial_regs is None:
136 initial_regs = [0] * 32
137 simulator = run_tst(prog, initial_regs, mem=initial_mem,
138 initial_fprs=initial_fprs,
139 svstate=svstate)
140
141 print ("GPRs")
142 simulator.gpr.dump()
143 print ("FPRs")
144 simulator.fpr.dump()
145
146 return simulator
147
148
149 if __name__ == "__main__":
150 unittest.main()