sv_binutils: use stdin as input stream
[openpower-isa.git] / src / openpower / sv / sv_binutils.py
1 import abc as _abc
2 import argparse as _argparse
3 import codecs as _codecs
4 import dataclasses as _dataclasses
5 import enum as _enum
6 import pathlib as _pathlib
7 import re as _re
8 import sys as _sys
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 )
21
22
23 def indent(strings):
24 return map(lambda string: (" " + string), strings)
25
26
27 class Field:
28 @classmethod
29 @_abc.abstractmethod
30 def c_decl(self, name):
31 pass
32
33 @_abc.abstractmethod
34 def c_value(self, prefix="", suffix=""):
35 pass
36
37 @classmethod
38 @_abc.abstractmethod
39 def c_var(self, name):
40 pass
41
42
43 class Enum(Field, _enum.Enum):
44 @classmethod
45 def c_decl(cls):
46 c_tag = f"svp64_{cls.__name__.lower()}"
47 yield f"enum {c_tag} {{"
48 for item in cls:
49 yield from indent(item.c_value(suffix=","))
50 yield f"}};"
51
52 def c_value(self, prefix="", suffix=""):
53 c_tag = f"svp64_{self.__class__.__name__.lower()}"
54 yield f"{prefix}{c_tag.upper()}_{self.name.upper()}{suffix}"
55
56 @classmethod
57 def c_var(cls, name):
58 c_tag = f"svp64_{cls.__name__.lower()}"
59 yield f"enum {c_tag} {name};"
60
61
62 # Python forbids inheriting from enum unless it's empty.
63 In1Sel = Enum("In1Sel", {item.name:item.value for item in _In1Sel})
64 In2Sel = Enum("In2Sel", {item.name:item.value for item in _In2Sel})
65 In3Sel = Enum("In3Sel", {item.name:item.value for item in _In3Sel})
66 OutSel = Enum("OutSel", {item.name:item.value for item in _OutSel})
67 CRInSel = Enum("CRInSel", {item.name:item.value for item in _CRInSel})
68 CROutSel = Enum("CROutSel", {item.name:item.value for item in _CROutSel})
69 SVPType = Enum("SVPType", {item.name:item.value for item in _SVPtype})
70 SVEType = Enum("SVEType", {item.name:item.value for item in _SVEtype})
71 SVEXTRA = Enum("SVEXTRA", {item.name:item.value for item in _SVEXTRA})
72
73
74 class Opcode(Field, str):
75 def c_value(self, prefix="", suffix=""):
76 yield f"{prefix}\"{self}\"{suffix}"
77
78 @classmethod
79 def c_var(cls, name):
80 yield f"const char *{name};"
81
82
83 class Name(Field, str):
84 def __repr__(self):
85 escaped = self.replace("\"", "\\\"")
86 return f"\"{escaped}\""
87
88 def c_value(self, prefix="", suffix=""):
89 yield f"{prefix}{self!r}{suffix}"
90
91 @classmethod
92 def c_var(cls, name):
93 yield f"const char *{name};"
94
95
96 @_dataclasses.dataclass(eq=True, frozen=True)
97 class Entry:
98 name: Name
99 opcode: Opcode
100 in1: In1Sel
101 in2: In2Sel
102 in3: In3Sel
103 out: OutSel
104 out2: OutSel
105 cr_in: CRInSel
106 cr_out: CROutSel
107 ptype: SVPType
108 etype: SVEType
109 sv_in1: SVEXTRA
110 sv_in2: SVEXTRA
111 sv_in3: SVEXTRA
112 sv_out: SVEXTRA
113 sv_out2: SVEXTRA
114 sv_cr_in: SVEXTRA
115 sv_cr_out: SVEXTRA
116
117 @classmethod
118 def c_decl(cls):
119 yield f"struct svp64_entry {{"
120 for field in _dataclasses.fields(cls):
121 if issubclass(field.type, Enum):
122 bits = len(field.type).bit_length()
123 yield from indent([f"uint64_t {field.name} : {bits};"])
124 else:
125 yield from indent(field.type.c_var(name=field.name))
126 yield f"}};"
127
128 def c_value(self, prefix="", suffix=""):
129 yield f"{prefix}{{"
130 for field in _dataclasses.fields(self):
131 name = field.name
132 attr = getattr(self, name)
133 yield from indent(attr.c_value(prefix=f".{name} = ", suffix=","))
134 yield f"}}{suffix}"
135
136 @classmethod
137 def c_var(cls, name):
138 yield f"struct svp64_entry {name};"
139
140
141 def regex_enum(enum):
142 assert issubclass(enum, _enum.Enum)
143 return "|".join(item.name for item in enum)
144
145
146 PATTERN_VHDL_BINARY = r"(?:2#[01]+#)"
147 PATTERN_DECIMAL = r"(?:[0-9]+)"
148 PATTERN_PARTIAL_BINARY = r"(?:[01-]+)"
149
150 # Examples of the entries to be caught by the pattern below:
151 # 2 => (P2, EXTRA3, RA_OR_ZERO, NONE, NONE, RT, NONE, NONE, NONE, Idx1, NONE, NONE, Idx0, NONE, NONE, NONE), -- lwz
152 # -----10110 => (P2, EXTRA3, NONE, FRB, NONE, FRT, NONE, NONE, CR1, NONE, Idx1, NONE, Idx0, NONE, NONE, Idx0), -- fsqrts
153 # 2#0000000000# => (P2, EXTRA3, NONE, NONE, NONE, NONE, NONE, BFA, BF, NONE, NONE, NONE, NONE, NONE, Idx1, Idx0), -- mcrf
154 PATTERN = "".join((
155 r"^\s*",
156 rf"(?P<opcode>{PATTERN_VHDL_BINARY}|{PATTERN_DECIMAL}|{PATTERN_PARTIAL_BINARY})",
157 r"\s?=>\s?",
158 r"\(",
159 r",\s".join((
160 rf"(?P<ptype>{regex_enum(_SVPtype)})",
161 rf"(?P<etype>{regex_enum(_SVEtype)})",
162 rf"(?P<in1>{regex_enum(_In1Sel)})",
163 rf"(?P<in2>{regex_enum(_In2Sel)})",
164 rf"(?P<in3>{regex_enum(_In3Sel)})",
165 rf"(?P<out>{regex_enum(_OutSel)})",
166 rf"(?P<out2>{regex_enum(_OutSel)})",
167 rf"(?P<cr_in>{regex_enum(_CRInSel)})",
168 rf"(?P<cr_out>{regex_enum(_CROutSel)})",
169 rf"(?P<sv_in1>{regex_enum(_SVEXTRA)})",
170 rf"(?P<sv_in2>{regex_enum(_SVEXTRA)})",
171 rf"(?P<sv_in3>{regex_enum(_SVEXTRA)})",
172 rf"(?P<sv_out>{regex_enum(_SVEXTRA)})",
173 rf"(?P<sv_out2>{regex_enum(_SVEXTRA)})",
174 rf"(?P<sv_cr_in>{regex_enum(_SVEXTRA)})",
175 rf"(?P<sv_cr_out>{regex_enum(_SVEXTRA)})",
176 )),
177 r"\)",
178 r",",
179 r"\s?--\s?",
180 r"(?P<name>[A-Za-z0-9_\./]+)",
181 r"\s*$",
182 ))
183 REGEX = _re.compile(PATTERN)
184
185
186 def parse(stream):
187 for line in stream:
188 match = REGEX.match(line)
189 if match is not None:
190 entry = match.groupdict()
191 for field in _dataclasses.fields(Entry):
192 key = field.name
193 value = entry[key]
194 if issubclass(field.type, _enum.Enum):
195 value = {item.name:item for item in field.type}[value]
196 else:
197 value = field.type(value)
198 entry[key] = value
199 yield Entry(**entry)
200
201
202 def main():
203 entries = tuple(parse(_sys.stdin))
204
205 print(f"{len(entries)} entries found")
206
207
208 if __name__ == "__main__":
209 parser = _argparse.ArgumentParser()
210
211 args = vars(parser.parse_args())
212 main(**args)