8583bf4b85a067b5c54df43c7e3ec8c180b5910a
[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 # expect get heading
95 assert l.startswith('#'), ("# not found in line %s" % l)
96
97 # whitespace expected
98 l = lines.pop(0).strip()
99 print(repr(l))
100 assert len(l) == 0, ("blank line not found %s" % l)
101 rewrite.append(l)
102
103 # Form expected
104 l = lines.pop(0).strip()
105 assert l.endswith('-Form'), ("line with -Form expected %s" % l)
106 rewrite.append(l)
107
108 # whitespace expected
109 l = lines.pop(0).strip()
110 assert len(l) == 0, ("blank line not found %s" % l)
111 rewrite.append(l)
112
113 # get list of opcodes
114 while True:
115 l = lines.pop(0).strip()
116 rewrite.append(l)
117 if len(l) == 0:
118 break
119 assert l.startswith('*'), ("* not found in line %s" % l)
120
121 rewrite.append("Pseudo-code:")
122 rewrite.append("")
123 # get pseudocode
124 while True:
125 l = lines.pop(0).rstrip()
126 rewrite.append(l)
127 if len(l) == 0:
128 break
129 assert l.startswith(' '), ("4spcs not found in line %s" % l)
130
131 # "Special Registers Altered" expected
132 l = lines.pop(0).rstrip()
133 assert l.startswith("Special"), ("special not found %s" % l)
134 rewrite.append(l)
135
136 # whitespace expected
137 l = lines.pop(0).strip()
138 assert len(l) == 0, ("blank line not found %s" % l)
139 rewrite.append(l)
140
141 # get special regs
142 while lines:
143 l = lines.pop(0).rstrip()
144 rewrite.append(l)
145 if len(l) == 0:
146 break
147 assert l.startswith(' '), ("4spcs not found in line %s" % l)
148
149 # expect and drop whitespace
150 while lines:
151 l = lines.pop(0).rstrip()
152 rewrite.append(l)
153 if len(l) != 0:
154 break
155
156 return rewrite
157
158 def read_file(self, fname):
159 pagename = fname.split('.')[0]
160 fname = os.path.join(get_isa_dir(), fname)
161 with open(fname) as f:
162 lines = f.readlines()
163
164 # set up dict with current page name
165 d = {'page': pagename}
166
167 # line-by-line lexer/parser, quite straightforward: pops one
168 # line off the list and checks it. nothing complicated needed,
169 # all sections are mandatory so no need for a full LALR parser.
170
171 l = lines.pop(0).rstrip() # get first line
172 while lines:
173 print(l)
174 # expect get heading
175 assert l.startswith('#'), ("# not found in line %s" % l)
176 d['desc'] = l[1:].strip()
177
178 # whitespace expected
179 l = lines.pop(0).strip()
180 print(repr(l))
181 assert len(l) == 0, ("blank line not found %s" % l)
182
183 # Form expected
184 l = lines.pop(0).strip()
185 assert l.endswith('-Form'), ("line with -Form expected %s" % l)
186 d['form'] = l.split('-')[0]
187
188 # whitespace expected
189 l = lines.pop(0).strip()
190 assert len(l) == 0, ("blank line not found %s" % l)
191
192 # get list of opcodes
193 li = []
194 while True:
195 l = lines.pop(0).strip()
196 if len(l) == 0:
197 break
198 assert l.startswith('*'), ("* not found in line %s" % l)
199 l = l[1:].split(' ') # lose star
200 l = filter(lambda x: len(x) != 0, l) # strip blanks
201 li.append(list(l))
202 opcodes = li
203
204 # "Pseudocode" expected
205 l = lines.pop(0).rstrip()
206 assert l.startswith("Pseudo-code:"), ("pseudocode found %s" % l)
207
208 # whitespace expected
209 l = lines.pop(0).strip()
210 print(repr(l))
211 assert len(l) == 0, ("blank line not found %s" % l)
212
213 # get pseudocode
214 li = []
215 while True:
216 l = lines.pop(0).rstrip()
217 if len(l) == 0:
218 break
219 assert l.startswith(' '), ("4spcs not found in line %s" % l)
220 l = l[4:] # lose 4 spaces
221 li.append(l)
222 d['pcode'] = li
223
224 # "Special Registers Altered" expected
225 l = lines.pop(0).rstrip()
226 assert l.startswith("Special"), ("special not found %s" % l)
227
228 # whitespace expected
229 l = lines.pop(0).strip()
230 assert len(l) == 0, ("blank line not found %s" % l)
231
232 # get special regs
233 li = []
234 while lines:
235 l = lines.pop(0).rstrip()
236 if len(l) == 0:
237 break
238 assert l.startswith(' '), ("4spcs not found in line %s" % l)
239 l = l[4:] # lose 4 spaces
240 li.append(l)
241 d['sregs'] = li
242
243 # add in opcode
244 for o in opcodes:
245 self.add_op(o, d)
246
247 # expect and drop whitespace
248 while lines:
249 l = lines.pop(0).rstrip()
250 if len(l) != 0:
251 break
252
253 def add_op(self, o, d):
254 opcode, regs = o[0], o[1:]
255 op = copy(d)
256 op['regs'] = regs
257 if len(regs) != 0:
258 regs[0] = regs[0].split(",")
259 op['opcode'] = opcode
260 self.instr[opcode] = Ops(**op)
261
262 # create list of instructions by form
263 form = op['form']
264 fl = self.forms.get(form, [])
265 self.forms[form] = fl + [opcode]
266
267 # create list of instructions by page
268 page = op['page']
269 pl = self.page.get(page, [])
270 self.page[page] = pl + [opcode]
271
272 def pprint_ops(self):
273 for k, v in self.instr.items():
274 print("# %s %s" % (v.opcode, v.desc))
275 print("Form: %s Regs: %s" % (v.form, v.regs))
276 print('\n'.join(map(lambda x: " %s" % x, v.pcode)))
277 print("Specials")
278 print('\n'.join(map(lambda x: " %s" % x, v.sregs)))
279 print()
280 for k, v in isa.forms.items():
281 print(k, v)
282
283
284 if __name__ == '__main__':
285 isa = ISA()
286 isa.pprint_ops()