power_insn: fix immediate operands
[openpower-isa.git] / src / openpower / sv / sv_binutils.py
1 import argparse as _argparse
2 import dataclasses as _dataclasses
3 import enum as _enum
4
5 import os as _os
6 import sys as _sys
7
8 _sys.path.append(_os.path.dirname(_os.path.realpath(__file__)) + "/../../")
9
10 from openpower.decoder.power_enums import (
11 In1Sel as _In1Sel,
12 In2Sel as _In2Sel,
13 In3Sel as _In3Sel,
14 OutSel as _OutSel,
15 CRInSel as _CRInSel,
16 CROutSel as _CROutSel,
17 SVPtype as _SVPtype,
18 SVEtype as _SVEtype,
19 SVExtra as _SVExtra,
20 Function as _Function,
21 find_wiki_dir as _find_wiki_dir,
22 )
23 from openpower.consts import SVP64MODE as _SVP64MODE
24 from openpower.decoder.power_insn import Database as _Database
25 from openpower.decoder.power_insn import SVP64Instruction as _SVP64Instruction
26
27
28 DISCLAIMER = """\
29 /* {path} -- {desc}
30 Copyright (C) 2022 Free Software Foundation, Inc.
31 Written by Dmitry Selyutin (ghostmansd).
32 Sponsored by NLnet and NGI POINTER under EU Grants 871528 and 957073.
33
34 This file is part of the GNU opcodes library.
35
36 This library is free software; you can redistribute it and/or modify
37 it under the terms of the GNU General Public License as published by
38 the Free Software Foundation; either version 3, or (at your option)
39 any later version.
40
41 It is distributed in the hope that it will be useful, but WITHOUT
42 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
43 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
44 License for more details.
45
46 You should have received a copy of the GNU General Public License
47 along with this file; see the file COPYING. If not, write to the
48 Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
49 MA 02110-1301, USA. */\
50 """
51
52
53 def indent(strings):
54 return map(lambda string: (" " + string), strings)
55
56
57 class ObjectMeta(type):
58 def __new__(metacls, clsname, bases, ns,
59 c_typedef="void", **kwargs):
60 if c_typedef == "void":
61 for base in bases:
62 if (hasattr(base, "c_typedef") and
63 (base.c_typedef != "void")):
64 c_typedef = base.c_typedef
65 break
66
67 ns.setdefault("c_typedef", c_typedef)
68 ns.update(kwargs)
69
70 return super().__new__(metacls, clsname, bases, ns)
71
72
73 class Object(metaclass=ObjectMeta):
74 @classmethod
75 def c_decl(cls):
76 yield from ()
77
78 @classmethod
79 def c_var(cls, name, prefix="", suffix=""):
80 return f"{prefix}{cls.c_typedef} {name}{suffix}"
81
82 def c_value(self, *, prefix="", suffix="", **kwargs):
83 yield from ()
84
85
86 class ArrayMeta(ObjectMeta):
87 def __new__(metacls, clsname, bases, ns,
88 c_base, c_size, **kwargs):
89 if c_size is Ellipsis:
90 clsname = f"{clsname}[]"
91 else:
92 clsname = f"{clsname}[{c_size}]"
93
94 return super().__new__(metacls, clsname, bases, ns,
95 c_typedef=c_base.c_typedef, c_base=c_base, c_size=c_size, **kwargs)
96
97 def __getitem__(cls, key):
98 (c_base, c_size) = key
99 return cls.__class__(cls.__name__, (cls,), {},
100 c_base=c_base, c_size=c_size)
101
102
103 class Array(Object, tuple, metaclass=ArrayMeta,
104 c_base=Object, c_size=...):
105 @classmethod
106 def c_decl(cls):
107 if cls.c_size is Ellipsis:
108 size = ""
109 else:
110 size = f"{len(cls)}"
111 yield f"{cls.c_base.c_typedef}[{size}]"
112
113 @classmethod
114 def c_var(cls, name, prefix="", suffix=""):
115 if cls.c_size is Ellipsis:
116 size = ""
117 else:
118 size = f"{len(cls)}"
119 return f"{prefix}{cls.c_base.c_typedef} {name}[{size}]{suffix}"
120
121 def c_value(self, *, prefix="", suffix="", **kwargs):
122 yield f"{prefix}{{"
123 for item in self:
124 yield from indent(item.c_value(suffix=","))
125 yield f"}}{suffix}"
126
127
128 class Void(Object, c_typedef="void"):
129 def c_var(cls, name, prefix="", suffix=""):
130 raise NotImplementedError
131
132
133 class EnumMeta(_enum.EnumMeta, ObjectMeta):
134 def __call__(cls, clsname, entries,
135 c_tag=None, c_typedef=None, exclude=None):
136 if exclude is None:
137 exclude = frozenset()
138 if isinstance(entries, type) and issubclass(entries, _enum.Enum):
139 # Use __members__, not __iter__, otherwise aliases are lost.
140 entries = dict(entries.__members__)
141 if isinstance(entries, dict):
142 entries = tuple(entries.items())
143 entries = ((key, value) for (key, value) in entries if key not in exclude)
144
145 if c_tag is None:
146 c_tag = f"svp64_{clsname.lower()}"
147 if c_typedef is None:
148 c_typedef = f"enum {c_tag}"
149
150 base = ObjectMeta(cls.__name__, (), {},
151 c_tag=c_tag, c_typedef=c_typedef)
152
153 return super().__call__(value=clsname, names=entries, type=base)
154
155
156 class Enum(Object, _enum.Enum, metaclass=EnumMeta):
157 @property
158 def c_name(self):
159 return f"{self.c_tag.upper()}_{self.name.upper()}"
160
161 @classmethod
162 def c_decl(cls):
163 yield f"{cls.c_typedef} {{"
164 for item in cls:
165 yield from indent(item.c_value(suffix=","))
166 yield f"}};"
167
168 def c_value(self, *, prefix="", suffix="", **kwargs):
169 yield f"{prefix}{self.c_name}{suffix}"
170
171 @classmethod
172 def c_var(cls, name, prefix="", suffix=""):
173 return f"{prefix}{cls.c_typedef} {name}{suffix}"
174
175
176 In1Sel = Enum("In1Sel", _In1Sel, c_tag="svp64_in1_sel")
177 In2Sel = Enum("In2Sel", _In2Sel, c_tag="svp64_in2_sel")
178 In3Sel = Enum("In3Sel", _In3Sel, c_tag="svp64_in3_sel")
179 OutSel = Enum("OutSel", _OutSel, c_tag="svp64_out_sel")
180 CRInSel = Enum("CRInSel", _CRInSel, c_tag="svp64_cr_in_sel")
181 CROutSel = Enum("CROutSel", _CROutSel, c_tag="svp64_cr_out_sel")
182 PType = Enum("PType", _SVPtype, c_tag="svp64_ptype")
183 EType = Enum("EType", _SVEtype, c_tag="svp64_etype", exclude="NONE")
184 Extra = Enum("Extra", _SVExtra, c_tag="svp64_extra", exclude="Idx_1_2")
185 Function = Enum("Function", _Function, c_tag="svp64_function")
186
187
188 class Constant(_enum.Enum, metaclass=EnumMeta):
189 @classmethod
190 def c_decl(cls):
191 yield f"/* {cls.c_tag.upper()} constants */"
192 # Use __members__, not __iter__, otherwise aliases are lost.
193 for (key, item) in cls.__members__.items():
194 key = f"{cls.c_tag.upper()}_{key.upper()}"
195 value = f"0x{item.value:08x}U"
196 yield f"#define {key} {value}"
197
198 def c_value(self, *, prefix="", suffix="", **kwargs):
199 yield f"{prefix}{self.c_tag.upper()}_{self.c_name.upper()}{suffix}"
200
201
202 Mode = Constant("Mode", _SVP64MODE)
203
204
205 class StructMeta(ObjectMeta):
206 def __new__(metacls, clsname, bases, ns,
207 c_tag=None, c_typedef=None):
208
209 if c_tag is None:
210 c_tag = f"svp64_{clsname.lower()}"
211 if c_typedef is None:
212 c_typedef = f"struct {c_tag}"
213
214 return super().__new__(metacls, clsname, bases, ns,
215 c_typedef=c_typedef, c_tag=c_tag)
216
217
218 @_dataclasses.dataclass(eq=True, frozen=True)
219 class Struct(Object, metaclass=StructMeta):
220 @classmethod
221 def c_decl(cls):
222 def transform(field):
223 return field.type.c_var(name=f"{field.name}", suffix=";")
224
225 yield f"{cls.c_typedef} {{"
226 yield from indent(map(transform, _dataclasses.fields(cls)))
227 yield f"}};"
228
229 def c_value(self, *, prefix="", suffix="", **kwargs):
230 yield f"{prefix}{{"
231 for field in _dataclasses.fields(self):
232 name = field.name
233 attr = getattr(self, name)
234 yield from indent(attr.c_value(prefix=f".{name} = ", suffix=","))
235 yield f"}}{suffix}"
236
237
238 class Integer(Object, str):
239 def c_value(self, *, prefix="", suffix="", **kwargs):
240 yield f"{prefix}{self}{suffix}"
241
242
243 class Byte(Integer, c_typedef="uint8_t"):
244 pass
245
246
247 class Size(Integer, c_typedef="size_t"):
248 pass
249
250
251 class UInt32(Integer, c_typedef="uint32_t"):
252 pass
253
254
255 class UInt64(Integer, c_typedef="uint64_t"):
256 pass
257
258
259 @_dataclasses.dataclass(eq=True, frozen=True)
260 class Instruction(Struct, c_tag="svp64_insn"):
261 value: UInt64
262
263 @classmethod
264 def c_decl(cls):
265 def mangle(path, action):
266 if path.endswith("]"):
267 path = path[:-1]
268 for symbol in (".", "[", "]"):
269 path = path.replace(symbol, "_")
270 if path != "":
271 return f"{cls.c_tag}_{action}_{path}"
272 else:
273 return f"{cls.c_tag}_{action}"
274
275 def getter(path, field):
276 yield "static inline uint64_t"
277 yield f"{mangle(path, 'get')}(const {cls.c_typedef} *insn)"
278 yield "{"
279 yield from indent(["uint64_t value = insn->value;"])
280 yield from indent(["return ("])
281 actions = []
282 for (dst, src) in enumerate(reversed(field)):
283 src = (64 - (src + 1))
284 dst = f"UINT64_C({dst})"
285 src = f"UINT64_C({src})"
286 action = f"(((value >> {src}) & UINT64_C(1)) << {dst})"
287 actions.append(action)
288 for action in indent(indent(actions[:-1])):
289 yield f"{action} |"
290 yield from indent(indent([f"{actions[-1]}"]))
291 yield from indent([");"])
292 yield "}"
293 yield ""
294
295 def setter(path, field):
296 mask = ((2 ** 64) - 1)
297 for bit in field:
298 mask &= ~(1 << (64 - (bit + 1)))
299 action = mangle(path, "set")
300 yield "static inline void"
301 yield f"{mangle(path, 'set')}({cls.c_typedef} *insn, uint64_t value)"
302 yield "{"
303 yield from indent([f"insn->value &= UINT64_C(0x{mask:016x});"])
304 actions = []
305 for (src, dst) in enumerate(reversed(field)):
306 dst = (64 - (dst + 1))
307 dst = f"UINT64_C({dst})"
308 src = f"UINT64_C({src})"
309 action = f"(((value >> {src}) & UINT64_C(1)) << {dst})"
310 actions.append(action)
311 yield from indent(["insn->value |= ("])
312 for action in indent(indent(actions[:-1])):
313 yield f"{action} |"
314 yield from indent(indent([f"{actions[-1]}"]))
315 yield from indent([");"])
316 yield "}"
317 yield ""
318
319 yield from super().c_decl()
320 yield ""
321 for (path, field) in _SVP64Instruction.traverse():
322 yield from getter(path, field)
323 yield from setter(path, field)
324
325
326 class Name(Object, str, c_typedef="const char *"):
327 def __repr__(self):
328 escaped = self.replace("\"", "\\\"")
329 return f"\"{escaped}\""
330
331 def c_value(self, *, prefix="", suffix="", **kwargs):
332 yield f"{prefix}{self!r}{suffix}"
333
334 @classmethod
335 def c_var(cls, name, prefix="", suffix=""):
336 return f"{prefix}const char *{name}{suffix}"
337
338
339 @_dataclasses.dataclass(eq=True, frozen=True)
340 class Opcode(Struct):
341 class Value(UInt32):
342 def __new__(cls, value):
343 if isinstance(value, int):
344 value = f"0x{value:08x}"
345 return super().__new__(cls, value)
346
347 class Mask(UInt32):
348 def __new__(cls, value):
349 if isinstance(value, int):
350 value = f"0x{value:08x}"
351 return super().__new__(cls, value)
352
353 value: Value
354 mask: Mask
355
356
357 @_dataclasses.dataclass(eq=True, frozen=True)
358 class Desc(Struct):
359 function: Function
360 in1: In1Sel
361 in2: In2Sel
362 in3: In3Sel
363 out: OutSel
364 out2: OutSel
365 cr_in: CRInSel
366 cr_out: CROutSel
367 ptype: PType
368 etype: EType
369 extra_idx_in1: Extra
370 extra_idx_in2: Extra
371 extra_idx_in3: Extra
372 extra_idx_out: Extra
373 extra_idx_out2: Extra
374 extra_idx_cr_in: Extra
375 extra_idx_cr_out: Extra
376
377 @classmethod
378 def c_decl(cls):
379 bits_all = 0
380 yield f"struct svp64_desc {{"
381 for field in _dataclasses.fields(cls):
382 bits = len(field.type).bit_length()
383 yield from indent([f"uint64_t {field.name} : {bits};"])
384 bits_all += bits
385 bits_rsvd = (64 - (bits_all % 64))
386 if bits_rsvd:
387 yield from indent([f"uint64_t : {bits_rsvd};"])
388 yield f"}};"
389
390
391 @_dataclasses.dataclass(eq=True, frozen=True)
392 class Record(Struct):
393 name: Name
394 opcode: Opcode
395 desc: Desc
396
397 def __lt__(self, other):
398 if not isinstance(other, self.__class__):
399 return NotImplemented
400
401 return self.name < other.name
402
403
404 class Codegen(_enum.Enum):
405 PPC_SVP64_GEN_H = "include/opcode/ppc-svp64-gen.h"
406 PPC_SVP64_OPC_GEN_C = "opcodes/ppc-svp64-opc-gen.c"
407
408 def __str__(self):
409 return self.value
410
411 def generate(self, records):
412 def ppc_svp64_h(records, num_records):
413 disclaimer = DISCLAIMER.format(path=str(self),
414 desc="Header file for PowerPC opcode table (SVP64 extensions)")
415 yield from disclaimer.splitlines()
416 yield ""
417
418 yield f"#ifndef {self.name}"
419 yield f"#define {self.name}"
420 yield ""
421
422 yield "#include <stdint.h>"
423 yield ""
424
425 yield "#ifdef __cplusplus"
426 yield "extern \"C\" {"
427 yield "#endif"
428 yield ""
429
430 enums = (
431 In1Sel, In2Sel, In3Sel, OutSel,
432 CRInSel, CROutSel,
433 PType, EType, Extra,
434 Mode, Function,
435 )
436 for enum in enums:
437 yield from enum.c_decl()
438 yield ""
439
440 for cls in (Instruction, Desc, Opcode, Record):
441 yield from cls.c_decl()
442 yield ""
443
444 yield records.c_var("svp64_records",
445 prefix="extern const ", suffix=";")
446 yield num_records.c_var("svp64_num_records",
447 prefix="extern const ", suffix=";")
448 yield ""
449
450 yield "extern const struct powerpc_pd_reg svp64_regs[];"
451 yield Size.c_var("svp64_num_regs", prefix="extern const ", suffix=";")
452 yield ""
453
454 yield "#ifdef __cplusplus"
455 yield "}"
456 yield "#endif"
457 yield ""
458
459 yield f"#endif /* {self.name} */"
460
461 def ppc_svp64_opc_c(records, num_records):
462 disclaimer = DISCLAIMER.format(path=str(self),
463 desc="PowerPC opcode list (SVP64 extensions)")
464 yield from disclaimer.splitlines()
465 yield ""
466
467 yield "#include \"opcode/ppc-svp64.h\""
468 yield ""
469
470 def opindex(enum, name, table):
471 sep = (max(map(len, list(table.values()) + ["UNUSED"])) + 1)
472 c_tag = f"svp64_{enum.__name__.lower()}"
473 yield "static inline ppc_opindex_t"
474 yield f"svp64_desc_{name}_opindex(const struct svp64_desc *desc)"
475 yield "{"
476 yield from indent(["static const ppc_opindex_t table[] = {"])
477 for key in enum:
478 value = table.get(key, "UNUSED")
479 yield from indent(indent([f"{value:{sep}}, /* {key.c_name} */"]))
480 yield from indent(["};"])
481 yield ""
482 yield from indent([f"return table[desc->{name}];"])
483 yield "}"
484 yield ""
485
486 yield from opindex(In1Sel, "in1", {
487 In1Sel.RA: "RA",
488 In1Sel.RA_OR_ZERO: "RA0",
489 In1Sel.SPR: "SPR",
490 In1Sel.RS: "RS",
491 In1Sel.FRA: "FRA",
492 In1Sel.FRS: "FRS",
493 })
494 yield from opindex(In2Sel, "in2", {
495 In2Sel.RB: "RB",
496 In2Sel.SPR: "SPR",
497 In2Sel.RS: "RS",
498 In2Sel.FRB: "FRB",
499 })
500 yield from opindex(In3Sel, "in3", {
501 In3Sel.RS: "RS",
502 In3Sel.RB: "RB",
503 In3Sel.FRS: "FRS",
504 In3Sel.FRC: "FRC",
505 In3Sel.RC: "RC",
506 In3Sel.RT: "RT",
507 })
508 for name in ("out", "out2"):
509 yield from opindex(OutSel, name, {
510 OutSel.RT: "RT",
511 OutSel.RA: "RA",
512 OutSel.SPR: "SPR",
513 OutSel.RT_OR_ZERO: "RT",
514 OutSel.FRT: "FRT",
515 OutSel.FRS: "FRS",
516 })
517 yield from opindex(CRInSel, "cr_in", {
518 CRInSel.BI: "BI",
519 CRInSel.BFA: "BFA",
520 CRInSel.BC: "BC",
521 CRInSel.WHOLE_REG: "FXM",
522 })
523 yield from opindex(CROutSel, "cr_out", {
524 CROutSel.BF: "BF",
525 CROutSel.BT: "BT",
526 CROutSel.WHOLE_REG: "FXM",
527 })
528
529 yield records.c_var("svp64_records",
530 prefix="const ", suffix=" = \\")
531 yield from records.c_value(prefix="", suffix=";")
532 yield ""
533 yield num_records.c_var("svp64_num_records",
534 prefix="const ", suffix=" = \\")
535 yield from indent(num_records.c_value(suffix=";"))
536 yield ""
537
538 yield "const struct powerpc_pd_reg svp64_regs[] = {"
539 regs = {}
540 for (category, count, flags) in sorted((
541 ("r", 128, "PPC_OPERAND_GPR"),
542 ("f", 128, "PPC_OPERAND_FPR"),
543 ("cr", 128, "PPC_OPERAND_CR_REG"),
544 )):
545 for index in range(count):
546 regs[f"{category}{index}"] = (index, flags)
547 regs[f"{category}.{index}"] = (index, flags)
548 for (name, (index, flags)) in sorted(regs.items()):
549 yield from indent([f"{{\"{name}\", {index}, {flags}}},"])
550 yield "};"
551 yield ""
552
553 num_regs = Size("(sizeof (svp64_regs) / sizeof (svp64_regs[0]))")
554 yield Size.c_var("svp64_num_regs",
555 prefix="const ", suffix=" = \\")
556 yield from indent(num_regs.c_value(suffix=";"))
557
558 records = Array[Record, ...](records)
559 num_records = Size("(sizeof (svp64_records) / sizeof (svp64_records[0]))")
560
561 yield from {
562 Codegen.PPC_SVP64_GEN_H: ppc_svp64_h,
563 Codegen.PPC_SVP64_OPC_GEN_C: ppc_svp64_opc_c,
564 }[self](records, num_records)
565
566
567 def records(db):
568 fields = {field.name:field.type for field in _dataclasses.fields(Desc)}
569
570 for insn in filter(lambda insn: insn.svp64 is not None, db):
571 desc = {}
572
573 for (key, cls) in fields.items():
574 value = getattr(insn, key)
575
576 if (((cls is EType) and (value is _SVEtype.NONE)) or
577 ((cls is Extra) and (value is _SVExtra.Idx_1_2))):
578 desc = None
579 break
580
581 if issubclass(cls, _enum.Enum):
582 value = cls[value.name]
583 else:
584 value = cls(value)
585 desc[key] = value
586
587 if desc is None:
588 continue
589
590 name = Name(f"sv.{insn.name}")
591 value = Opcode.Value(insn.opcode.value)
592 mask = Opcode.Mask(insn.opcode.mask)
593 opcode = Opcode(value=value, mask=mask)
594 desc = Desc(**desc)
595
596 yield Record(name=name, opcode=opcode, desc=desc)
597
598
599 def main(codegen):
600 db = _Database(_find_wiki_dir())
601 for line in codegen.generate(records(db)):
602 print(line)
603
604
605 if __name__ == "__main__":
606 parser = _argparse.ArgumentParser()
607 parser.add_argument("codegen",
608 type=Codegen, choices=Codegen,
609 help="code generator")
610
611 args = vars(parser.parse_args())
612 main(**args)