1 """Implementation of pospopcount in SVP64
2 Copyright (C) 2023 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
3 Licensed under the LGPLv3+
4 Funded by NLnet NGI0-Entrust under EU grant agreement No 101069594.
5 * https://nlnet.nl/project/Libre-SOC-OpenPOWER-ISA
6 * https://bugs.libre-soc.org/show_bug.cgi?id=672
7 * https://libre-soc.org/openpower/sv/cookbook/pospopcount/
11 from copy
import deepcopy
13 from nmutil
.formaltest
import FHDLTestCase
14 from openpower
.decoder
.isa
.test_caller
import run_tst
15 from openpower
.decoder
.selectable_int
import SelectableInt
16 from openpower
.simulator
.program
import Program
17 from openpower
.insndb
.asm
import SVP64Asm
20 def write_byte(mem
, addr
, val
):
21 addr
, offs
= (addr
// 8)*8, (addr
% 8)*8
23 value
= mem
.get(addr
, 0) & ~mask
24 value
= value |
(val
<< offs
)
25 mem
[addr
] = value
& 0xffff_ffff_ffff_ffff
29 class PosPopCountTestCase(FHDLTestCase
):
31 def _check_regs(self
, sim
, expected
):
33 self
.assertEqual(sim
.gpr(i
), SelectableInt(expected
[i
], 64))
35 def test_sv_pospopcount(self
):
36 """positional popcount
40 "mtspr 9, 3", # move r3 to CTR
41 # VL = MIN(CTR,MAXVL=8)
42 "setvl 3,0,8,0,1,1", # set MVL=8, VL=MIN(MVL,CTR)
43 # load VL bytes (update r4 addr) but compressed (dw=8)
44 "addi 6, 0, 0", # initialise r6 to zero
45 "sv.lbzu/pi/dw=8 *6, 1(4)", # should be /lf here as well
46 # gather performs the transpose (which gets us to positional..)
48 # now those bits have been turned around, popcount and sum them
49 "setvl 0,0,8,0,1,1", # set MVL=VL=8
50 "sv.popcntd/sw=8 *24,*8", # do the (now transposed) popcount
51 "sv.add *16,*16,*24", # and accumulate in results
52 # branch back if CTR still non-zero. works even though VL=8
53 "sv.bc/all 16, *0, -0x28", # reduce CTR by VL and stop if -ve
58 tst_array
= [23,19,25,189,76,255,32,191,67,205,0,39,107]
59 #tst_array = [1,2,3,4,5,6,7,8,9,10,11,12,13]
60 #tst_array = [254] * 10
61 #tst_array = [1,2,3,4,5,6,7,8,9,10,11,12,13]
62 #tst_array = [1,2,3,4,5,6,7,8,9,10,11,12,13]
63 #tst_array = [1,2,3,4,5,6,7,8,9]
64 #tst_array = list(range(240))
65 initial_regs
= [0] * 64
66 initial_regs
[3] = len(tst_array
)
67 initial_regs
[4] = 256-8 # load address
69 # some memory with identifying garbage in it
70 initial_mem
= {16: 0xf0f1_f2f3_f4f5_f6f7,
71 24: 0x4041_4243_4445_4647,
72 40: 0x8081_8283_8485_8687,
73 48: 0x9091_9293_9495_9697,
74 248: 0xffff_aaaa_cccc_eeee,
75 256: 0xa0a1_a2a3_a4a5_a6a7,
78 # overwrite the garbage with the test data
79 for i
, c
in enumerate(tst_array
):
80 write_byte(initial_mem
, initial_regs
[4]+i
, c
)
82 for i
, c
in enumerate(tst_array
):
83 print ("array", i
, bin(c
), c
)
85 # now get the expected results: do a simple pospopcount
89 expected
[j
] += (c
>> j
) & 1
91 with
Program(lst
, bigendian
=False) as program
:
92 sim
= self
.run_tst_program(program
, initial_mem
=initial_mem
,
93 initial_regs
=initial_regs
)
94 for (k
, val
) in enumerate(expected
):
95 print("idx, count, reg", k
, val
, sim
.gpr(k
+16).value
)
96 for (k
, val
) in enumerate(expected
):
97 self
.assertEqual(val
, sim
.gpr(k
+16))
99 def run_tst_program(self
, prog
, initial_regs
=None,
100 svstate
=None, initial_fprs
=None,
102 if initial_regs
is None:
103 initial_regs
= [0] * 32
104 if initial_fprs
is None:
105 initial_fprs
= [0] * 32
106 simulator
= run_tst(prog
, initial_regs
, svstate
=svstate
,
107 initial_fprs
=initial_fprs
,
112 mem
= simulator
.mem
.dump(printout
=True, asciidump
=True)
117 if __name__
== "__main__":