rename divrem2du->divmod2du for consistency with PowerISA mod* instructions
[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 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
572 # 1.6.21.1 VA2-FORM
573 # |0 |6 |11 |16 |21 |24|26 |31 |
574 # | PO | RT | RA | RB | RC | XO |once|
575 PO = 4
576 XO = 0b11100
577 (RT, RA, RB, RC, once) = fields
578 return instruction(
579 (PO, 0, 5),
580 (RT, 6, 10),
581 (RA, 11, 15),
582 (RB, 16, 20),
583 (RC, 21, 25),
584 (XO, 26, 30),
585 (once, 31, 31),
586 )
587
588
589 @_custom_insns(
590 _insn("madded", XO=50),
591 _insn("divmod2du", XO=52),
592 )
593 def va_form(fields, XO):
594 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
595 # 1.6.21.1 VA-FORM
596 # |0 |6 |11 |16 |21 |26 |
597 # | PO | RT | RA | RB | RC | XO |
598 PO = 4
599 (RT, RA, RB, RC) = fields
600 return instruction(
601 (PO, 0, 5),
602 (RT, 6, 10),
603 (RA, 11, 15),
604 (RB, 16, 20),
605 (RC, 21, 25),
606 (XO, 26, 31),
607 )
608
609
610 @_custom_insns(
611 _insn("dsld", XO=0b00111001, Rc=0),
612 _insn("dsld.", XO=0b00111001, Rc=1),
613 _insn("dsrd", XO=0b10111001, Rc=0),
614 _insn("dsrd.", XO=0b10111001, Rc=1),
615 )
616 def dsld_dsrd(fields, XO, Rc):
617 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
618 # 1.6.27 Z23-FORM
619 # |0 |6 |11 |15 |16 |21 |23 |31 |
620 # | PO | RT | RA | RB |sm | XO |Rc |
621 PO = 31
622 (RT, RA, RB, sm) = fields
623 return instruction(
624 (PO, 0, 5),
625 (RT, 6, 10),
626 (RA, 11, 15),
627 (RB, 16, 20),
628 (sm, 21, 22),
629 (XO, 23, 30),
630 (Rc, 31, 31),
631 )
632
633
634 # decode GPR into sv extra
635 def get_extra_gpr(etype, regmode, field):
636 if regmode == 'scalar':
637 # cut into 2-bits 5-bits SS FFFFF
638 sv_extra = field >> 5
639 field = field & 0b11111
640 else:
641 # cut into 5-bits 2-bits FFFFF SS
642 sv_extra = field & 0b11
643 field = field >> 2
644 return sv_extra, field
645
646
647 # decode 3-bit CR into sv extra
648 def get_extra_cr_3bit(etype, regmode, field):
649 if regmode == 'scalar':
650 # cut into 2-bits 3-bits SS FFF
651 sv_extra = field >> 3
652 field = field & 0b111
653 else:
654 # cut into 3-bits 4-bits FFF SSSS but will cut 2 zeros off later
655 sv_extra = field & 0b1111
656 field = field >> 4
657 return sv_extra, field
658
659
660 # decodes SUBVL
661 def decode_subvl(encoding):
662 pmap = {'2': 0b01, '3': 0b10, '4': 0b11}
663 assert encoding in pmap, \
664 "encoding %s for SUBVL not recognised" % encoding
665 return pmap[encoding]
666
667
668 # decodes elwidth
669 def decode_elwidth(encoding):
670 pmap = {'8': 0b11, '16': 0b10, '32': 0b01}
671 assert encoding in pmap, \
672 "encoding %s for elwidth not recognised" % encoding
673 return pmap[encoding]
674
675
676 # decodes predicate register encoding
677 def decode_predicate(encoding):
678 pmap = { # integer
679 '1<<r3': (0, 0b001),
680 'r3': (0, 0b010),
681 '~r3': (0, 0b011),
682 'r10': (0, 0b100),
683 '~r10': (0, 0b101),
684 'r30': (0, 0b110),
685 '~r30': (0, 0b111),
686 # CR
687 'lt': (1, 0b000),
688 'nl': (1, 0b001), 'ge': (1, 0b001), # same value
689 'gt': (1, 0b010),
690 'ng': (1, 0b011), 'le': (1, 0b011), # same value
691 'eq': (1, 0b100),
692 'ne': (1, 0b101),
693 'so': (1, 0b110), 'un': (1, 0b110), # same value
694 'ns': (1, 0b111), 'nu': (1, 0b111), # same value
695 }
696 assert encoding in pmap, \
697 "encoding %s for predicate not recognised" % encoding
698 return pmap[encoding]
699
700
701 # decodes "Mode" in similar way to BO field (supposed to, anyway)
702 def decode_bo(encoding):
703 pmap = { # TODO: double-check that these are the same as Branch BO
704 'lt': 0b000,
705 'nl': 0b001, 'ge': 0b001, # same value
706 'gt': 0b010,
707 'ng': 0b011, 'le': 0b011, # same value
708 'eq': 0b100,
709 'ne': 0b101,
710 'so': 0b110, 'un': 0b110, # same value
711 'ns': 0b111, 'nu': 0b111, # same value
712 }
713 assert encoding in pmap, \
714 "encoding %s for BO Mode not recognised" % encoding
715 # barse-ackwards MSB0/LSB0. sigh. this would be nice to be the
716 # same as the decode_predicate() CRfield table above, but (inv,CRbit)
717 # is how it is in the spec [decode_predicate is (CRbit,inv)]
718 mapped = pmap[encoding]
719 si = SelectableInt(0, 3)
720 si[0] = mapped & 1 # inv
721 si[1:3] = mapped >> 1 # CR
722 return int(si)
723
724
725 # partial-decode fail-first mode
726 def decode_ffirst(encoding):
727 if encoding in ['RC1', '~RC1']:
728 return encoding
729 return decode_bo(encoding)
730
731
732 def decode_reg(field, macros=None):
733 if macros is None:
734 macros = {}
735 # decode the field number. "5.v" or "3.s" or "9"
736 # and now also "*0", and "*%0". note: *NOT* to add "*%rNNN" etc.
737 # https://bugs.libre-soc.org/show_bug.cgi?id=884#c0
738 if field.startswith(("*%", "*")):
739 if field.startswith("*%"):
740 field = field[2:]
741 else:
742 field = field[1:]
743 while field in macros:
744 field = macros[field]
745 return int(field), "vector" # actual register number
746
747 # try old convention (to be retired)
748 field = field.split(".")
749 regmode = 'scalar' # default
750 if len(field) == 2:
751 if field[1] == 's':
752 regmode = 'scalar'
753 elif field[1] == 'v':
754 regmode = 'vector'
755 field = int(field[0]) # actual register number
756 return field, regmode
757
758
759 def decode_imm(field):
760 ldst_imm = "(" in field and field[-1] == ')'
761 if ldst_imm:
762 return field[:-1].split("(")
763 else:
764 return None, field
765
766
767 def crf_extra(etype, rname, extra_idx, regmode, field, extras):
768 """takes a CR Field number (CR0-CR127), splits into EXTRA2/3 and v3.0
769 the scalar/vector mode (crNN.v or crNN.s) changes both the format
770 of the EXTRA2/3 encoding as well as what range of registers is possible.
771 this function can be used for both BF/BFA and BA/BB/BT by first removing
772 the bottom 2 bits of BA/BB/BT then re-instating them after encoding.
773 see https://libre-soc.org/openpower/sv/svp64/appendix/#cr_extra
774 for specification
775 """
776 sv_extra, field = get_extra_cr_3bit(etype, regmode, field)
777 # now sanity-check (and shrink afterwards)
778 if etype == 'EXTRA2':
779 # 3-bit CR Field (BF, BFA) EXTRA2 encoding
780 if regmode == 'scalar':
781 # range is CR0-CR15 in increments of 1
782 assert (sv_extra >> 1) == 0, \
783 "scalar CR %s cannot fit into EXTRA2 %s" % \
784 (rname, str(extras[extra_idx]))
785 # all good: encode as scalar
786 sv_extra = sv_extra & 0b01
787 else: # vector
788 # range is CR0-CR127 in increments of 16
789 assert sv_extra & 0b111 == 0, \
790 "vector CR %s cannot fit into EXTRA2 %s" % \
791 (rname, str(extras[extra_idx]))
792 # all good: encode as vector (bit 2 set)
793 sv_extra = 0b10 | (sv_extra >> 3)
794 else:
795 # 3-bit CR Field (BF, BFA) EXTRA3 encoding
796 if regmode == 'scalar':
797 # range is CR0-CR31 in increments of 1
798 assert (sv_extra >> 2) == 0, \
799 "scalar CR %s cannot fit into EXTRA3 %s" % \
800 (rname, str(extras[extra_idx]))
801 # all good: encode as scalar
802 sv_extra = sv_extra & 0b11
803 else: # vector
804 # range is CR0-CR127 in increments of 8
805 assert sv_extra & 0b11 == 0, \
806 "vector CR %s cannot fit into EXTRA3 %s" % \
807 (rname, str(extras[extra_idx]))
808 # all good: encode as vector (bit 3 set)
809 sv_extra = 0b100 | (sv_extra >> 2)
810 return sv_extra, field
811
812
813 def to_number(field):
814 if field.startswith("0x"):
815 return eval(field)
816 if field.startswith("0b"):
817 return eval(field)
818 return int(field)
819
820
821 db = Database(find_wiki_dir())
822
823
824 # decodes svp64 assembly listings and creates EXT001 svp64 prefixes
825 class SVP64Asm:
826 def __init__(self, lst, bigendian=False, macros=None):
827 if macros is None:
828 macros = {}
829 self.macros = macros
830 self.lst = lst
831 self.trans = self.translate(lst)
832 self.isa = ISA() # reads the v3.0B pseudo-code markdown files
833 self.svp64 = SVP64RM() # reads the svp64 Remap entries for registers
834 assert bigendian == False, "error, bigendian not supported yet"
835
836 def __iter__(self):
837 yield from self.trans
838
839 def translate_one(self, insn, macros=None):
840 if macros is None:
841 macros = {}
842 macros.update(self.macros)
843 isa = self.isa
844 svp64 = self.svp64
845 insn_no_comments = insn.partition('#')[0]
846 # find first space, to get opcode
847 ls = insn_no_comments.split()
848 opcode = ls[0]
849 # now find opcode fields
850 fields = ''.join(ls[1:]).split(',')
851 mfields = list(map(str.strip, fields))
852 log("opcode, fields", ls, opcode, mfields)
853 fields = []
854 # macro substitution
855 for field in mfields:
856 fields.append(macro_subst(macros, field))
857 log("opcode, fields substed", ls, opcode, fields)
858
859 # identify if it is a special instruction
860 custom_insn_hook = CUSTOM_INSNS.get(opcode)
861 if custom_insn_hook is not None:
862 fields = tuple(map(to_number, fields))
863 insn_num = custom_insn_hook(fields)
864 log(opcode, bin(insn_num))
865 yield ".long 0x%X # %s" % (insn_num, insn)
866 return
867
868 # identify if is a svp64 mnemonic
869 if not opcode.startswith('sv.'):
870 yield insn # unaltered
871 return
872 opcode = opcode[3:] # strip leading "sv"
873
874 # start working on decoding the svp64 op: sv.basev30Bop/vec2/mode
875 opmodes = opcode.split("/") # split at "/"
876 v30b_op_orig = opmodes.pop(0) # first is the v3.0B
877 # check instruction ends with dot
878 rc_mode = v30b_op_orig.endswith('.')
879 if rc_mode:
880 v30b_op = v30b_op_orig[:-1]
881 else:
882 v30b_op = v30b_op_orig
883
884 # look up the 32-bit op (original, with "." if it has it)
885 if v30b_op_orig in isa.instr:
886 isa_instr = isa.instr[v30b_op_orig]
887 else:
888 raise Exception("opcode %s of '%s' not supported" %
889 (v30b_op_orig, insn))
890
891 # look up the svp64 op, first the original (with "." if it has it)
892 if v30b_op_orig in svp64.instrs:
893 rm = svp64.instrs[v30b_op_orig] # one row of the svp64 RM CSV
894 # then without the "." (if there was one)
895 elif v30b_op in svp64.instrs:
896 rm = svp64.instrs[v30b_op] # one row of the svp64 RM CSV
897 else:
898 raise Exception(f"opcode {v30b_op_orig!r} of "
899 f"{insn!r} not an svp64 instruction")
900
901 # get regs info e.g. "RT,RA,RB"
902 v30b_regs = isa_instr.regs[0]
903 log("v3.0B op", v30b_op, "Rc=1" if rc_mode else '')
904 log("v3.0B regs", opcode, v30b_regs)
905 log("RM", rm)
906
907 # right. the first thing to do is identify the ordering of
908 # the registers, by name. the EXTRA2/3 ordering is in
909 # rm['0']..rm['3'] but those fields contain the names RA, BB
910 # etc. we have to read the pseudocode to understand which
911 # reg is which in our instruction. sigh.
912
913 # first turn the svp64 rm into a "by name" dict, recording
914 # which position in the RM EXTRA it goes into
915 # also: record if the src or dest was a CR, for sanity-checking
916 # (elwidth overrides on CRs are banned)
917 decode = decode_extra(rm)
918 dest_reg_cr, src_reg_cr, svp64_src, svp64_dest = decode
919
920 log("EXTRA field index, src", svp64_src)
921 log("EXTRA field index, dest", svp64_dest)
922
923 # okaaay now we identify the field value (opcode N,N,N) with
924 # the pseudo-code info (opcode RT, RA, RB)
925 assert len(fields) == len(v30b_regs), \
926 "length of fields %s must match insn `%s` fields %s" % \
927 (str(v30b_regs), insn, str(fields))
928 opregfields = zip(fields, v30b_regs) # err that was easy
929
930 # now for each of those find its place in the EXTRA encoding
931 # note there is the possibility (for LD/ST-with-update) of
932 # RA occurring **TWICE**. to avoid it getting added to the
933 # v3.0B suffix twice, we spot it as a duplicate, here
934 extras = OrderedDict()
935 for idx, (field, regname) in enumerate(opregfields):
936 imm, regname = decode_imm(regname)
937 rtype = get_regtype(regname)
938 log(" idx find", rtype, idx, field, regname, imm)
939 if rtype is None:
940 # probably an immediate field, append it straight
941 extras[('imm', idx, False)] = (idx, field, None, None, None)
942 continue
943 extra = svp64_src.get(regname, None)
944 if extra is not None:
945 extra = ('s', extra, False) # not a duplicate
946 extras[extra] = (idx, field, regname, rtype, imm)
947 log(" idx src", idx, extra, extras[extra])
948 dextra = svp64_dest.get(regname, None)
949 log("regname in", regname, dextra)
950 if dextra is not None:
951 is_a_duplicate = extra is not None # duplicate spotted
952 dextra = ('d', dextra, is_a_duplicate)
953 extras[dextra] = (idx, field, regname, rtype, imm)
954 log(" idx dst", idx, extra, extras[dextra])
955
956 # great! got the extra fields in their associated positions:
957 # also we know the register type. now to create the EXTRA encodings
958 etype = rm['Etype'] # Extra type: EXTRA3/EXTRA2
959 ptype = rm['Ptype'] # Predication type: Twin / Single
960 extra_bits = 0
961 v30b_newfields = []
962 for extra_idx, (idx, field, rname, rtype, iname) in extras.items():
963 # is it a field we don't alter/examine? if so just put it
964 # into newfields
965 if rtype is None:
966 v30b_newfields.append(field)
967 continue
968
969 # identify if this is a ld/st immediate(reg) thing
970 ldst_imm = "(" in field and field[-1] == ')'
971 if ldst_imm:
972 immed, field = field[:-1].split("(")
973
974 field, regmode = decode_reg(field, macros=macros)
975 log(" ", extra_idx, rname, rtype,
976 regmode, iname, field, end=" ")
977
978 # see Mode field https://libre-soc.org/openpower/sv/svp64/
979 # XXX TODO: the following is a bit of a laborious repeated
980 # mess, which could (and should) easily be parameterised.
981 # XXX also TODO: the LD/ST modes which are different
982 # https://libre-soc.org/openpower/sv/ldst/
983
984 # rright. SVP64 register numbering is from 0 to 127
985 # for GPRs, FPRs *and* CR Fields, where for v3.0 the GPRs and RPFs
986 # are 0-31 and CR Fields are only 0-7. the SVP64 RM "Extra"
987 # area is used to extend the numbering from the 32-bit
988 # instruction, and also to record whether the register
989 # is scalar or vector. on a per-operand basis. this
990 # results in a slightly finnicky encoding: here we go...
991
992 # encode SV-GPR and SV-FPR field into extra, v3.0field
993 if rtype in ['GPR', 'FPR']:
994 sv_extra, field = get_extra_gpr(etype, regmode, field)
995 # now sanity-check. EXTRA3 is ok, EXTRA2 has limits
996 # (and shrink to a single bit if ok)
997 if etype == 'EXTRA2':
998 if regmode == 'scalar':
999 # range is r0-r63 in increments of 1
1000 assert (sv_extra >> 1) == 0, \
1001 "scalar GPR %s cannot fit into EXTRA2 %s" % \
1002 (rname, str(extras[extra_idx]))
1003 # all good: encode as scalar
1004 sv_extra = sv_extra & 0b01
1005 else:
1006 # range is r0-r127 in increments of 2 (r0 r2 ... r126)
1007 assert sv_extra & 0b01 == 0, \
1008 "%s: vector field %s cannot fit " \
1009 "into EXTRA2 %s" % \
1010 (insn, rname, str(extras[extra_idx]))
1011 # all good: encode as vector (bit 2 set)
1012 sv_extra = 0b10 | (sv_extra >> 1)
1013 elif regmode == 'vector':
1014 # EXTRA3 vector bit needs marking
1015 sv_extra |= 0b100
1016
1017 # encode SV-CR 3-bit field into extra, v3.0field.
1018 # 3-bit is for things like BF and BFA
1019 elif rtype == 'CR_3bit':
1020 sv_extra, field = crf_extra(etype, rname, extra_idx,
1021 regmode, field, extras)
1022
1023 # encode SV-CR 5-bit field into extra, v3.0field
1024 # 5-bit is for things like BA BB BC BT etc.
1025 # *sigh* this is the same as 3-bit except the 2 LSBs of the
1026 # 5-bit field are passed through unaltered.
1027 elif rtype == 'CR_5bit':
1028 cr_subfield = field & 0b11 # record bottom 2 bits for later
1029 field = field >> 2 # strip bottom 2 bits
1030 # use the exact same 3-bit function for the top 3 bits
1031 sv_extra, field = crf_extra(etype, rname, extra_idx,
1032 regmode, field, extras)
1033 # reconstruct the actual 5-bit CR field (preserving the
1034 # bottom 2 bits, unaltered)
1035 field = (field << 2) | cr_subfield
1036
1037 else:
1038 raise Exception("no type match: %s" % rtype)
1039
1040 # capture the extra field info
1041 log("=>", "%5s" % bin(sv_extra), field)
1042 extras[extra_idx] = sv_extra
1043
1044 # append altered field value to v3.0b, differs for LDST
1045 # note that duplicates are skipped e.g. EXTRA2 contains
1046 # *BOTH* s:RA *AND* d:RA which happens on LD/ST-with-update
1047 srcdest, idx, duplicate = extra_idx
1048 if duplicate: # skip adding to v3.0b fields, already added
1049 continue
1050 if ldst_imm:
1051 v30b_newfields.append(("%s(%s)" % (immed, str(field))))
1052 else:
1053 v30b_newfields.append(str(field))
1054
1055 log("new v3.0B fields", v30b_op, v30b_newfields)
1056 log("extras", extras)
1057
1058 # rright. now we have all the info. start creating SVP64 instruction.
1059 svp64_insn = SVP64Instruction.pair(prefix=0, suffix=0)
1060 svp64_prefix = svp64_insn.prefix
1061 svp64_rm = svp64_insn.prefix.rm
1062
1063 # begin with EXTRA fields
1064 for idx, sv_extra in extras.items():
1065 log(idx)
1066 if idx is None:
1067 continue
1068 if idx[0] == 'imm':
1069 continue
1070 srcdest, idx, duplicate = idx
1071 if etype == 'EXTRA2':
1072 svp64_rm.extra2[idx] = sv_extra
1073 else:
1074 svp64_rm.extra3[idx] = sv_extra
1075
1076 # identify if the op is a LD/ST.
1077 # see https://libre-soc.org/openpower/sv/ldst/
1078 is_ldst = rm['mode'] in [ 'LDST_IDX', 'LDST_IMM']
1079 is_ldst_idx = rm['mode'] == 'LDST_IDX'
1080 is_ld = v30b_op.startswith("l") and is_ldst
1081 is_st = v30b_op.startswith("s") and is_ldst
1082
1083 # branch-conditional detection
1084 is_bc = rm['mode'] == 'BRANCH'
1085
1086 # parts of svp64_rm
1087 mmode = 0 # bit 0
1088 pmask = 0 # bits 1-3
1089 destwid = 0 # bits 4-5
1090 srcwid = 0 # bits 6-7
1091 subvl = 0 # bits 8-9
1092 smask = 0 # bits 16-18 but only for twin-predication
1093 mode = 0 # bits 19-23
1094
1095 mask_m_specified = False
1096 has_pmask = False
1097 has_smask = False
1098
1099 saturation = None
1100 src_zero = 0
1101 dst_zero = 0
1102 sv_mode = None
1103
1104 mapreduce = False
1105 reverse_gear = False
1106 mapreduce_crm = False
1107
1108 predresult = False
1109 failfirst = False
1110 ldst_elstride = 0
1111 sea = False
1112
1113 vli = False
1114 sea = False
1115
1116 # ok let's start identifying opcode augmentation fields
1117 for encmode in opmodes:
1118 # predicate mask (src and dest)
1119 if encmode.startswith("m="):
1120 pme = encmode
1121 pmmode, pmask = decode_predicate(encmode[2:])
1122 smmode, smask = pmmode, pmask
1123 mmode = pmmode
1124 mask_m_specified = True
1125 # predicate mask (dest)
1126 elif encmode.startswith("dm="):
1127 pme = encmode
1128 pmmode, pmask = decode_predicate(encmode[3:])
1129 mmode = pmmode
1130 has_pmask = True
1131 # predicate mask (src, twin-pred)
1132 elif encmode.startswith("sm="):
1133 sme = encmode
1134 smmode, smask = decode_predicate(encmode[3:])
1135 mmode = smmode
1136 has_smask = True
1137 # vec2/3/4
1138 elif encmode.startswith("vec"):
1139 subvl = decode_subvl(encmode[3:])
1140 # elwidth (both src and dest, like mask)
1141 elif encmode.startswith("w="):
1142 destwid = decode_elwidth(encmode[2:])
1143 srcwid = decode_elwidth(encmode[2:])
1144 # just dest width
1145 elif encmode.startswith("dw="):
1146 destwid = decode_elwidth(encmode[3:])
1147 # just src width
1148 elif encmode.startswith("sw="):
1149 srcwid = decode_elwidth(encmode[3:])
1150 # element-strided LD/ST
1151 elif encmode == 'els':
1152 ldst_elstride = 1
1153 # in indexed mode, set sv_mode=0b01
1154 if is_ldst_idx:
1155 sv_mode = 0b01
1156 # saturation
1157 elif encmode == 'sats':
1158 assert sv_mode is None
1159 saturation = 1
1160 sv_mode = 0b10
1161 elif encmode == 'satu':
1162 assert sv_mode is None
1163 sv_mode = 0b10
1164 saturation = 0
1165 # predicate zeroing
1166 elif encmode == 'zz': # TODO, a lot more checking on legality
1167 dst_zero = 1 # NOT on cr_ops, that's RM[6]
1168 src_zero = 1
1169 elif encmode == 'sz':
1170 src_zero = 1
1171 elif encmode == 'dz':
1172 dst_zero = 1
1173 # failfirst
1174 elif encmode.startswith("ff="):
1175 assert sv_mode is None
1176 sv_mode = 0b01
1177 failfirst = decode_ffirst(encmode[3:])
1178 assert sea is False, "cannot use failfirst with signed-address"
1179 # predicate-result, interestingly same as fail-first
1180 elif encmode.startswith("pr="):
1181 assert sv_mode is None
1182 sv_mode = 0b11
1183 predresult = decode_ffirst(encmode[3:])
1184 # map-reduce mode, reverse-gear
1185 elif encmode == 'mrr':
1186 assert sv_mode is None
1187 sv_mode = 0b00
1188 mapreduce = True
1189 reverse_gear = True
1190 # map-reduce mode
1191 elif encmode == 'mr':
1192 assert sv_mode is None
1193 sv_mode = 0b00
1194 mapreduce = True
1195 elif encmode == 'crm': # CR on map-reduce
1196 assert sv_mode is None
1197 sv_mode = 0b00
1198 mapreduce_crm = True
1199 elif encmode == 'vli':
1200 assert sv_mode == 0b01 # only allow ff mode
1201 vli = True
1202 elif encmode == 'sea':
1203 assert is_ldst_idx
1204 sea = True
1205 assert failfirst is False, "cannot use ffirst+signed-address"
1206 elif is_bc:
1207 if encmode == 'all':
1208 svp64_rm.branch.ALL = 1
1209 elif encmode == 'snz':
1210 svp64_rm.branch.sz = 1
1211 svp64_rm.branch.SNZ = 1
1212 elif encmode == 'sl':
1213 svp64_rm.branch.SL = 1
1214 elif encmode == 'slu':
1215 svp64_rm.branch.SLu = 1
1216 elif encmode == 'lru':
1217 svp64_rm.branch.LRu = 1
1218 elif encmode == 'vs':
1219 svp64_rm.branch.VLS = 1
1220 elif encmode == 'vsi':
1221 svp64_rm.branch.VLS = 1
1222 svp64_rm.branch.vls.VLi = 1
1223 elif encmode == 'vsb':
1224 svp64_rm.branch.VLS = 1
1225 svp64_rm.branch.vls.VSb = 1
1226 elif encmode == 'vsbi':
1227 svp64_rm.branch.VLS = 1
1228 svp64_rm.branch.vls.VSb = 1
1229 svp64_rm.branch.vls.VLi = 1
1230 elif encmode == 'ctr':
1231 svp64_rm.branch.CTR = 1
1232 elif encmode == 'cti':
1233 svp64_rm.branch.CTR = 1
1234 svp64_rm.branch.ctr.CTi = 1
1235 else:
1236 raise AssertionError("unknown encmode %s" % encmode)
1237 else:
1238 raise AssertionError("unknown encmode %s" % encmode)
1239
1240 # sanity check if dz/zz used in branch-mode
1241 if is_bc and dst_zero:
1242 raise AssertionError("dz/zz not supported in branch, use 'sz'")
1243
1244 # check sea *after* all qualifiers are evaluated
1245 if sea:
1246 assert sv_mode in (None, 0b00, 0b01)
1247
1248 if ptype == '2P':
1249 # since m=xx takes precedence (overrides) sm=xx and dm=xx,
1250 # treat them as mutually exclusive
1251 if mask_m_specified:
1252 assert not has_smask,\
1253 "cannot have both source-mask and predicate mask"
1254 assert not has_pmask,\
1255 "cannot have both dest-mask and predicate mask"
1256 # since the default is INT predication (ALWAYS), if you
1257 # specify one CR mask, you must specify both, to avoid
1258 # mixing INT and CR reg types
1259 if has_pmask and pmmode == 1:
1260 assert has_smask, \
1261 "need explicit source-mask in CR twin predication"
1262 if has_smask and smmode == 1:
1263 assert has_pmask, \
1264 "need explicit dest-mask in CR twin predication"
1265 # sanity-check that 2Pred mask is same mode
1266 if has_pmask and has_smask:
1267 assert smmode == pmmode, \
1268 "predicate masks %s and %s must be same reg type" % \
1269 (pme, sme)
1270
1271 # sanity-check that twin-predication mask only specified in 2P mode
1272 if ptype == '1P':
1273 assert not has_smask, \
1274 "source-mask can only be specified on Twin-predicate ops"
1275 assert not has_pmask, \
1276 "dest-mask can only be specified on Twin-predicate ops"
1277
1278 # construct the mode field, doing sanity-checking along the way
1279 if src_zero:
1280 assert has_smask or mask_m_specified, \
1281 "src zeroing requires a source predicate"
1282 if dst_zero:
1283 assert has_pmask or mask_m_specified, \
1284 "dest zeroing requires a dest predicate"
1285
1286 # okaaay, so there are 4 different modes, here, which will be
1287 # partly-merged-in: is_ldst is merged in with "normal", but
1288 # is_bc is so different it's done separately. likewise is_cr
1289 # (when it is done). here are the maps:
1290
1291 # for "normal" arithmetic: https://libre-soc.org/openpower/sv/normal/
1292 """
1293 | 0-1 | 2 | 3 4 | description |
1294 | --- | --- |---------|-------------------------- |
1295 | 00 | 0 | dz sz | simple mode |
1296 | 00 | 1 | 0 RG | scalar reduce mode (mapreduce) |
1297 | 01 | inv | CR-bit | Rc=1: ffirst CR sel |
1298 | 01 | inv | VLi RC1 | Rc=0: ffirst z/nonz |
1299 | 10 | N | dz sz | sat mode: N=0/1 u/s |
1300 | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
1301 | 11 | inv | zz RC1 | Rc=0: pred-result z/nonz |
1302 """
1303
1304 # https://libre-soc.org/openpower/sv/ldst/
1305 # for LD/ST-immediate:
1306 """
1307 | 0-1 | 2 | 3 4 | description |
1308 | --- | --- |---------|--------------------------- |
1309 | 00 | 0 | zz els | normal mode |
1310 | 00 | 1 | / / | reserved |
1311 | 01 | inv | CR-bit | Rc=1: ffirst CR sel |
1312 | 01 | inv | els RC1 | Rc=0: ffirst z/nonz |
1313 | 10 | N | zz els | sat mode: N=0/1 u/s |
1314 | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
1315 | 11 | inv | els RC1 | Rc=0: pred-result z/nonz |
1316 """
1317
1318 # for LD/ST-indexed (RA+RB):
1319 """
1320 | 0-1 | 2 | 3 4 | description |
1321 | --- | --- |---------|----------------------------- |
1322 | 00 | SEA | dz sz | normal mode |
1323 | 01 | SEA | dz sz | strided (scalar only source) |
1324 | 10 | N | dz sz | sat mode: N=0/1 u/s |
1325 | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
1326 | 11 | inv | dz RC1 | Rc=0: pred-result z/nonz |
1327 """
1328
1329 # and leaving out branches and cr_ops for now because they're
1330 # under development
1331 """ TODO branches and cr_ops
1332 """
1333
1334 if is_bc:
1335 sv_mode = int(svp64_rm.mode[0, 1])
1336 if src_zero:
1337 svp64_rm.branch.sz = 1
1338
1339 else:
1340 ######################################
1341 # "element-strided" mode, ldst_idx
1342 if sv_mode == 0b01 and is_ldst_idx:
1343 mode |= src_zero << SVP64MODE.SZ # predicate zeroing
1344 mode |= dst_zero << SVP64MODE.DZ # predicate zeroing
1345 mode |= sea << SVP64MODE.SEA # el-strided
1346
1347 ######################################
1348 # "normal" mode
1349 elif sv_mode is None:
1350 mode |= src_zero << SVP64MODE.SZ # predicate zeroing
1351 mode |= dst_zero << SVP64MODE.DZ # predicate zeroing
1352 if is_ldst:
1353 # TODO: for now, LD/ST-indexed is ignored.
1354 mode |= ldst_elstride << SVP64MODE.ELS_NORMAL # el-strided
1355 else:
1356 # TODO, reduce and subvector mode
1357 # 00 1 dz CRM reduce mode (mapreduce), SUBVL=1
1358 # 00 1 SVM CRM subvector reduce mode, SUBVL>1
1359 pass
1360 sv_mode = 0b00
1361
1362 ######################################
1363 # "mapreduce" modes
1364 elif sv_mode == 0b00:
1365 mode |= (0b1 << SVP64MODE.REDUCE) # sets mapreduce
1366 assert dst_zero == 0, "dest-zero not allowed in mapreduce mode"
1367 if reverse_gear:
1368 mode |= (0b1 << SVP64MODE.RG) # sets Reverse-gear mode
1369 if mapreduce_crm:
1370 mode |= (0b1 << SVP64MODE.CRM) # sets CRM mode
1371 assert rc_mode, "CRM only allowed when Rc=1"
1372 # bit of weird encoding to jam zero-pred or SVM mode in.
1373 # SVM mode can be enabled only when SUBVL=2/3/4 (vec2/3/4)
1374 if subvl == 0:
1375 mode |= dst_zero << SVP64MODE.DZ # predicate zeroing
1376
1377 ######################################
1378 # "failfirst" modes
1379 elif sv_mode == 0b01:
1380 assert src_zero == 0, "dest-zero not allowed in failfirst mode"
1381 if failfirst == 'RC1':
1382 mode |= (0b1 << SVP64MODE.RC1) # sets RC1 mode
1383 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1384 assert rc_mode == False, "ffirst RC1 only ok when Rc=0"
1385 elif failfirst == '~RC1':
1386 mode |= (0b1 << SVP64MODE.RC1) # sets RC1 mode
1387 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1388 mode |= (0b1 << SVP64MODE.INV) # ... with inversion
1389 assert rc_mode == False, "ffirst RC1 only ok when Rc=0"
1390 else:
1391 assert dst_zero == 0, "dst-zero not allowed in ffirst BO"
1392 assert rc_mode, "ffirst BO only possible when Rc=1"
1393 mode |= (failfirst << SVP64MODE.BO_LSB) # set BO
1394
1395 ######################################
1396 # "saturation" modes
1397 elif sv_mode == 0b10:
1398 mode |= src_zero << SVP64MODE.SZ # predicate zeroing
1399 mode |= dst_zero << SVP64MODE.DZ # predicate zeroing
1400 mode |= (saturation << SVP64MODE.N) # signed/us saturation
1401
1402 ######################################
1403 # "predicate-result" modes. err... code-duplication from ffirst
1404 elif sv_mode == 0b11:
1405 assert src_zero == 0, "dest-zero not allowed in predresult mode"
1406 if predresult == 'RC1':
1407 mode |= (0b1 << SVP64MODE.RC1) # sets RC1 mode
1408 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1409 assert rc_mode == False, "pr-mode RC1 only ok when Rc=0"
1410 elif predresult == '~RC1':
1411 mode |= (0b1 << SVP64MODE.RC1) # sets RC1 mode
1412 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1413 mode |= (0b1 << SVP64MODE.INV) # ... with inversion
1414 assert rc_mode == False, "pr-mode RC1 only ok when Rc=0"
1415 else:
1416 assert dst_zero == 0, "dst-zero not allowed in pr-mode BO"
1417 assert rc_mode, "pr-mode BO only possible when Rc=1"
1418 mode |= (predresult << SVP64MODE.BO_LSB) # set BO
1419
1420 # whewww.... modes all done :)
1421 # now put into svp64_rm, but respect MSB0 order
1422 if sv_mode&1:
1423 mode |= (0b1<<SVP64MODE.MOD2_LSB)
1424 if sv_mode&2:
1425 mode |= (0b1<<SVP64MODE.MOD2_MSB)
1426
1427 if sea:
1428 mode |= (0b1 << SVP64MODE.SEA)
1429
1430 if not is_bc:
1431 svp64_rm.mode = mode # mode: bits 19-23
1432 if vli:
1433 svp64_rm.normal.ffrc0.VLi = 1
1434
1435 # put in predicate masks into svp64_rm
1436 if ptype == '2P':
1437 svp64_rm.smask = smask # source pred: bits 16-18
1438
1439 # put in elwidths unless bc
1440 svp64_rm.ewsrc = srcwid # srcwid: bits 6-7
1441 svp64_rm.elwidth = destwid # destwid: bits 4-5
1442
1443 svp64_rm.mmode = mmode # mask mode: bit 0
1444 svp64_rm.mask = pmask # 1-pred: bits 1-3
1445 svp64_rm.subvl = subvl # and subvl: bits 8-9
1446
1447 # nice debug printout. (and now for something completely different)
1448 # https://youtu.be/u0WOIwlXE9g?t=146
1449 svp64_rm_value = int(svp64_rm)
1450 log("svp64_rm", hex(svp64_rm_value), bin(svp64_rm_value))
1451 log(" mmode 0 :", bin(mmode))
1452 log(" pmask 1-3 :", bin(pmask))
1453 log(" dstwid 4-5 :", bin(destwid))
1454 log(" srcwid 6-7 :", bin(srcwid))
1455 log(" subvl 8-9 :", bin(subvl))
1456 log(" mode 19-23:", bin(svp64_rm.mode))
1457 offs = 2 if etype == 'EXTRA2' else 3 # 2 or 3 bits
1458 for idx, sv_extra in extras.items():
1459 if idx is None:
1460 continue
1461 if idx[0] == 'imm':
1462 continue
1463 srcdest, idx, duplicate = idx
1464 start = (10+idx*offs)
1465 end = start + offs-1
1466 log(" extra%d %2d-%2d:" % (idx, start, end),
1467 bin(sv_extra))
1468 if ptype == '2P':
1469 log(" smask 16-17:", bin(smask))
1470 log()
1471
1472 # update prefix PO and ID (aka PID)
1473 svp64_prefix.po = 0x1
1474 svp64_prefix.id = 0b11
1475
1476 # fiinally yield the svp64 prefix and the thingy. v3.0b opcode
1477 rc = '.' if rc_mode else ''
1478 yield ".long 0x%08x" % int(svp64_prefix)
1479 log(v30b_op, v30b_newfields)
1480
1481 v30b_op_rc = v30b_op
1482 if not v30b_op.endswith('.'):
1483 v30b_op_rc += rc
1484
1485 # svstep is weird
1486 # FIXME(lkcl): should sv.svstep be like svstep?
1487 if v30b_op_rc in ("svstep", "svstep."):
1488 # compensate for `SVi -= 1` in svstep()
1489 v30b_newfields[1] = str(int(v30b_newfields[1]) + 1)
1490
1491 custom_insn_hook = CUSTOM_INSNS.get(v30b_op_rc)
1492 if custom_insn_hook is not None:
1493 fields = tuple(map(to_number, v30b_newfields))
1494 insn_num = custom_insn_hook(fields)
1495 log(opcode, bin(insn_num))
1496 yield ".long 0x%X # %s" % (insn_num, insn)
1497 return
1498 # argh, sv.fmadds etc. need to be done manually
1499 elif v30b_op == 'ffmadds':
1500 opcode = 59 << (32-6) # bits 0..6 (MSB0)
1501 opcode |= int(v30b_newfields[0]) << (32-11) # FRT
1502 opcode |= int(v30b_newfields[1]) << (32-16) # FRA
1503 opcode |= int(v30b_newfields[2]) << (32-21) # FRB
1504 opcode |= int(v30b_newfields[3]) << (32-26) # FRC
1505 opcode |= 0b00101 << (32-31) # bits 26-30
1506 if rc:
1507 opcode |= 1 # Rc, bit 31.
1508 yield ".long 0x%x" % opcode
1509 # argh, sv.fdmadds need to be done manually
1510 elif v30b_op == 'fdmadds':
1511 opcode = 59 << (32-6) # bits 0..6 (MSB0)
1512 opcode |= int(v30b_newfields[0]) << (32-11) # FRT
1513 opcode |= int(v30b_newfields[1]) << (32-16) # FRA
1514 opcode |= int(v30b_newfields[2]) << (32-21) # FRB
1515 opcode |= int(v30b_newfields[3]) << (32-26) # FRC
1516 opcode |= 0b11011 << (32-31) # bits 26-30
1517 if rc:
1518 opcode |= 1 # Rc, bit 31.
1519 yield ".long 0x%x" % opcode
1520 # argh, sv.ffadds etc. need to be done manually
1521 elif v30b_op == 'ffadds':
1522 opcode = 59 << (32-6) # bits 0..6 (MSB0)
1523 opcode |= int(v30b_newfields[0]) << (32-11) # FRT
1524 opcode |= int(v30b_newfields[1]) << (32-16) # FRA
1525 opcode |= int(v30b_newfields[2]) << (32-21) # FRB
1526 opcode |= 0b1111100000 << (32-31) # bits 21-30
1527 if rc:
1528 opcode |= 1 # Rc, bit 31.
1529 yield ".long 0x%x" % opcode
1530 else:
1531 if not v30b_op.endswith('.'):
1532 v30b_op += rc
1533 yield "%s %s" % (v30b_op, ", ".join(v30b_newfields))
1534 for (name, span) in svp64_insn.traverse("SVP64"):
1535 value = svp64_insn.storage[span]
1536 log(name, f"{value.value:0{value.bits}b}", span)
1537 log("new v3.0B fields", v30b_op, v30b_newfields)
1538
1539 def translate(self, lst):
1540 for insn in lst:
1541 yield from self.translate_one(insn)
1542
1543
1544 def macro_subst(macros, txt):
1545 again = True
1546 log("subst", txt, macros)
1547 while again:
1548 again = False
1549 for macro, value in macros.items():
1550 if macro == txt:
1551 again = True
1552 replaced = txt.replace(macro, value)
1553 log("macro", txt, "replaced", replaced, macro, value)
1554 txt = replaced
1555 continue
1556 toreplace = '%s.s' % macro
1557 if toreplace == txt:
1558 again = True
1559 replaced = txt.replace(toreplace, "%s.s" % value)
1560 log("macro", txt, "replaced", replaced, toreplace, value)
1561 txt = replaced
1562 continue
1563 toreplace = '%s.v' % macro
1564 if toreplace == txt:
1565 again = True
1566 replaced = txt.replace(toreplace, "%s.v" % value)
1567 log("macro", txt, "replaced", replaced, toreplace, value)
1568 txt = replaced
1569 continue
1570 toreplace = '*%s' % macro
1571 if toreplace in txt:
1572 again = True
1573 replaced = txt.replace(toreplace, '*%s' % value)
1574 log("macro", txt, "replaced", replaced, toreplace, value)
1575 txt = replaced
1576 continue
1577 toreplace = '(%s)' % macro
1578 if toreplace in txt:
1579 again = True
1580 replaced = txt.replace(toreplace, '(%s)' % value)
1581 log("macro", txt, "replaced", replaced, toreplace, value)
1582 txt = replaced
1583 continue
1584 log(" processed", txt)
1585 return txt
1586
1587
1588 def get_ws(line):
1589 # find whitespace
1590 ws = ''
1591 while line:
1592 if not line[0].isspace():
1593 break
1594 ws += line[0]
1595 line = line[1:]
1596 return ws, line
1597
1598
1599 def asm_process():
1600 # get an input file and an output file
1601 args = sys.argv[1:]
1602 if len(args) == 0:
1603 infile = sys.stdin
1604 outfile = sys.stdout
1605 # read the whole lot in advance in case of in-place
1606 lines = list(infile.readlines())
1607 elif len(args) != 2:
1608 print("pysvp64asm [infile | -] [outfile | -]", file=sys.stderr)
1609 exit(0)
1610 else:
1611 if args[0] == '--':
1612 infile = sys.stdin
1613 else:
1614 infile = open(args[0], "r")
1615 # read the whole lot in advance in case of in-place overwrite
1616 lines = list(infile.readlines())
1617
1618 if args[1] == '--':
1619 outfile = sys.stdout
1620 else:
1621 outfile = open(args[1], "w")
1622
1623 # read the line, look for custom insn, process it
1624 macros = {} # macros which start ".set"
1625 isa = SVP64Asm([])
1626 for line in lines:
1627 op = line.split("#")[0].strip()
1628 # identify macros
1629 if op.startswith(".set"):
1630 macro = op[4:].split(",")
1631 (macro, value) = map(str.strip, macro)
1632 macros[macro] = value
1633 if not op.startswith('sv.') and not op.startswith(tuple(CUSTOM_INSNS)):
1634 outfile.write(line)
1635 continue
1636
1637 (ws, line) = get_ws(line)
1638 lst = isa.translate_one(op, macros)
1639 lst = '; '.join(lst)
1640 outfile.write("%s%s # %s\n" % (ws, lst, op))
1641
1642
1643 if __name__ == '__main__':
1644 lst = ['slw 3, 1, 4',
1645 'extsw 5, 3',
1646 'sv.extsw 5, 3',
1647 'sv.cmpi 5, 1, 3, 2',
1648 'sv.setb 5, 31',
1649 'sv.isel 64.v, 3, 2, 65.v',
1650 'sv.setb/dm=r3/sm=1<<r3 5, 31',
1651 'sv.setb/m=r3 5, 31',
1652 'sv.setb/vec2 5, 31',
1653 'sv.setb/sw=8/ew=16 5, 31',
1654 'sv.extsw./ff=eq 5, 31',
1655 'sv.extsw./satu/sz/dz/sm=r3/dm=r3 5, 31',
1656 'sv.extsw./pr=eq 5.v, 31',
1657 'sv.add. 5.v, 2.v, 1.v',
1658 'sv.add./m=r3 5.v, 2.v, 1.v',
1659 ]
1660 lst += [
1661 'sv.stw 5.v, 4(1.v)',
1662 'sv.ld 5.v, 4(1.v)',
1663 'setvl. 2, 3, 4, 0, 1, 1',
1664 'sv.setvl. 2, 3, 4, 0, 1, 1',
1665 ]
1666 lst = [
1667 "sv.stfsu 0.v, 16(4.v)",
1668 ]
1669 lst = [
1670 "sv.stfsu/els 0.v, 16(4)",
1671 ]
1672 lst = [
1673 'sv.add./mr 5.v, 2.v, 1.v',
1674 ]
1675 macros = {'win2': '50', 'win': '60'}
1676 lst = [
1677 'sv.addi win2.v, win.v, -1',
1678 'sv.add./mrr 5.v, 2.v, 1.v',
1679 #'sv.lhzsh 5.v, 11(9.v), 15',
1680 #'sv.lwzsh 5.v, 11(9.v), 15',
1681 'sv.ffmadds 6.v, 2.v, 4.v, 6.v',
1682 ]
1683 lst = [
1684 #'sv.fmadds 0.v, 8.v, 16.v, 4.v',
1685 #'sv.ffadds 0.v, 8.v, 4.v',
1686 'svremap 11, 0, 1, 2, 3, 2, 1',
1687 'svshape 8, 1, 1, 1, 0',
1688 'svshape 8, 1, 1, 1, 1',
1689 ]
1690 lst = [
1691 #'sv.lfssh 4.v, 11(8.v), 15',
1692 #'sv.lwzsh 4.v, 11(8.v), 15',
1693 #'sv.svstep. 2.v, 4, 0',
1694 #'sv.fcfids. 48.v, 64.v',
1695 'sv.fcoss. 80.v, 0.v',
1696 'sv.fcoss. 20.v, 0.v',
1697 ]
1698 lst = [
1699 'sv.bc/all 3,12,192',
1700 'sv.bclr/vsbi 3,81.v,192',
1701 'sv.ld 5.v, 4(1.v)',
1702 'sv.svstep. 2.v, 4, 0',
1703 ]
1704 lst = [
1705 'maxs 3,12,5',
1706 'maxs. 3,12,5',
1707 'avgadd 3,12,5',
1708 'absdu 3,12,5',
1709 'absds 3,12,5',
1710 'absdacu 3,12,5',
1711 'absdacs 3,12,5',
1712 'cprop 3,12,5',
1713 'svindex 0,0,1,0,0,0,0',
1714 ]
1715 lst = [
1716 'sv.svstep./m=r3 2.v, 4, 0',
1717 'ternlogi 0,0,0,0x5',
1718 'fmvis 5,65535',
1719 'fmvis 5,1',
1720 'fmvis 5,2',
1721 'fmvis 5,4',
1722 'fmvis 5,8',
1723 'fmvis 5,16',
1724 'fmvis 5,32',
1725 'fmvis 5,64',
1726 'fmvis 5,32768',
1727 ]
1728 lst = [
1729 'sv.andi. *80, *80, 1',
1730 'sv.ffmadds. 6.v, 2.v, 4.v, 6.v', # incorrectly inserted 32-bit op
1731 'sv.ffmadds 6.v, 2.v, 4.v, 6.v', # correctly converted to .long
1732 'svshape2 8, 1, 31, 7, 1, 1',
1733 'sv.ld 5.v, 4(1.v)',
1734 'sv.stw 5.v, 4(1.v)',
1735 'sv.bc/all 3,12,192',
1736 'pcdec. 0,0,0,0,0',
1737 ]
1738 isa = SVP64Asm(lst, macros=macros)
1739 log("list:\n", "\n\t".join(list(isa)))
1740 # running svp64.py is designed to test hard-coded lists
1741 # (above) - which strictly speaking should all be unit tests.
1742 # if you need to actually do assembler translation at the
1743 # commandline use "pysvp64asm" - see setup.py
1744 # XXX NO. asm_process()