code cleanup / comments
[openpower-isa.git] / src / openpower / decoder / power_fields.py
1 from collections import OrderedDict, namedtuple
2 from openpower.decoder.power_enums import find_wiki_file
3
4
5 class BitRange(OrderedDict):
6 """BitRange: remaps from straight indices (0,1,2..) to bit numbers
7 """
8
9 def __getitem__(self, subscript):
10 if isinstance(subscript, slice):
11 return list(self.values())[subscript]
12 else:
13 return OrderedDict.__getitem__(self, subscript)
14
15
16 def decode_instructions(form):
17 res = {}
18 accum = []
19 for l in form:
20 if l.strip().startswith("Formats"):
21 l = l.strip().split(":")[-1]
22 l = l.replace(" ", "")
23 l = l.split(",")
24 for fmt in l:
25 if fmt not in res:
26 res[fmt] = [accum[0]]
27 else:
28 res[fmt].append(accum[0])
29 accum = []
30 else:
31 accum.append(l.strip())
32 return res
33
34
35 def decode_form_header(hdr):
36 res = {}
37 count = 0
38 hdr = hdr.strip()
39 for f in hdr.split("|"):
40 if not f:
41 continue
42 if f[0].isdigit():
43 idx = int(f.strip().split(' ')[0])
44 res[count] = idx
45 count += len(f) + 1
46 return res
47
48
49 def find_unique(d, key):
50 if key not in d:
51 return key
52 idx = 1
53 while "%s_%d" % (key, idx) in d:
54 idx += 1
55 return "%s_%d" % (key, idx)
56
57
58 def decode_line(header, line):
59 line = line.strip()
60 res = {}
61 count = 0
62 prev_fieldname = None
63 for f in line.split("|"):
64 if not f:
65 continue
66 end = count + len(f) + 1
67 fieldname = f.strip()
68 if not fieldname or fieldname.startswith('/'):
69 if prev_fieldname is not None:
70 res[prev_fieldname] = (res[prev_fieldname], header[count])
71 prev_fieldname = None
72 count = end
73 continue
74 bitstart = header[count]
75 if prev_fieldname is not None:
76 res[prev_fieldname] = (res[prev_fieldname], bitstart)
77 res[fieldname] = bitstart
78 count = end
79 prev_fieldname = fieldname
80 res[prev_fieldname] = (bitstart, 32)
81 return res
82
83
84 def decode_form(form):
85 header = decode_form_header(form[0])
86 res = []
87 for line in form[1:]:
88 dec = decode_line(header, line)
89 if dec:
90 res.append(dec)
91 fields = {}
92 falternate = {}
93 for l in res:
94 for k, (start, end) in l.items():
95 if k in fields:
96 if (start, end) == fields[k]:
97 continue # already in and matching for this Form
98 if k in falternate:
99 alternate = "%s_%d" % (k, falternate[k])
100 if (start, end) == fields[alternate]:
101 continue
102 falternate[k] = fidx = falternate.get(k, 0) + 1
103 fields["%s_%d" % (k, fidx)] = (start, end)
104 else:
105 fields[k] = (start, end)
106 return fields
107
108
109 class DecodeFields:
110
111 def __init__(self, bitkls=BitRange, bitargs=(), fname=None,
112 name_on_wiki=None):
113 self.bitkls = bitkls
114 self.bitargs = bitargs
115 if fname is None:
116 assert name_on_wiki is None
117 fname = "fields.txt"
118 name_on_wiki = "fields.text"
119 self.fname = find_wiki_file(name_on_wiki)
120
121 @property
122 def form_names(self):
123 return self.instrs.keys()
124
125 def create_specs(self):
126 self.forms, self.instrs = self.decode_fields()
127 forms = self.form_names
128 #print ("specs", self.forms, forms)
129 for form in forms:
130 fields = self.instrs[form]
131 fk = fields.keys()
132 Fields = namedtuple("Fields", fk)
133 instr = Fields(**fields)
134 setattr(self, "Form%s" % form, instr)
135 # now add in some commonly-used fields (should be done automatically)
136 # note that these should only be ones which are the same on all Forms
137 # note: these are from microwatt insn_helpers.vhdl
138 self.common_fields = {
139 "PO": self.Formall.PO,
140 "FRS": self.FormX.FRS,
141 "FRT": self.FormX.FRT,
142 "FRA": self.FormX.FRA,
143 "FRB": self.FormX.FRB,
144 "FRC": self.FormA.FRC,
145 "RS": self.FormX.RS,
146 "RT": self.FormX.RT,
147 "RA": self.FormX.RA,
148 "RB": self.FormX.RB,
149 "RC": self.FormVA.RC,
150 "SI": self.FormD.SI,
151 "UI": self.FormD.UI,
152 "L": self.FormD.L,
153 "SH32": self.FormM.SH,
154 "sh": self.FormMD.sh,
155 "MB32": self.FormM.MB,
156 "ME32": self.FormM.ME,
157 "LI": self.FormI.LI,
158 "LK": self.FormI.LK,
159 "AA": self.FormB.AA,
160 "Rc": self.FormX.Rc,
161 "OE": self.FormXO.OE,
162 "BD": self.FormB.BD,
163 "BF": self.FormX.BF,
164 "CR": self.FormXL.XO,
165 "BB": self.FormXL.BB,
166 "BA": self.FormXL.BA,
167 "BT": self.FormXL.BT,
168 "FXM": self.FormXFX.FXM,
169 "BO": self.FormXL.BO,
170 "BI": self.FormXL.BI,
171 "BH": self.FormXL.BH,
172 "D": self.FormD.D,
173 "DS": self.FormDS.DS,
174 "TO": self.FormX.TO,
175 "BC": self.FormA.BC,
176 "SH": self.FormX.SH,
177 "ME": self.FormM.ME,
178 "MB": self.FormM.MB,
179 "SPR": self.FormXFX.SPR}
180 for k, v in self.common_fields.items():
181 setattr(self, k, v)
182
183 def decode_fields(self):
184 with open(self.fname) as f:
185 txt = f.readlines()
186 #print ("decode", txt)
187 forms = {}
188 reading_data = False
189 for l in txt:
190 l = l.strip()
191 if len(l) == 0:
192 continue
193 if reading_data:
194 if l[0] == '#':
195 reading_data = False
196 else:
197 forms[heading].append(l)
198 if not reading_data:
199 assert l[0] == '#'
200 heading = l[1:].strip()
201 # if heading.startswith('1.6.28'): # skip instr fields for now
202 # break
203 heading = heading.split(' ')[-1]
204 reading_data = True
205 forms[heading] = []
206
207 res = {}
208 inst = {}
209
210 for hdr, form in forms.items():
211 if heading == 'Fields':
212 i = decode_instructions(form)
213 for form, field in i.items():
214 inst[form] = self.decode_instruction_fields(field)
215 # else:
216 # res[hdr] = decode_form(form)
217 return res, inst
218
219 def decode_instruction_fields(self, fields):
220 res = {}
221 for field in fields:
222 f, spec = field.strip().split(" ")
223 ss = spec[1:-1].split(",")
224 fs = f.split(",")
225 if len(fs) > 1:
226 individualfields = []
227 for f0, s0 in zip(fs, ss):
228 txt = "%s (%s)" % (f0, s0)
229 individualfields.append(txt)
230 if len(fs) > 1:
231 res.update(self.decode_instruction_fields(
232 individualfields))
233 d = self.bitkls(*self.bitargs)
234 idx = 0
235 for s in ss:
236 s = s.split(':')
237 if len(s) == 1:
238 d[idx] = int(s[0])
239 idx += 1
240 else:
241 start = int(s[0])
242 end = int(s[1])
243 while start <= end:
244 d[idx] = start
245 idx += 1
246 start += 1
247 f = f.replace(",", "_")
248 unique = find_unique(res, f)
249 res[unique] = d
250
251 return res
252
253
254 if __name__ == '__main__':
255 dec = DecodeFields()
256 dec.create_specs()
257 forms, instrs = dec.forms, dec.instrs
258 for form, fields in instrs.items():
259 print("Form", form)
260 for field, bits in fields.items():
261 print("\tfield", field, bits)