Merge branch 'master' of ssh://git.libre-riscv.org:922/soc
[soc.git] / src / soc / decoder / pseudo / pagereader.py
1 # Reads OpenPOWER ISA pages from http://libre-riscv.org/openpower/isa
2 """OpenPOWER ISA page parser
3
4 returns an OrderedDict of namedtuple "Ops" containing details of all
5 instructions listed in markdown files.
6
7 format must be strictly as follows (no optional sections) including whitespace:
8
9 # Compare Logical
10
11 X-Form
12
13 * cmpl BF,L,RA,RB
14
15 if L = 0 then a <- [0]*32 || (RA)[32:63]
16 b <- [0]*32 || (RB)[32:63]
17 else a <- (RA)
18 b <- (RB)
19 if a <u b then c <- 0b100
20 else if a >u b then c <- 0b010
21 else c <- 0b001
22 CR[4*BF+32:4*BF+35] <- c || XER[SO]
23
24 Special Registers Altered:
25
26 CR field BF
27 Another field
28
29 this translates to:
30
31 # heading
32 blank
33 Some-Form
34 blank
35 * instruction registerlist
36 * instruction registerlist
37 blank
38 4-space-indented pseudo-code
39 4-space-indented pseudo-code
40 blank
41 Special Registers Altered:
42 4-space-indented register description
43 blank
44 blank(s) (optional for convenience at end-of-page)
45 """
46
47 from collections import namedtuple, OrderedDict
48 from copy import copy
49 import os
50
51 opfields = ("desc", "form", "opcode", "regs", "pcode", "sregs", "page")
52 Ops = namedtuple("Ops", opfields)
53
54
55 def get_isa_dir():
56 fdir = os.path.abspath(os.path.dirname(__file__))
57 fdir = os.path.split(fdir)[0]
58 fdir = os.path.split(fdir)[0]
59 fdir = os.path.split(fdir)[0]
60 fdir = os.path.split(fdir)[0]
61 return os.path.join(fdir, "libreriscv", "openpower", "isa")
62
63
64 class ISA:
65
66 def __init__(self):
67 self.instr = OrderedDict()
68 self.forms = {}
69 self.page = {}
70 for pth in os.listdir(os.path.join(get_isa_dir())):
71 print(get_isa_dir(), pth)
72 if "swp" in pth:
73 continue
74 assert pth.endswith(".mdwn"), "only %s in isa dir" % pth
75 self.read_file(pth)
76 continue
77 # code which helped add in the keyword "Pseudo-code:" automatically
78 rewrite = self.read_file_for_rewrite(pth)
79 name = os.path.join("/tmp", pth)
80 with open(name, "w") as f:
81 f.write('\n'.join(rewrite) + '\n')
82
83 def read_file_for_rewrite(self, fname):
84 pagename = fname.split('.')[0]
85 fname = os.path.join(get_isa_dir(), fname)
86 with open(fname) as f:
87 lines = f.readlines()
88 rewrite = []
89
90 l = lines.pop(0).rstrip() # get first line
91 rewrite.append(l)
92 while lines:
93 print(l)
94 # look for HTML comment, if starting, skip line.
95 # XXX this is braindead! it doesn't look for the end
96 # so please put ending of comments on one line:
97 # <!-- line 1 comment -->
98 # <!-- line 2 comment -->
99 if l.startswith('<!--'):
100 # print ("skipping comment", l)
101 l = lines.pop(0).rstrip() # get first line
102 continue
103
104 # Ignore blank lines before the first #
105 if len(l.strip()) == 0:
106 continue
107
108 # expect get heading
109 assert l.startswith('#'), ("# not found in line %s" % l)
110
111 # whitespace expected
112 l = lines.pop(0).strip()
113 print(repr(l))
114 assert len(l) == 0, ("blank line not found %s" % l)
115 rewrite.append(l)
116
117 # Form expected
118 l = lines.pop(0).strip()
119 assert l.endswith('-Form'), ("line with -Form expected %s" % l)
120 rewrite.append(l)
121
122 # whitespace expected
123 l = lines.pop(0).strip()
124 assert len(l) == 0, ("blank line not found %s" % l)
125 rewrite.append(l)
126
127 # get list of opcodes
128 while True:
129 l = lines.pop(0).strip()
130 rewrite.append(l)
131 if len(l) == 0:
132 break
133 assert l.startswith('*'), ("* not found in line %s" % l)
134
135 rewrite.append("Pseudo-code:")
136 rewrite.append("")
137 # get pseudocode
138 while True:
139 l = lines.pop(0).rstrip()
140 rewrite.append(l)
141 if len(l) == 0:
142 break
143 assert l.startswith(' '), ("4spcs not found in line %s" % l)
144
145 # "Special Registers Altered" expected
146 l = lines.pop(0).rstrip()
147 assert l.startswith("Special"), ("special not found %s" % l)
148 rewrite.append(l)
149
150 # whitespace expected
151 l = lines.pop(0).strip()
152 assert len(l) == 0, ("blank line not found %s" % l)
153 rewrite.append(l)
154
155 # get special regs
156 while lines:
157 l = lines.pop(0).rstrip()
158 rewrite.append(l)
159 if len(l) == 0:
160 break
161 assert l.startswith(' '), ("4spcs not found in line %s" % l)
162
163 # expect and drop whitespace
164 while lines:
165 l = lines.pop(0).rstrip()
166 rewrite.append(l)
167 if len(l) != 0 and not l.startswith('<!--'):
168 break
169
170 return rewrite
171
172 def read_file(self, fname):
173 pagename = fname.split('.')[0]
174 fname = os.path.join(get_isa_dir(), fname)
175 with open(fname) as f:
176 lines = f.readlines()
177
178 # set up dict with current page name
179 d = {'page': pagename}
180
181 # line-by-line lexer/parser, quite straightforward: pops one
182 # line off the list and checks it. nothing complicated needed,
183 # all sections are mandatory so no need for a full LALR parser.
184
185 l = lines.pop(0).rstrip() # get first line
186 while lines:
187 print(l)
188 # look for HTML comment, if starting, skip line.
189 # XXX this is braindead! it doesn't look for the end
190 # so please put ending of comments on one line:
191 # <!-- line 1 comment -->
192 # <!-- line 2 comment -->
193 if l.startswith('<!--'):
194 # print ("skipping comment", l)
195 l = lines.pop(0).rstrip() # get next line
196 continue
197
198 # Ignore blank lines before the first #
199 if len(l) == 0:
200 l = lines.pop(0).rstrip() # get next line
201 continue
202
203 # expect get heading
204 assert l.startswith('#'), ("# not found in line '%s'" % l)
205 d['desc'] = l[1:].strip()
206
207 # whitespace expected
208 l = lines.pop(0).strip()
209 print(repr(l))
210 assert len(l) == 0, ("blank line not found %s" % l)
211
212 # Form expected
213 l = lines.pop(0).strip()
214 assert l.endswith('-Form'), ("line with -Form expected %s" % l)
215 d['form'] = l.split('-')[0]
216
217 # whitespace expected
218 l = lines.pop(0).strip()
219 assert len(l) == 0, ("blank line not found %s" % l)
220
221 # get list of opcodes
222 li = []
223 while True:
224 l = lines.pop(0).strip()
225 if len(l) == 0:
226 break
227 assert l.startswith('*'), ("* not found in line %s" % l)
228 l = l[1:].split(' ') # lose star
229 l = filter(lambda x: len(x) != 0, l) # strip blanks
230 li.append(list(l))
231 opcodes = li
232
233 # "Pseudocode" expected
234 l = lines.pop(0).rstrip()
235 assert l.startswith("Pseudo-code:"), ("pseudocode found %s" % l)
236
237 # whitespace expected
238 l = lines.pop(0).strip()
239 print(repr(l))
240 assert len(l) == 0, ("blank line not found %s" % l)
241
242 # get pseudocode
243 li = []
244 while True:
245 l = lines.pop(0).rstrip()
246 if len(l) == 0:
247 break
248 assert l.startswith(' '), ("4spcs not found in line %s" % l)
249 l = l[4:] # lose 4 spaces
250 li.append(l)
251 d['pcode'] = li
252
253 # "Special Registers Altered" expected
254 l = lines.pop(0).rstrip()
255 assert l.startswith("Special"), ("special not found %s" % l)
256
257 # whitespace expected
258 l = lines.pop(0).strip()
259 assert len(l) == 0, ("blank line not found %s" % l)
260
261 # get special regs
262 li = []
263 while lines:
264 l = lines.pop(0).rstrip()
265 if len(l) == 0:
266 break
267 assert l.startswith(' '), ("4spcs not found in line %s" % l)
268 l = l[4:] # lose 4 spaces
269 li.append(l)
270 d['sregs'] = li
271
272 # add in opcode
273 for o in opcodes:
274 self.add_op(o, d)
275
276 # expect and drop whitespace
277 while lines:
278 l = lines.pop(0).rstrip()
279 if len(l) != 0 and not l.startswith('<!--'):
280 break
281
282 def add_op(self, o, d):
283 opcode, regs = o[0], o[1:]
284 op = copy(d)
285 op['regs'] = regs
286 if len(regs) != 0:
287 regs[0] = regs[0].split(",")
288 op['opcode'] = opcode
289 self.instr[opcode] = Ops(**op)
290
291 # create list of instructions by form
292 form = op['form']
293 fl = self.forms.get(form, [])
294 self.forms[form] = fl + [opcode]
295
296 # create list of instructions by page
297 page = op['page']
298 pl = self.page.get(page, [])
299 self.page[page] = pl + [opcode]
300
301 def pprint_ops(self):
302 for k, v in self.instr.items():
303 print("# %s %s" % (v.opcode, v.desc))
304 print("Form: %s Regs: %s" % (v.form, v.regs))
305 print('\n'.join(map(lambda x: " %s" % x, v.pcode)))
306 print("Specials")
307 print('\n'.join(map(lambda x: " %s" % x, v.sregs)))
308 print()
309 for k, v in isa.forms.items():
310 print(k, v)
311
312
313 if __name__ == '__main__':
314 isa = ISA()
315 isa.pprint_ops()
316 # example on how to access cmp regs:
317 print ("cmp regs:", isa.instr["cmp"].regs)