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