eb1f811540c2ab864b7e7bd5e2307238faad1e43
[openpower-isa.git] / src / openpower / sv / trans / svp64.py
1 # SPDX-License-Identifier: LGPLv3+
2 # Copyright (C) 2021 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
3 # Funded by NLnet http://nlnet.nl
4
5 """SVP64 OpenPOWER v3.0B assembly translator
6
7 This class takes raw svp64 assembly mnemonics (aliases excluded) and creates
8 an EXT001-encoded "svp64 prefix" (as a .long) followed by a v3.0B opcode.
9
10 It is very simple and straightforward, the only weirdness being the
11 extraction of the register information and conversion to v3.0B numbering.
12
13 Encoding format of svp64: https://libre-soc.org/openpower/sv/svp64/
14 Encoding format of arithmetic: https://libre-soc.org/openpower/sv/normal/
15 Encoding format of LDST: https://libre-soc.org/openpower/sv/ldst/
16 **TODO format of branches: https://libre-soc.org/openpower/sv/branches/**
17 **TODO format of CRs: https://libre-soc.org/openpower/sv/cr_ops/**
18 Bugtracker: https://bugs.libre-soc.org/show_bug.cgi?id=578
19 """
20
21 import functools
22 import os
23 import sys
24 from collections import OrderedDict
25 import inspect
26
27 from openpower.decoder.pseudo.pagereader import ISA
28 from openpower.decoder.power_svp64 import SVP64RM, get_regtype, decode_extra
29 from openpower.decoder.selectable_int import SelectableInt
30 from openpower.consts import SVP64MODE
31 from openpower.decoder.power_insn import SVP64Instruction
32 from openpower.decoder.power_insn import Database
33 from openpower.decoder.power_enums import find_wiki_dir
34
35 # for debug logging
36 from openpower.util import log
37
38
39 def instruction(*fields):
40 def instruction(insn, desc):
41 (value, start, end) = desc
42 bits = ((1,) * ((end + 1) - start))
43 mask = 0
44 for bit in bits:
45 mask = ((mask << 1) | bit)
46 return (insn | ((value & mask) << (31 - end)))
47
48 return functools.reduce(instruction, fields, 0)
49
50
51 CUSTOM_INSNS = {}
52
53
54 def _insn(name, **kwargs):
55 return name, kwargs
56
57
58 def _custom_insns(*insns):
59 """ a decorator that adds the function to `CUSTOM_INSNS` """
60
61 def decorator(fn):
62 FIELDS_ARG = object()
63 if len(insns) == 0:
64 insns_ = (fn.__name__, {}),
65 else:
66 insns_ = insns
67 for name, kwargs in insns_:
68 if not isinstance(name, str):
69 raise TypeError("instruction name must be a str: {name!r}")
70 if name in CUSTOM_INSNS:
71 raise ValueError(f"duplicate instruction mnemonic: {name!r}")
72 # use getcallargs to check that arguments work:
73 inspect.getcallargs(fn, FIELDS_ARG, **kwargs)
74 CUSTOM_INSNS[name] = functools.partial(fn, **kwargs)
75 return fn
76 return decorator
77
78
79 @_custom_insns(
80 _insn("setvl", Rc=0),
81 _insn("setvl.", Rc=1),
82 )
83 def setvl(fields, Rc):
84 """
85 setvl is a *32-bit-only* instruction. It controls SVSTATE.
86 It is *not* a 64-bit-prefixed Vector instruction (no sv.setvl, yet),
87 it is a Vector *control* instruction.
88
89 * setvl RT,RA,SVi,vf,vs,ms
90
91 1.6.28 SVL-FORM - from fields.txt
92 |0 |6 |11 |16 |23 |24 |25 |26 |31 |
93 | PO | RT | RA | SVi |ms |vs |vf | XO |Rc |
94 """
95 PO = 22
96 XO = 0b11011
97 # ARRRGH these are in a non-obvious order in openpower/isa/simplev.mdwn
98 # compared to the SVL-Form above. sigh
99 # setvl RT,RA,SVi,vf,vs,ms
100 (RT, RA, SVi, vf, vs, ms) = fields
101 SVi -= 1
102 return instruction(
103 (PO, 0, 5),
104 (RT, 6, 10),
105 (RA, 11, 15),
106 (SVi, 16, 22),
107 (ms, 23, 23),
108 (vs, 24, 24),
109 (vf, 25, 25),
110 (XO, 26, 30),
111 (Rc, 31, 31),
112 )
113
114
115 @_custom_insns(
116 _insn("svstep", Rc=0),
117 _insn("svstep.", Rc=1),
118 )
119 def svstep(fields, Rc):
120 """
121 svstep is a 32-bit instruction. It updates SVSTATE.
122 It *can* be SVP64-prefixed, to indicate that its registers
123 are Vectorised.
124
125 * svstep RT,SVi,vf
126
127 # 1.6.28 SVL-FORM - from fields.txt
128 # |0 |6 |11 |16 |23 |24 |25 |26 |31 |
129 # | PO | RT | / | SVi |/ |/ |vf | XO |Rc |
130
131 """
132 PO = 22
133 XO = 0b10011
134 (RT, SVi, vf) = fields
135 SVi -= 1
136 return instruction(
137 (PO, 0, 5),
138 (RT, 6, 10),
139 (0, 11, 15),
140 (SVi, 16, 22),
141 (0, 23, 23),
142 (0, 24, 24),
143 (vf, 25, 25),
144 (XO, 26, 30),
145 (Rc, 31, 31),
146 )
147
148
149 @_custom_insns()
150 def svshape(fields):
151 """
152 svshape is a *32-bit-only* instruction. It updates SVSHAPE and SVSTATE.
153 It is *not* a 64-bit-prefixed Vector instruction (no sv.svshape, yet),
154 it is a Vector *control* instruction.
155
156 https://libre-soc.org/openpower/sv/remap/#svshape
157
158 * svshape SVxd,SVyd,SVzd,SVrm,vf
159
160 # 1.6.33 SVM-FORM from fields.txt
161 # |0 |6 |11 |16 |21 |25 |26 |31 |
162 # | PO | SVxd | SVyd | SVzd | SVrm |vf | XO |
163
164 note that SVrm is not permitted to be 0b0111, 0b1000 or 0b1001.
165 0b0111 is reserved and 0b100- is for svshape2
166
167 """
168 PO = 22
169 XO = 0b011001
170 (SVxd, SVyd, SVzd, SVrm, vf) = fields
171 SVxd -= 1
172 SVyd -= 1
173 SVzd -= 1
174
175 # check SVrm for reserved (and svshape2) values
176 assert SVrm not in [0b1000, 0b1001], \
177 "svshape reserved SVrm value %s" % bin(SVrm)
178
179 return instruction(
180 (PO, 0, 5),
181 (SVxd, 6, 10),
182 (SVyd, 11, 15),
183 (SVzd, 16, 20),
184 (SVrm, 21, 24),
185 (vf, 25, 25),
186 (XO, 26, 31),
187 )
188
189
190 @_custom_insns()
191 def svshape2(fields):
192 """
193 svshape2 is a *32-bit-only* instruction. It updates SVSHAPE and SVSTATE.
194 It is *not* a 64-bit-prefixed Vector instruction (no sv.svshape2, yet),
195 it is a Vector *control* instruction, and is a sort-of hybrid of
196 svshape and svindex, with the key important feature being the "offset".
197
198 https://libre-soc.org/openpower/sv/remap/discussion
199
200 * svshape2 SVo,SVM2yx,rmm,SVd,sk,mm
201
202 # 1.6.35.1 SVM2-FORM from fields.txt
203 # |0 |6 |10 |11 |16 |21 |24|25 |26 |31 |
204 # | PO | SVo |SVMyx| rmm | SVd |XO |mm|sk | XO |
205
206 note that this fits into the space of svshape and that XO is
207 split across 2 areas.
208
209 """
210 PO = 22
211 XO = 0b011001
212 XO2 = 0b100 # not really XO2 but hey
213 (offs, yx, rmm, SVd, sk, mm) = fields
214 SVd -= 1 # offset by one
215
216 return instruction(
217 (PO, 0, 5),
218 (offs, 6, 9), # offset (the whole point of adding svshape2)
219 (yx, 10, 10), # like svindex
220 (rmm, 11, 15), # ditto svindex
221 (SVd, 16, 20), # ditto svindex
222 (XO2, 21, 23), # actually XO split across 2 places...
223 (mm, 24, 24), # ditto svindex
224 (sk, 25, 25), # ditto svindex
225 (XO, 26, 31),
226 )
227
228
229 @_custom_insns()
230 def svindex(fields):
231 """
232 svindex is a *32-bit-only* instruction. It is a convenience
233 instruction that reduces instruction count for Indexed REMAP
234 Mode.
235 It is *not* a 64-bit-prefixed Vector instruction (no sv.svindex, yet),
236 it is a Vector *control* instruction.
237
238 1.6.28 SVI-FORM
239 |0 |6 |11 |16 |21 |23|24|25|26 31|
240 | PO | SVG|rmm | SVd |ew |yx|mm|sk| XO |
241 """
242 # note that the dimension field one subtracted
243 PO = 22
244 XO = 0b101001
245 (SVG, rmm, SVd, ew, yx, mm, sk) = fields
246 SVd -= 1
247 return instruction(
248 (PO, 0, 5),
249 (SVG, 6, 10),
250 (rmm, 11, 15),
251 (SVd, 16, 20),
252 (ew, 21, 22),
253 (yx, 23, 23),
254 (mm, 24, 24),
255 (sk, 25, 25),
256 (XO, 26, 31),
257 )
258
259
260 @_custom_insns()
261 def svremap(fields):
262 """
263 this is a *32-bit-only* instruction. It updates the SVSHAPE SPR
264 it is *not* a 64-bit-prefixed Vector instruction (no sv.svremap),
265 it is a Vector *control* instruction.
266
267 * svremap SVme,mi0,mi1,mi2,mo0,mo1,pst
268
269 # 1.6.34 SVRM-FORM
270 |0 |6 |11 |13 |15 |17 |19 |21 |22 |26 |31 |
271 | PO | SVme |mi0 | mi1 | mi2 | mo0 | mo1 |pst |/// | XO |
272
273 """
274 PO = 22
275 XO = 0b111001
276 (SVme, mi0, mi1, mi2, mo0, mo1, pst) = fields
277 return instruction(
278 (PO, 0, 5),
279 (SVme, 6, 10),
280 (mi0, 11, 12),
281 (mi1, 13, 14),
282 (mi2, 15, 16),
283 (mo0, 17, 18),
284 (mo1, 19, 20),
285 (pst, 21, 21),
286 (0, 22, 25),
287 (XO, 26, 31),
288 )
289
290
291 # ok from here-on down these are added as 32-bit instructions
292 # and are here only because binutils (at present) doesn't have
293 # them (that's being fixed!)
294 # they can - if implementations then choose - be Vectorised
295 # because they are general-purpose scalar instructions
296 @_custom_insns()
297 def bmask(fields):
298 """
299 1.6.2.2 BM2-FORM
300 |0 |6 |11 |16 |21 |26 |27 31|
301 | PO | RT | RA | RB |bm |L | XO |
302 """
303 PO = 22
304 XO = 0b010001
305 (RT, RA, RB, bm, L) = fields
306 return instruction(
307 (PO, 0, 5),
308 (RT, 6, 10),
309 (RA, 11, 15),
310 (RB, 16, 20),
311 (bm, 21, 25),
312 (L, 26, 26),
313 (XO, 27, 31),
314 )
315
316
317 def _fptrans_insn(name, XO):
318 return [
319 _insn(name, PO=63, Rc=0, XO=XO),
320 _insn(name + ".", PO=63, Rc=1, XO=XO),
321 _insn(name + "s", PO=59, Rc=0, XO=XO),
322 _insn(name + "s.", PO=59, Rc=1, XO=XO),
323 ]
324
325
326 @_custom_insns(
327 *_fptrans_insn("fatan2", XO=0b1001001110),
328 *_fptrans_insn("fatan2pi", XO=0b1000001110),
329 *_fptrans_insn("fpow", XO=0b1111101101),
330 *_fptrans_insn("fpown", XO=0b1101101100),
331 *_fptrans_insn("fpowr", XO=0b1111101100),
332 *_fptrans_insn("frootn", XO=0b1101101101),
333 *_fptrans_insn("fhypot", XO=0b1010001110),
334 *_fptrans_insn("fminnum08", XO=0b1011001100),
335 *_fptrans_insn("fmaxnum08", XO=0b1011101100),
336 *_fptrans_insn("fmin19", XO=0b1011001101),
337 *_fptrans_insn("fmax19", XO=0b1011101101),
338 *_fptrans_insn("fminnum19", XO=0b1011001110),
339 *_fptrans_insn("fmaxnum19", XO=0b1011101110),
340 *_fptrans_insn("fminc", XO=0b1011001111),
341 *_fptrans_insn("fmaxc", XO=0b1011101111),
342 *_fptrans_insn("fminmagnum08", XO=0b1100001110),
343 *_fptrans_insn("fmaxmagnum08", XO=0b1100001111),
344 *_fptrans_insn("fminmag19", XO=0b1101101110),
345 *_fptrans_insn("fmaxmag19", XO=0b1101101111),
346 *_fptrans_insn("fminmagnum19", XO=0b1110001110),
347 *_fptrans_insn("fmaxmagnum19", XO=0b1110001111),
348 *_fptrans_insn("fminmagc", XO=0b1111101110),
349 *_fptrans_insn("fmaxmagc", XO=0b1111101111),
350 *_fptrans_insn("fmod", XO=0b1101001111),
351 *_fptrans_insn("fremainder", XO=0b1111001111),
352 )
353 def fptrans_binary(fields, PO, Rc, XO):
354 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
355 # however we are out of space with opcode 22
356 # 1.6.7 X-FORM
357 # |0 |6 |11 |16 |21 |31 |
358 # | PO | FRT | FRA | FRB | XO |Rc |
359 # | PO | FRT | FRA | RB | XO |Rc |
360 (FRT, FRA, FRB) = fields
361 return instruction(
362 (PO, 0, 5),
363 (FRT, 6, 10),
364 (FRA, 11, 15),
365 (FRB, 16, 20),
366 (XO, 21, 30),
367 (Rc, 31, 31),
368 )
369
370
371 @_custom_insns(
372 *_fptrans_insn("frsqrt", XO=0b1001001100),
373 *_fptrans_insn("fcbrt", XO=0b1000001100),
374 *_fptrans_insn("frecip", XO=0b1010001100),
375 *_fptrans_insn("fexp2m1", XO=0b1100001100),
376 *_fptrans_insn("flog2p1", XO=0b1100001101),
377 *_fptrans_insn("fexp2", XO=0b1110001100),
378 *_fptrans_insn("flog2", XO=0b1110001101),
379 *_fptrans_insn("fexpm1", XO=0b1100101100),
380 *_fptrans_insn("flogp1", XO=0b1100101101),
381 *_fptrans_insn("fexp", XO=0b1110101100),
382 *_fptrans_insn("flog", XO=0b1110101101),
383 *_fptrans_insn("fexp10m1", XO=0b1101001100),
384 *_fptrans_insn("flog10p1", XO=0b1101001101),
385 *_fptrans_insn("fexp10", XO=0b1111001100),
386 *_fptrans_insn("flog10", XO=0b1111001101),
387 *_fptrans_insn("fsin", XO=0b1001001101),
388 *_fptrans_insn("fcos", XO=0b1001101100),
389 *_fptrans_insn("ftan", XO=0b1001101101),
390 *_fptrans_insn("fasin", XO=0b1001001111),
391 *_fptrans_insn("facos", XO=0b1001101110),
392 *_fptrans_insn("fatan", XO=0b1001101111),
393 *_fptrans_insn("fsinpi", XO=0b1000001101),
394 *_fptrans_insn("fcospi", XO=0b1000101100),
395 *_fptrans_insn("ftanpi", XO=0b1000101101),
396 *_fptrans_insn("fasinpi", XO=0b1000001111),
397 *_fptrans_insn("facospi", XO=0b1000101110),
398 *_fptrans_insn("fatanpi", XO=0b1000101111),
399 *_fptrans_insn("fsinh", XO=0b1010001101),
400 *_fptrans_insn("fcosh", XO=0b1010101100),
401 *_fptrans_insn("ftanh", XO=0b1010101101),
402 *_fptrans_insn("fasinh", XO=0b1010001111),
403 *_fptrans_insn("facosh", XO=0b1010101110),
404 *_fptrans_insn("fatanh", XO=0b1010101111),
405 )
406 def fptrans_unary(fields, PO, Rc, XO):
407 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
408 # however we are out of space with opcode 22
409 # 1.6.7 X-FORM
410 # |0 |6 |11 |16 |21 |31 |
411 # | PO | FRT | /// | FRB | XO |Rc |
412 (FRT, FRB) = fields
413 return instruction(
414 (PO, 0, 5),
415 (FRT, 6, 10),
416 (0, 11, 15),
417 (FRB, 16, 20),
418 (XO, 21, 30),
419 (Rc, 31, 31),
420 )
421
422
423 @_custom_insns(
424 _insn("ternlogi", Rc=0),
425 _insn("ternlogi.", Rc=1),
426 )
427 def ternlogi(fields, Rc):
428 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
429 # however we are out of space with opcode 22
430 # 1.6.34 TLI-FORM
431 # |0 |6 |11 |16 |21 |29 |31 |
432 # | PO | RT | RA | RB | TLI | XO |Rc |
433 PO = 5
434 XO = 0
435 (RT, RA, RB, TLI) = fields
436 return instruction(
437 (PO, 0, 5),
438 (RT, 6, 10),
439 (RA, 11, 15),
440 (RB, 16, 20),
441 (TLI, 21, 28),
442 (XO, 29, 30),
443 (Rc, 31, 31),
444 )
445
446
447 @_custom_insns(
448 _insn("grev", Rc=0, imm=0, word=0),
449 _insn("grevw", Rc=0, imm=0, word=1),
450 _insn("grevi", Rc=0, imm=1, word=0),
451 _insn("grevwi", Rc=0, imm=1, word=1),
452 _insn("grev.", Rc=1, imm=0, word=0),
453 _insn("grevw.", Rc=1, imm=0, word=1),
454 _insn("grevi.", Rc=1, imm=1, word=0),
455 _insn("grevwi.", Rc=1, imm=1, word=1),
456 )
457 def grev(fields, Rc, imm, word):
458 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
459 # however we are out of space with opcode 22
460 insn = PO = 5
461 # _ matches fields in table at:
462 # https://libre-soc.org/openpower/sv/bitmanip/
463 XO = 0b1_0010_110
464 if word:
465 XO |= 0b100_000
466 if imm:
467 XO |= 0b1000_000
468 (RT, RA, XBI) = fields
469 insn = (insn << 5) | RT
470 insn = (insn << 5) | RA
471 if imm and not word:
472 assert 0 <= XBI < 64
473 insn = (insn << 6) | XBI
474 insn = (insn << 9) | XO
475 else:
476 assert 0 <= XBI < 32
477 insn = (insn << 5) | XBI
478 insn = (insn << 10) | XO
479 insn = (insn << 1) | Rc
480 return insn
481
482
483 @_custom_insns(
484 _insn("maxs", XO=0b0111001110, Rc=0),
485 _insn("maxs.", XO=0b0111001110, Rc=1),
486 _insn("maxu", XO=0b0011001110, Rc=0),
487 _insn("maxu.", XO=0b0011001110, Rc=1),
488 _insn("minu", XO=0b0001001110, Rc=0),
489 _insn("minu.", XO=0b0001001110, Rc=1),
490 _insn("mins", XO=0b0101001110, Rc=0),
491 _insn("mins.", XO=0b0101001110, Rc=1),
492 _insn("absdu", XO=0b1011110110, Rc=0),
493 _insn("absdu.", XO=0b1011110110, Rc=1),
494 _insn("absds", XO=0b1001110110, Rc=0),
495 _insn("absds.", XO=0b1001110110, Rc=1),
496 _insn("avgadd", XO=0b1101001110, Rc=0),
497 _insn("avgadd.", XO=0b1101001110, Rc=1),
498 _insn("absdacu", XO=0b1111110110, Rc=0),
499 _insn("absdacu.", XO=0b1111110110, Rc=1),
500 _insn("absdacs", XO=0b0111110110, Rc=0),
501 _insn("absdacs.", XO=0b0111110110, Rc=1),
502 _insn("cprop", XO=0b0110001110, Rc=0),
503 _insn("cprop.", XO=0b0110001110, Rc=1),
504 )
505 def av(fields, XO, Rc):
506 # 1.6.7 X-FORM
507 # |0 |6 |7|8|9 |10 |11|12|13 |15|16|17 |20|21 |31 |
508 # | PO | RT | RA | RB | XO |Rc |
509 PO = 22
510 (RT, RA, RB) = fields
511 return instruction(
512 (PO, 0, 5),
513 (RT, 6, 10),
514 (RA, 11, 15),
515 (RB, 16, 20),
516 (XO, 21, 30),
517 (Rc, 31, 31),
518 )
519
520
521 @_custom_insns()
522 def fmvis(fields):
523 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
524 # V3.0B 1.6.6 DX-FORM
525 # |0 |6 |7|8|9 |10 |11|12|13 |15|16|17 |26|27 |31 |
526 # | PO | FRS | d1 | d0 | XO |d2 |
527 PO = 22
528 XO = 0b00011
529 (FRS, imm) = fields
530 # first split imm into d1, d0 and d2. sigh
531 d2 = (imm & 1) # LSB (0)
532 d1 = (imm >> 1) & 0b11111 # bits 1-5
533 d0 = (imm >> 6) # MSBs 6-15
534 return instruction(
535 (PO, 0, 5),
536 (FRS, 6, 10),
537 (d1, 11, 15),
538 (d0, 16, 25),
539 (XO, 26, 30),
540 (d2, 31, 31),
541 )
542
543
544 @_custom_insns()
545 def fishmv(fields):
546 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
547 # V3.0B 1.6.6 DX-FORM
548 # |0 |6 |7|8|9 |10 |11|12|13 |15|16|17 |26|27 |31 |
549 # | PO | FRS | d1 | d0 | XO |d2 |
550 PO = 22
551 XO = 0b01011
552 (FRS, imm) = fields
553 # first split imm into d1, d0 and d2. sigh
554 d2 = (imm & 1) # LSB (0)
555 d1 = (imm >> 1) & 0b11111 # bits 1-5
556 d0 = (imm >> 6) # MSBs 6-15
557 return instruction(
558 (PO, 0, 5),
559 (FRS, 6, 10),
560 (d1, 11, 15),
561 (d0, 16, 25),
562 (XO, 26, 30),
563 (d2, 31, 31),
564 )
565
566
567 @_custom_insns(
568 _insn("pcdec."), # named "pcdec." because it always writes to CR0
569 )
570 def pcdec(fields):
571 # 1.6.21.1 VA2-FORM
572 # |0 |6 |11 |16 |21 |24|26 |31 |
573 # | PO | RT | RA | RB | RC | XO |once|
574 PO = 4
575 XO = 0b11100
576 (RT, RA, RB, RC, once) = fields
577 return instruction(
578 (PO, 0, 5),
579 (RT, 6, 10),
580 (RA, 11, 15),
581 (RB, 16, 20),
582 (RC, 21, 25),
583 (XO, 26, 30),
584 (once, 31, 31),
585 )
586
587
588 # decode GPR into sv extra
589 def get_extra_gpr(etype, regmode, field):
590 if regmode == 'scalar':
591 # cut into 2-bits 5-bits SS FFFFF
592 sv_extra = field >> 5
593 field = field & 0b11111
594 else:
595 # cut into 5-bits 2-bits FFFFF SS
596 sv_extra = field & 0b11
597 field = field >> 2
598 return sv_extra, field
599
600
601 # decode 3-bit CR into sv extra
602 def get_extra_cr_3bit(etype, regmode, field):
603 if regmode == 'scalar':
604 # cut into 2-bits 3-bits SS FFF
605 sv_extra = field >> 3
606 field = field & 0b111
607 else:
608 # cut into 3-bits 4-bits FFF SSSS but will cut 2 zeros off later
609 sv_extra = field & 0b1111
610 field = field >> 4
611 return sv_extra, field
612
613
614 # decodes SUBVL
615 def decode_subvl(encoding):
616 pmap = {'2': 0b01, '3': 0b10, '4': 0b11}
617 assert encoding in pmap, \
618 "encoding %s for SUBVL not recognised" % encoding
619 return pmap[encoding]
620
621
622 # decodes elwidth
623 def decode_elwidth(encoding):
624 pmap = {'8': 0b11, '16': 0b10, '32': 0b01}
625 assert encoding in pmap, \
626 "encoding %s for elwidth not recognised" % encoding
627 return pmap[encoding]
628
629
630 # decodes predicate register encoding
631 def decode_predicate(encoding):
632 pmap = { # integer
633 '1<<r3': (0, 0b001),
634 'r3': (0, 0b010),
635 '~r3': (0, 0b011),
636 'r10': (0, 0b100),
637 '~r10': (0, 0b101),
638 'r30': (0, 0b110),
639 '~r30': (0, 0b111),
640 # CR
641 'lt': (1, 0b000),
642 'nl': (1, 0b001), 'ge': (1, 0b001), # same value
643 'gt': (1, 0b010),
644 'ng': (1, 0b011), 'le': (1, 0b011), # same value
645 'eq': (1, 0b100),
646 'ne': (1, 0b101),
647 'so': (1, 0b110), 'un': (1, 0b110), # same value
648 'ns': (1, 0b111), 'nu': (1, 0b111), # same value
649 }
650 assert encoding in pmap, \
651 "encoding %s for predicate not recognised" % encoding
652 return pmap[encoding]
653
654
655 # decodes "Mode" in similar way to BO field (supposed to, anyway)
656 def decode_bo(encoding):
657 pmap = { # TODO: double-check that these are the same as Branch BO
658 'lt': 0b000,
659 'nl': 0b001, 'ge': 0b001, # same value
660 'gt': 0b010,
661 'ng': 0b011, 'le': 0b011, # same value
662 'eq': 0b100,
663 'ne': 0b101,
664 'so': 0b110, 'un': 0b110, # same value
665 'ns': 0b111, 'nu': 0b111, # same value
666 }
667 assert encoding in pmap, \
668 "encoding %s for BO Mode not recognised" % encoding
669 # barse-ackwards MSB0/LSB0. sigh
670 mapped = pmap[encoding]
671 si = SelectableInt(0, 3)
672 si[0] = mapped & 1 # inv
673 si[1:3] = mapped >> 1 # CR
674 return int(si)
675
676
677 # partial-decode fail-first mode
678 def decode_ffirst(encoding):
679 if encoding in ['RC1', '~RC1']:
680 return encoding
681 return decode_bo(encoding)
682
683
684 def decode_reg(field, macros=None):
685 if macros is None:
686 macros = {}
687 # decode the field number. "5.v" or "3.s" or "9"
688 # and now also "*0", and "*%0". note: *NOT* to add "*%rNNN" etc.
689 # https://bugs.libre-soc.org/show_bug.cgi?id=884#c0
690 if field.startswith(("*%", "*")):
691 if field.startswith("*%"):
692 field = field[2:]
693 else:
694 field = field[1:]
695 while field in macros:
696 field = macros[field]
697 return int(field), "vector" # actual register number
698
699 # try old convention (to be retired)
700 field = field.split(".")
701 regmode = 'scalar' # default
702 if len(field) == 2:
703 if field[1] == 's':
704 regmode = 'scalar'
705 elif field[1] == 'v':
706 regmode = 'vector'
707 field = int(field[0]) # actual register number
708 return field, regmode
709
710
711 def decode_imm(field):
712 ldst_imm = "(" in field and field[-1] == ')'
713 if ldst_imm:
714 return field[:-1].split("(")
715 else:
716 return None, field
717
718
719 def crf_extra(etype, rname, extra_idx, regmode, field, extras):
720 """takes a CR Field number (CR0-CR127), splits into EXTRA2/3 and v3.0
721 the scalar/vector mode (crNN.v or crNN.s) changes both the format
722 of the EXTRA2/3 encoding as well as what range of registers is possible.
723 this function can be used for both BF/BFA and BA/BB/BT by first removing
724 the bottom 2 bits of BA/BB/BT then re-instating them after encoding.
725 see https://libre-soc.org/openpower/sv/svp64/appendix/#cr_extra
726 for specification
727 """
728 sv_extra, field = get_extra_cr_3bit(etype, regmode, field)
729 # now sanity-check (and shrink afterwards)
730 if etype == 'EXTRA2':
731 # 3-bit CR Field (BF, BFA) EXTRA2 encoding
732 if regmode == 'scalar':
733 # range is CR0-CR15 in increments of 1
734 assert (sv_extra >> 1) == 0, \
735 "scalar CR %s cannot fit into EXTRA2 %s" % \
736 (rname, str(extras[extra_idx]))
737 # all good: encode as scalar
738 sv_extra = sv_extra & 0b01
739 else: # vector
740 # range is CR0-CR127 in increments of 16
741 assert sv_extra & 0b111 == 0, \
742 "vector CR %s cannot fit into EXTRA2 %s" % \
743 (rname, str(extras[extra_idx]))
744 # all good: encode as vector (bit 2 set)
745 sv_extra = 0b10 | (sv_extra >> 3)
746 else:
747 # 3-bit CR Field (BF, BFA) EXTRA3 encoding
748 if regmode == 'scalar':
749 # range is CR0-CR31 in increments of 1
750 assert (sv_extra >> 2) == 0, \
751 "scalar CR %s cannot fit into EXTRA3 %s" % \
752 (rname, str(extras[extra_idx]))
753 # all good: encode as scalar
754 sv_extra = sv_extra & 0b11
755 else: # vector
756 # range is CR0-CR127 in increments of 8
757 assert sv_extra & 0b11 == 0, \
758 "vector CR %s cannot fit into EXTRA3 %s" % \
759 (rname, str(extras[extra_idx]))
760 # all good: encode as vector (bit 3 set)
761 sv_extra = 0b100 | (sv_extra >> 2)
762 return sv_extra, field
763
764
765 def to_number(field):
766 if field.startswith("0x"):
767 return eval(field)
768 if field.startswith("0b"):
769 return eval(field)
770 return int(field)
771
772
773 db = Database(find_wiki_dir())
774
775
776 # decodes svp64 assembly listings and creates EXT001 svp64 prefixes
777 class SVP64Asm:
778 def __init__(self, lst, bigendian=False, macros=None):
779 if macros is None:
780 macros = {}
781 self.macros = macros
782 self.lst = lst
783 self.trans = self.translate(lst)
784 self.isa = ISA() # reads the v3.0B pseudo-code markdown files
785 self.svp64 = SVP64RM() # reads the svp64 Remap entries for registers
786 assert bigendian == False, "error, bigendian not supported yet"
787
788 def __iter__(self):
789 yield from self.trans
790
791 def translate_one(self, insn, macros=None):
792 if macros is None:
793 macros = {}
794 macros.update(self.macros)
795 isa = self.isa
796 svp64 = self.svp64
797 insn_no_comments = insn.partition('#')[0]
798 # find first space, to get opcode
799 ls = insn_no_comments.split(' ')
800 opcode = ls[0]
801 # now find opcode fields
802 fields = ''.join(ls[1:]).split(',')
803 mfields = list(map(str.strip, fields))
804 log("opcode, fields", ls, opcode, mfields)
805 fields = []
806 # macro substitution
807 for field in mfields:
808 fields.append(macro_subst(macros, field))
809 log("opcode, fields substed", ls, opcode, fields)
810
811 # identify if it is a special instruction
812 custom_insn_hook = CUSTOM_INSNS.get(opcode)
813 if custom_insn_hook is not None:
814 fields = tuple(map(to_number, fields))
815 insn_num = custom_insn_hook(fields)
816 log(opcode, bin(insn_num))
817 yield ".long 0x%X # %s" % (insn_num, insn)
818 return
819
820 # identify if is a svp64 mnemonic
821 if not opcode.startswith('sv.'):
822 yield insn # unaltered
823 return
824 opcode = opcode[3:] # strip leading "sv"
825
826 # start working on decoding the svp64 op: sv.basev30Bop/vec2/mode
827 opmodes = opcode.split("/") # split at "/"
828 v30b_op_orig = opmodes.pop(0) # first is the v3.0B
829 # check instruction ends with dot
830 rc_mode = v30b_op_orig.endswith('.')
831 if rc_mode:
832 v30b_op = v30b_op_orig[:-1]
833 else:
834 v30b_op = v30b_op_orig
835
836 # look up the 32-bit op (original, with "." if it has it)
837 if v30b_op_orig in isa.instr:
838 isa_instr = isa.instr[v30b_op_orig]
839 else:
840 raise Exception("opcode %s of '%s' not supported" %
841 (v30b_op_orig, insn))
842
843 # look up the svp64 op, first the original (with "." if it has it)
844 if v30b_op_orig in svp64.instrs:
845 rm = svp64.instrs[v30b_op_orig] # one row of the svp64 RM CSV
846 # then without the "." (if there was one)
847 elif v30b_op in svp64.instrs:
848 rm = svp64.instrs[v30b_op] # one row of the svp64 RM CSV
849 else:
850 raise Exception(f"opcode {v30b_op_orig!r} of "
851 f"{insn!r} not an svp64 instruction")
852
853 # get regs info e.g. "RT,RA,RB"
854 v30b_regs = isa_instr.regs[0]
855 log("v3.0B op", v30b_op, "Rc=1" if rc_mode else '')
856 log("v3.0B regs", opcode, v30b_regs)
857 log("RM", rm)
858
859 # right. the first thing to do is identify the ordering of
860 # the registers, by name. the EXTRA2/3 ordering is in
861 # rm['0']..rm['3'] but those fields contain the names RA, BB
862 # etc. we have to read the pseudocode to understand which
863 # reg is which in our instruction. sigh.
864
865 # first turn the svp64 rm into a "by name" dict, recording
866 # which position in the RM EXTRA it goes into
867 # also: record if the src or dest was a CR, for sanity-checking
868 # (elwidth overrides on CRs are banned)
869 decode = decode_extra(rm)
870 dest_reg_cr, src_reg_cr, svp64_src, svp64_dest = decode
871
872 log("EXTRA field index, src", svp64_src)
873 log("EXTRA field index, dest", svp64_dest)
874
875 # okaaay now we identify the field value (opcode N,N,N) with
876 # the pseudo-code info (opcode RT, RA, RB)
877 assert len(fields) == len(v30b_regs), \
878 "length of fields %s must match insn `%s` fields %s" % \
879 (str(v30b_regs), insn, str(fields))
880 opregfields = zip(fields, v30b_regs) # err that was easy
881
882 # now for each of those find its place in the EXTRA encoding
883 # note there is the possibility (for LD/ST-with-update) of
884 # RA occurring **TWICE**. to avoid it getting added to the
885 # v3.0B suffix twice, we spot it as a duplicate, here
886 extras = OrderedDict()
887 for idx, (field, regname) in enumerate(opregfields):
888 imm, regname = decode_imm(regname)
889 rtype = get_regtype(regname)
890 log(" idx find", rtype, idx, field, regname, imm)
891 if rtype is None:
892 # probably an immediate field, append it straight
893 extras[('imm', idx, False)] = (idx, field, None, None, None)
894 continue
895 extra = svp64_src.get(regname, None)
896 if extra is not None:
897 extra = ('s', extra, False) # not a duplicate
898 extras[extra] = (idx, field, regname, rtype, imm)
899 log(" idx src", idx, extra, extras[extra])
900 dextra = svp64_dest.get(regname, None)
901 log("regname in", regname, dextra)
902 if dextra is not None:
903 is_a_duplicate = extra is not None # duplicate spotted
904 dextra = ('d', dextra, is_a_duplicate)
905 extras[dextra] = (idx, field, regname, rtype, imm)
906 log(" idx dst", idx, extra, extras[dextra])
907
908 # great! got the extra fields in their associated positions:
909 # also we know the register type. now to create the EXTRA encodings
910 etype = rm['Etype'] # Extra type: EXTRA3/EXTRA2
911 ptype = rm['Ptype'] # Predication type: Twin / Single
912 extra_bits = 0
913 v30b_newfields = []
914 for extra_idx, (idx, field, rname, rtype, iname) in extras.items():
915 # is it a field we don't alter/examine? if so just put it
916 # into newfields
917 if rtype is None:
918 v30b_newfields.append(field)
919 continue
920
921 # identify if this is a ld/st immediate(reg) thing
922 ldst_imm = "(" in field and field[-1] == ')'
923 if ldst_imm:
924 immed, field = field[:-1].split("(")
925
926 field, regmode = decode_reg(field, macros=macros)
927 log(" ", extra_idx, rname, rtype,
928 regmode, iname, field, end=" ")
929
930 # see Mode field https://libre-soc.org/openpower/sv/svp64/
931 # XXX TODO: the following is a bit of a laborious repeated
932 # mess, which could (and should) easily be parameterised.
933 # XXX also TODO: the LD/ST modes which are different
934 # https://libre-soc.org/openpower/sv/ldst/
935
936 # rright. SVP64 register numbering is from 0 to 127
937 # for GPRs, FPRs *and* CR Fields, where for v3.0 the GPRs and RPFs
938 # are 0-31 and CR Fields are only 0-7. the SVP64 RM "Extra"
939 # area is used to extend the numbering from the 32-bit
940 # instruction, and also to record whether the register
941 # is scalar or vector. on a per-operand basis. this
942 # results in a slightly finnicky encoding: here we go...
943
944 # encode SV-GPR and SV-FPR field into extra, v3.0field
945 if rtype in ['GPR', 'FPR']:
946 sv_extra, field = get_extra_gpr(etype, regmode, field)
947 # now sanity-check. EXTRA3 is ok, EXTRA2 has limits
948 # (and shrink to a single bit if ok)
949 if etype == 'EXTRA2':
950 if regmode == 'scalar':
951 # range is r0-r63 in increments of 1
952 assert (sv_extra >> 1) == 0, \
953 "scalar GPR %s cannot fit into EXTRA2 %s" % \
954 (rname, str(extras[extra_idx]))
955 # all good: encode as scalar
956 sv_extra = sv_extra & 0b01
957 else:
958 # range is r0-r127 in increments of 2 (r0 r2 ... r126)
959 assert sv_extra & 0b01 == 0, \
960 "%s: vector field %s cannot fit " \
961 "into EXTRA2 %s" % \
962 (insn, rname, str(extras[extra_idx]))
963 # all good: encode as vector (bit 2 set)
964 sv_extra = 0b10 | (sv_extra >> 1)
965 elif regmode == 'vector':
966 # EXTRA3 vector bit needs marking
967 sv_extra |= 0b100
968
969 # encode SV-CR 3-bit field into extra, v3.0field.
970 # 3-bit is for things like BF and BFA
971 elif rtype == 'CR_3bit':
972 sv_extra, field = crf_extra(etype, rname, extra_idx,
973 regmode, field, extras)
974
975 # encode SV-CR 5-bit field into extra, v3.0field
976 # 5-bit is for things like BA BB BC BT etc.
977 # *sigh* this is the same as 3-bit except the 2 LSBs of the
978 # 5-bit field are passed through unaltered.
979 elif rtype == 'CR_5bit':
980 cr_subfield = field & 0b11 # record bottom 2 bits for later
981 field = field >> 2 # strip bottom 2 bits
982 # use the exact same 3-bit function for the top 3 bits
983 sv_extra, field = crf_extra(etype, rname, extra_idx,
984 regmode, field, extras)
985 # reconstruct the actual 5-bit CR field (preserving the
986 # bottom 2 bits, unaltered)
987 field = (field << 2) | cr_subfield
988
989 else:
990 raise Exception("no type match: %s" % rtype)
991
992 # capture the extra field info
993 log("=>", "%5s" % bin(sv_extra), field)
994 extras[extra_idx] = sv_extra
995
996 # append altered field value to v3.0b, differs for LDST
997 # note that duplicates are skipped e.g. EXTRA2 contains
998 # *BOTH* s:RA *AND* d:RA which happens on LD/ST-with-update
999 srcdest, idx, duplicate = extra_idx
1000 if duplicate: # skip adding to v3.0b fields, already added
1001 continue
1002 if ldst_imm:
1003 v30b_newfields.append(("%s(%s)" % (immed, str(field))))
1004 else:
1005 v30b_newfields.append(str(field))
1006
1007 log("new v3.0B fields", v30b_op, v30b_newfields)
1008 log("extras", extras)
1009
1010 # rright. now we have all the info. start creating SVP64 instruction.
1011 svp64_insn = SVP64Instruction.pair(prefix=0, suffix=0)
1012 svp64_prefix = svp64_insn.prefix
1013 svp64_rm = svp64_insn.prefix.rm
1014
1015 # begin with EXTRA fields
1016 for idx, sv_extra in extras.items():
1017 log(idx)
1018 if idx is None:
1019 continue
1020 if idx[0] == 'imm':
1021 continue
1022 srcdest, idx, duplicate = idx
1023 if etype == 'EXTRA2':
1024 svp64_rm.extra2[idx] = sv_extra
1025 else:
1026 svp64_rm.extra3[idx] = sv_extra
1027
1028 # identify if the op is a LD/ST.
1029 # see https://libre-soc.org/openpower/sv/ldst/
1030 is_ldst = rm['mode'] in [ 'LDST_IDX', 'LDST_IMM']
1031 is_ld = v30b_op.startswith("l") and is_ldst
1032 is_st = v30b_op.startswith("s") and is_ldst
1033
1034 # branch-conditional detection
1035 is_bc = rm['mode'] == 'BRANCH'
1036
1037 # parts of svp64_rm
1038 mmode = 0 # bit 0
1039 pmask = 0 # bits 1-3
1040 destwid = 0 # bits 4-5
1041 srcwid = 0 # bits 6-7
1042 subvl = 0 # bits 8-9
1043 smask = 0 # bits 16-18 but only for twin-predication
1044 mode = 0 # bits 19-23
1045
1046 mask_m_specified = False
1047 has_pmask = False
1048 has_smask = False
1049
1050 saturation = None
1051 src_zero = 0
1052 dst_zero = 0
1053 sv_mode = None
1054
1055 mapreduce = False
1056 reverse_gear = False
1057 mapreduce_crm = False
1058
1059 predresult = False
1060 failfirst = False
1061 ldst_elstride = 0
1062
1063 vli = False
1064
1065 # ok let's start identifying opcode augmentation fields
1066 for encmode in opmodes:
1067 # predicate mask (src and dest)
1068 if encmode.startswith("m="):
1069 pme = encmode
1070 pmmode, pmask = decode_predicate(encmode[2:])
1071 smmode, smask = pmmode, pmask
1072 mmode = pmmode
1073 mask_m_specified = True
1074 # predicate mask (dest)
1075 elif encmode.startswith("dm="):
1076 pme = encmode
1077 pmmode, pmask = decode_predicate(encmode[3:])
1078 mmode = pmmode
1079 has_pmask = True
1080 # predicate mask (src, twin-pred)
1081 elif encmode.startswith("sm="):
1082 sme = encmode
1083 smmode, smask = decode_predicate(encmode[3:])
1084 mmode = smmode
1085 has_smask = True
1086 # vec2/3/4
1087 elif encmode.startswith("vec"):
1088 subvl = decode_subvl(encmode[3:])
1089 # elwidth (both src and dest, like mask)
1090 elif encmode.startswith("w="):
1091 destwid = decode_elwidth(encmode[2:])
1092 srcwid = decode_elwidth(encmode[2:])
1093 # just dest width
1094 elif encmode.startswith("dw="):
1095 destwid = decode_elwidth(encmode[3:])
1096 # just src width
1097 elif encmode.startswith("sw="):
1098 srcwid = decode_elwidth(encmode[3:])
1099 # element-strided LD/ST
1100 elif encmode == 'els':
1101 ldst_elstride = 1
1102 # saturation
1103 elif encmode == 'sats':
1104 assert sv_mode is None
1105 saturation = 1
1106 sv_mode = 0b10
1107 elif encmode == 'satu':
1108 assert sv_mode is None
1109 sv_mode = 0b10
1110 saturation = 0
1111 # predicate zeroing
1112 elif encmode == 'zz': # TODO, a lot more checking on legality
1113 dst_zero = 1 # NOT on cr_ops, that's RM[6]
1114 src_zero = 1
1115 elif encmode == 'sz':
1116 src_zero = 1
1117 elif encmode == 'dz':
1118 dst_zero = 1
1119 # failfirst
1120 elif encmode.startswith("ff="):
1121 assert sv_mode is None
1122 sv_mode = 0b01
1123 failfirst = decode_ffirst(encmode[3:])
1124 # predicate-result, interestingly same as fail-first
1125 elif encmode.startswith("pr="):
1126 assert sv_mode is None
1127 sv_mode = 0b11
1128 predresult = decode_ffirst(encmode[3:])
1129 # map-reduce mode, reverse-gear
1130 elif encmode == 'mrr':
1131 assert sv_mode is None
1132 sv_mode = 0b00
1133 mapreduce = True
1134 reverse_gear = True
1135 # map-reduce mode
1136 elif encmode == 'mr':
1137 assert sv_mode is None
1138 sv_mode = 0b00
1139 mapreduce = True
1140 elif encmode == 'crm': # CR on map-reduce
1141 assert sv_mode is None
1142 sv_mode = 0b00
1143 mapreduce_crm = True
1144 elif encmode == 'vli':
1145 assert sv_mode == 0b01 # only allow ff mode
1146 vli = True
1147 elif is_bc:
1148 if encmode == 'all':
1149 svp64_rm.branch.ALL = 1
1150 elif encmode == 'snz':
1151 svp64_rm.branch.sz = 1
1152 svp64_rm.branch.SNZ = 1
1153 elif encmode == 'sl':
1154 svp64_rm.branch.SL = 1
1155 elif encmode == 'slu':
1156 svp64_rm.branch.SLu = 1
1157 elif encmode == 'lru':
1158 svp64_rm.branch.LRu = 1
1159 elif encmode == 'vs':
1160 svp64_rm.branch.VLS = 1
1161 elif encmode == 'vsi':
1162 svp64_rm.branch.VLS = 1
1163 svp64_rm.branch.vls.VLI = 1
1164 elif encmode == 'vsb':
1165 svp64_rm.branch.VLS = 1
1166 svp64_rm.branch.vls.VSb = 1
1167 elif encmode == 'vsbi':
1168 svp64_rm.branch.VLS = 1
1169 svp64_rm.branch.vls.VSb = 1
1170 svp64_rm.branch.vls.VLI = 1
1171 elif encmode == 'ctr':
1172 svp64_rm.branch.CTR = 1
1173 elif encmode == 'cti':
1174 svp64_rm.branch.CTR = 1
1175 svp64_rm.branch.ctr.CTi = 1
1176 else:
1177 raise AssertionError("unknown encmode %s" % encmode)
1178 else:
1179 raise AssertionError("unknown encmode %s" % encmode)
1180
1181 if ptype == '2P':
1182 # since m=xx takes precedence (overrides) sm=xx and dm=xx,
1183 # treat them as mutually exclusive
1184 if mask_m_specified:
1185 assert not has_smask,\
1186 "cannot have both source-mask and predicate mask"
1187 assert not has_pmask,\
1188 "cannot have both dest-mask and predicate mask"
1189 # since the default is INT predication (ALWAYS), if you
1190 # specify one CR mask, you must specify both, to avoid
1191 # mixing INT and CR reg types
1192 if has_pmask and pmmode == 1:
1193 assert has_smask, \
1194 "need explicit source-mask in CR twin predication"
1195 if has_smask and smmode == 1:
1196 assert has_pmask, \
1197 "need explicit dest-mask in CR twin predication"
1198 # sanity-check that 2Pred mask is same mode
1199 if has_pmask and has_smask:
1200 assert smmode == pmmode, \
1201 "predicate masks %s and %s must be same reg type" % \
1202 (pme, sme)
1203
1204 # sanity-check that twin-predication mask only specified in 2P mode
1205 if ptype == '1P':
1206 assert not has_smask, \
1207 "source-mask can only be specified on Twin-predicate ops"
1208 assert not has_pmask, \
1209 "dest-mask can only be specified on Twin-predicate ops"
1210
1211 # construct the mode field, doing sanity-checking along the way
1212
1213 if src_zero:
1214 assert has_smask or mask_m_specified, \
1215 "src zeroing requires a source predicate"
1216 if dst_zero:
1217 assert has_pmask or mask_m_specified, \
1218 "dest zeroing requires a dest predicate"
1219
1220 # okaaay, so there are 4 different modes, here, which will be
1221 # partly-merged-in: is_ldst is merged in with "normal", but
1222 # is_bc is so different it's done separately. likewise is_cr
1223 # (when it is done). here are the maps:
1224
1225 # for "normal" arithmetic: https://libre-soc.org/openpower/sv/normal/
1226 """
1227 | 0-1 | 2 | 3 4 | description |
1228 | --- | --- |---------|-------------------------- |
1229 | 00 | 0 | dz sz | simple mode |
1230 | 00 | 1 | 0 RG | scalar reduce mode (mapreduce) |
1231 | 01 | inv | CR-bit | Rc=1: ffirst CR sel |
1232 | 01 | inv | VLi RC1 | Rc=0: ffirst z/nonz |
1233 | 10 | N | dz sz | sat mode: N=0/1 u/s |
1234 | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
1235 | 11 | inv | zz RC1 | Rc=0: pred-result z/nonz |
1236 """
1237
1238 # https://libre-soc.org/openpower/sv/ldst/
1239 # for LD/ST-immediate:
1240 """
1241 | 0-1 | 2 | 3 4 | description |
1242 | --- | --- |---------|--------------------------- |
1243 | 00 | 0 | zz els | normal mode |
1244 | 00 | 1 | / / | reserved |
1245 | 01 | inv | CR-bit | Rc=1: ffirst CR sel |
1246 | 01 | inv | els RC1 | Rc=0: ffirst z/nonz |
1247 | 10 | N | zz els | sat mode: N=0/1 u/s |
1248 | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
1249 | 11 | inv | els RC1 | Rc=0: pred-result z/nonz |
1250 """
1251
1252 # for LD/ST-indexed (RA+RB):
1253 """
1254 | 0-1 | 2 | 3 4 | description |
1255 | --- | --- |---------|-------------------------- |
1256 | 00 | SEA | dz sz | normal mode |
1257 | 01 | SEA | dz sz | Strided (scalar only source) |
1258 | 10 | N | dz sz | sat mode: N=0/1 u/s |
1259 | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
1260 | 11 | inv | dz RC1 | Rc=0: pred-result z/nonz |
1261 """
1262
1263 # and leaving out branches and cr_ops for now because they're
1264 # under development
1265 """ TODO branches and cr_ops
1266 """
1267
1268 if is_bc:
1269 sv_mode = int(svp64_rm.mode[0, 1])
1270 if src_zero:
1271 svp64_rm.branch.sz = 1
1272
1273 else:
1274 ######################################
1275 # "normal" mode
1276 if sv_mode is None:
1277 mode |= src_zero << SVP64MODE.SZ # predicate zeroing
1278 mode |= dst_zero << SVP64MODE.DZ # predicate zeroing
1279 if is_ldst:
1280 # TODO: for now, LD/ST-indexed is ignored.
1281 mode |= ldst_elstride << SVP64MODE.ELS_NORMAL # el-strided
1282 else:
1283 # TODO, reduce and subvector mode
1284 # 00 1 dz CRM reduce mode (mapreduce), SUBVL=1
1285 # 00 1 SVM CRM subvector reduce mode, SUBVL>1
1286 pass
1287 sv_mode = 0b00
1288
1289 ######################################
1290 # "mapreduce" modes
1291 elif sv_mode == 0b00:
1292 mode |= (0b1 << SVP64MODE.REDUCE) # sets mapreduce
1293 assert dst_zero == 0, "dest-zero not allowed in mapreduce mode"
1294 if reverse_gear:
1295 mode |= (0b1 << SVP64MODE.RG) # sets Reverse-gear mode
1296 if mapreduce_crm:
1297 mode |= (0b1 << SVP64MODE.CRM) # sets CRM mode
1298 assert rc_mode, "CRM only allowed when Rc=1"
1299 # bit of weird encoding to jam zero-pred or SVM mode in.
1300 # SVM mode can be enabled only when SUBVL=2/3/4 (vec2/3/4)
1301 if subvl == 0:
1302 mode |= dst_zero << SVP64MODE.DZ # predicate zeroing
1303
1304 ######################################
1305 # "failfirst" modes
1306 elif sv_mode == 0b01:
1307 assert src_zero == 0, "dest-zero not allowed in failfirst mode"
1308 if failfirst == 'RC1':
1309 mode |= (0b1 << SVP64MODE.RC1) # sets RC1 mode
1310 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1311 assert rc_mode == False, "ffirst RC1 only ok when Rc=0"
1312 elif failfirst == '~RC1':
1313 mode |= (0b1 << SVP64MODE.RC1) # sets RC1 mode
1314 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1315 mode |= (0b1 << SVP64MODE.INV) # ... with inversion
1316 assert rc_mode == False, "ffirst RC1 only ok when Rc=0"
1317 else:
1318 assert dst_zero == 0, "dst-zero not allowed in ffirst BO"
1319 assert rc_mode, "ffirst BO only possible when Rc=1"
1320 mode |= (failfirst << SVP64MODE.BO_LSB) # set BO
1321
1322 ######################################
1323 # "saturation" modes
1324 elif sv_mode == 0b10:
1325 mode |= src_zero << SVP64MODE.SZ # predicate zeroing
1326 mode |= dst_zero << SVP64MODE.DZ # predicate zeroing
1327 mode |= (saturation << SVP64MODE.N) # signed/us saturation
1328
1329 ######################################
1330 # "predicate-result" modes. err... code-duplication from ffirst
1331 elif sv_mode == 0b11:
1332 assert src_zero == 0, "dest-zero not allowed in predresult mode"
1333 if predresult == 'RC1':
1334 mode |= (0b1 << SVP64MODE.RC1) # sets RC1 mode
1335 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1336 assert rc_mode == False, "pr-mode RC1 only ok when Rc=0"
1337 elif predresult == '~RC1':
1338 mode |= (0b1 << SVP64MODE.RC1) # sets RC1 mode
1339 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1340 mode |= (0b1 << SVP64MODE.INV) # ... with inversion
1341 assert rc_mode == False, "pr-mode RC1 only ok when Rc=0"
1342 else:
1343 assert dst_zero == 0, "dst-zero not allowed in pr-mode BO"
1344 assert rc_mode, "pr-mode BO only possible when Rc=1"
1345 mode |= (predresult << SVP64MODE.BO_LSB) # set BO
1346
1347 # whewww.... modes all done :)
1348 # now put into svp64_rm, but respect MSB0 order
1349 if sv_mode&1:
1350 mode |= (0b1<<SVP64MODE.MOD2_LSB)
1351 if sv_mode&2:
1352 mode |= (0b1<<SVP64MODE.MOD2_MSB)
1353
1354 if not is_bc:
1355 svp64_rm.mode = mode # mode: bits 19-23
1356 if vli:
1357 svp64_rm.normal.ffrc0.VLi = 1
1358
1359 # put in predicate masks into svp64_rm
1360 if ptype == '2P':
1361 svp64_rm.smask = smask # source pred: bits 16-18
1362
1363 # put in elwidths unless bc
1364 svp64_rm.ewsrc = srcwid # srcwid: bits 6-7
1365 svp64_rm.elwidth = destwid # destwid: bits 4-5
1366
1367 svp64_rm.mmode = mmode # mask mode: bit 0
1368 svp64_rm.mask = pmask # 1-pred: bits 1-3
1369 svp64_rm.subvl = subvl # and subvl: bits 8-9
1370
1371 # nice debug printout. (and now for something completely different)
1372 # https://youtu.be/u0WOIwlXE9g?t=146
1373 svp64_rm_value = int(svp64_rm)
1374 log("svp64_rm", hex(svp64_rm_value), bin(svp64_rm_value))
1375 log(" mmode 0 :", bin(mmode))
1376 log(" pmask 1-3 :", bin(pmask))
1377 log(" dstwid 4-5 :", bin(destwid))
1378 log(" srcwid 6-7 :", bin(srcwid))
1379 log(" subvl 8-9 :", bin(subvl))
1380 log(" mode 19-23:", bin(svp64_rm.mode))
1381 offs = 2 if etype == 'EXTRA2' else 3 # 2 or 3 bits
1382 for idx, sv_extra in extras.items():
1383 if idx is None:
1384 continue
1385 if idx[0] == 'imm':
1386 continue
1387 srcdest, idx, duplicate = idx
1388 start = (10+idx*offs)
1389 end = start + offs-1
1390 log(" extra%d %2d-%2d:" % (idx, start, end),
1391 bin(sv_extra))
1392 if ptype == '2P':
1393 log(" smask 16-17:", bin(smask))
1394 log()
1395
1396 # update prefix PO and ID (aka PID)
1397 svp64_prefix.po = 0x1
1398 svp64_prefix.id = 0b11
1399
1400 # fiinally yield the svp64 prefix and the thingy. v3.0b opcode
1401 rc = '.' if rc_mode else ''
1402 yield ".long 0x%08x" % int(svp64_prefix)
1403 log(v30b_op, v30b_newfields)
1404
1405 v30b_op_rc = v30b_op
1406 if not v30b_op.endswith('.'):
1407 v30b_op_rc += rc
1408
1409 # svstep is weird
1410 # FIXME(lkcl): should sv.svstep be like svstep?
1411 if v30b_op_rc in ("svstep", "svstep."):
1412 # compensate for `SVi -= 1` in svstep()
1413 v30b_newfields[1] = str(int(v30b_newfields[1]) + 1)
1414
1415 custom_insn_hook = CUSTOM_INSNS.get(v30b_op_rc)
1416 if custom_insn_hook is not None:
1417 fields = tuple(map(to_number, v30b_newfields))
1418 insn_num = custom_insn_hook(fields)
1419 log(opcode, bin(insn_num))
1420 yield ".long 0x%X # %s" % (insn_num, insn)
1421 return
1422 # argh, sv.fmadds etc. need to be done manually
1423 elif v30b_op == 'ffmadds':
1424 opcode = 59 << (32-6) # bits 0..6 (MSB0)
1425 opcode |= int(v30b_newfields[0]) << (32-11) # FRT
1426 opcode |= int(v30b_newfields[1]) << (32-16) # FRA
1427 opcode |= int(v30b_newfields[2]) << (32-21) # FRB
1428 opcode |= int(v30b_newfields[3]) << (32-26) # FRC
1429 opcode |= 0b00101 << (32-31) # bits 26-30
1430 if rc:
1431 opcode |= 1 # Rc, bit 31.
1432 yield ".long 0x%x" % opcode
1433 # argh, sv.fdmadds need to be done manually
1434 elif v30b_op == 'fdmadds':
1435 opcode = 59 << (32-6) # bits 0..6 (MSB0)
1436 opcode |= int(v30b_newfields[0]) << (32-11) # FRT
1437 opcode |= int(v30b_newfields[1]) << (32-16) # FRA
1438 opcode |= int(v30b_newfields[2]) << (32-21) # FRB
1439 opcode |= int(v30b_newfields[3]) << (32-26) # FRC
1440 opcode |= 0b11011 << (32-31) # bits 26-30
1441 if rc:
1442 opcode |= 1 # Rc, bit 31.
1443 yield ".long 0x%x" % opcode
1444 # argh, sv.ffadds etc. need to be done manually
1445 elif v30b_op == 'ffadds':
1446 opcode = 59 << (32-6) # bits 0..6 (MSB0)
1447 opcode |= int(v30b_newfields[0]) << (32-11) # FRT
1448 opcode |= int(v30b_newfields[1]) << (32-16) # FRA
1449 opcode |= int(v30b_newfields[2]) << (32-21) # FRB
1450 opcode |= 0b1111100000 << (32-31) # bits 21-30
1451 if rc:
1452 opcode |= 1 # Rc, bit 31.
1453 yield ".long 0x%x" % opcode
1454 else:
1455 if not v30b_op.endswith('.'):
1456 v30b_op += rc
1457 yield "%s %s" % (v30b_op, ", ".join(v30b_newfields))
1458 for (field, value, span) in svp64_insn.traverse("SVP64"):
1459 log(field, f"{value.value:0{value.bits}b}", span)
1460 log("new v3.0B fields", v30b_op, v30b_newfields)
1461
1462 def translate(self, lst):
1463 for insn in lst:
1464 yield from self.translate_one(insn)
1465
1466
1467 def macro_subst(macros, txt):
1468 again = True
1469 log("subst", txt, macros)
1470 while again:
1471 again = False
1472 for macro, value in macros.items():
1473 if macro == txt:
1474 again = True
1475 replaced = txt.replace(macro, value)
1476 log("macro", txt, "replaced", replaced, macro, value)
1477 txt = replaced
1478 continue
1479 toreplace = '%s.s' % macro
1480 if toreplace == txt:
1481 again = True
1482 replaced = txt.replace(toreplace, "%s.s" % value)
1483 log("macro", txt, "replaced", replaced, toreplace, value)
1484 txt = replaced
1485 continue
1486 toreplace = '%s.v' % macro
1487 if toreplace == txt:
1488 again = True
1489 replaced = txt.replace(toreplace, "%s.v" % value)
1490 log("macro", txt, "replaced", replaced, toreplace, value)
1491 txt = replaced
1492 continue
1493 toreplace = '(%s)' % macro
1494 if toreplace in txt:
1495 again = True
1496 replaced = txt.replace(toreplace, '(%s)' % value)
1497 log("macro", txt, "replaced", replaced, toreplace, value)
1498 txt = replaced
1499 continue
1500 log(" processed", txt)
1501 return txt
1502
1503
1504 def get_ws(line):
1505 # find whitespace
1506 ws = ''
1507 while line:
1508 if not line[0].isspace():
1509 break
1510 ws += line[0]
1511 line = line[1:]
1512 return ws, line
1513
1514
1515 def asm_process():
1516 # get an input file and an output file
1517 args = sys.argv[1:]
1518 if len(args) == 0:
1519 infile = sys.stdin
1520 outfile = sys.stdout
1521 # read the whole lot in advance in case of in-place
1522 lines = list(infile.readlines())
1523 elif len(args) != 2:
1524 print("pysvp64asm [infile | -] [outfile | -]", file=sys.stderr)
1525 exit(0)
1526 else:
1527 if args[0] == '--':
1528 infile = sys.stdin
1529 else:
1530 infile = open(args[0], "r")
1531 # read the whole lot in advance in case of in-place overwrite
1532 lines = list(infile.readlines())
1533
1534 if args[1] == '--':
1535 outfile = sys.stdout
1536 else:
1537 outfile = open(args[1], "w")
1538
1539 # read the line, look for custom insn, process it
1540 macros = {} # macros which start ".set"
1541 isa = SVP64Asm([])
1542 for line in lines:
1543 op = line.split("#")[0].strip()
1544 # identify macros
1545 if op.startswith(".set"):
1546 macro = op[4:].split(",")
1547 (macro, value) = map(str.strip, macro)
1548 macros[macro] = value
1549 if not op.startswith('sv.') and not op.startswith(tuple(CUSTOM_INSNS)):
1550 outfile.write(line)
1551 continue
1552
1553 (ws, line) = get_ws(line)
1554 lst = isa.translate_one(op, macros)
1555 lst = '; '.join(lst)
1556 outfile.write("%s%s # %s\n" % (ws, lst, op))
1557
1558
1559 if __name__ == '__main__':
1560 lst = ['slw 3, 1, 4',
1561 'extsw 5, 3',
1562 'sv.extsw 5, 3',
1563 'sv.cmpi 5, 1, 3, 2',
1564 'sv.setb 5, 31',
1565 'sv.isel 64.v, 3, 2, 65.v',
1566 'sv.setb/dm=r3/sm=1<<r3 5, 31',
1567 'sv.setb/m=r3 5, 31',
1568 'sv.setb/vec2 5, 31',
1569 'sv.setb/sw=8/ew=16 5, 31',
1570 'sv.extsw./ff=eq 5, 31',
1571 'sv.extsw./satu/sz/dz/sm=r3/dm=r3 5, 31',
1572 'sv.extsw./pr=eq 5.v, 31',
1573 'sv.add. 5.v, 2.v, 1.v',
1574 'sv.add./m=r3 5.v, 2.v, 1.v',
1575 ]
1576 lst += [
1577 'sv.stw 5.v, 4(1.v)',
1578 'sv.ld 5.v, 4(1.v)',
1579 'setvl. 2, 3, 4, 0, 1, 1',
1580 'sv.setvl. 2, 3, 4, 0, 1, 1',
1581 ]
1582 lst = [
1583 "sv.stfsu 0.v, 16(4.v)",
1584 ]
1585 lst = [
1586 "sv.stfsu/els 0.v, 16(4)",
1587 ]
1588 lst = [
1589 'sv.add./mr 5.v, 2.v, 1.v',
1590 ]
1591 macros = {'win2': '50', 'win': '60'}
1592 lst = [
1593 'sv.addi win2.v, win.v, -1',
1594 'sv.add./mrr 5.v, 2.v, 1.v',
1595 #'sv.lhzsh 5.v, 11(9.v), 15',
1596 #'sv.lwzsh 5.v, 11(9.v), 15',
1597 'sv.ffmadds 6.v, 2.v, 4.v, 6.v',
1598 ]
1599 lst = [
1600 #'sv.fmadds 0.v, 8.v, 16.v, 4.v',
1601 #'sv.ffadds 0.v, 8.v, 4.v',
1602 'svremap 11, 0, 1, 2, 3, 2, 1',
1603 'svshape 8, 1, 1, 1, 0',
1604 'svshape 8, 1, 1, 1, 1',
1605 ]
1606 lst = [
1607 #'sv.lfssh 4.v, 11(8.v), 15',
1608 #'sv.lwzsh 4.v, 11(8.v), 15',
1609 #'sv.svstep. 2.v, 4, 0',
1610 #'sv.fcfids. 48.v, 64.v',
1611 'sv.fcoss. 80.v, 0.v',
1612 'sv.fcoss. 20.v, 0.v',
1613 ]
1614 lst = [
1615 'sv.bc/all 3,12,192',
1616 'sv.bclr/vsbi 3,81.v,192',
1617 'sv.ld 5.v, 4(1.v)',
1618 'sv.svstep. 2.v, 4, 0',
1619 ]
1620 lst = [
1621 'maxs 3,12,5',
1622 'maxs. 3,12,5',
1623 'avgadd 3,12,5',
1624 'absdu 3,12,5',
1625 'absds 3,12,5',
1626 'absdacu 3,12,5',
1627 'absdacs 3,12,5',
1628 'cprop 3,12,5',
1629 'svindex 0,0,1,0,0,0,0',
1630 ]
1631 lst = [
1632 'sv.svstep./m=r3 2.v, 4, 0',
1633 'ternlogi 0,0,0,0x5',
1634 'fmvis 5,65535',
1635 'fmvis 5,1',
1636 'fmvis 5,2',
1637 'fmvis 5,4',
1638 'fmvis 5,8',
1639 'fmvis 5,16',
1640 'fmvis 5,32',
1641 'fmvis 5,64',
1642 'fmvis 5,32768',
1643 ]
1644 lst = [
1645 'sv.andi. *80, *80, 1',
1646 'sv.ffmadds. 6.v, 2.v, 4.v, 6.v', # incorrectly inserted 32-bit op
1647 'sv.ffmadds 6.v, 2.v, 4.v, 6.v', # correctly converted to .long
1648 'svshape2 8, 1, 31, 7, 1, 1',
1649 'sv.ld 5.v, 4(1.v)',
1650 'sv.stw 5.v, 4(1.v)',
1651 'sv.bc/all 3,12,192',
1652 'pcdec. 0,0,0,0,0',
1653 ]
1654 isa = SVP64Asm(lst, macros=macros)
1655 log("list:\n", "\n\t".join(list(isa)))
1656 # running svp64.py is designed to test hard-coded lists
1657 # (above) - which strictly speaking should all be unit tests.
1658 # if you need to actually do assembler translation at the
1659 # commandline use "pysvp64asm" - see setup.py
1660 # XXX NO. asm_process()