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