1 # Reads OpenPOWER ISA pages from http://libre-soc.org/openpower/isa
2 """OpenPOWER ISA page parser
4 returns an OrderedDict of namedtuple "Ops" containing details of all
5 instructions listed in markdown files.
7 format must be strictly as follows (no optional sections) including whitespace:
15 if L = 0 then a <- [0]*32 || (RA)[32:63]
16 b <- [0]*32 || (RB)[32:63]
19 if a <u b then c <- 0b100
20 else if a >u b then c <- 0b010
22 CR[4*BF+32:4*BF+35] <- c || XER[SO]
24 Special Registers Altered:
35 * instruction registerlist
36 * instruction registerlist
38 4-space-indented pseudo-code
39 4-space-indented pseudo-code
41 Special Registers Altered:
42 4-space-indented register description
44 blank(s) (optional for convenience at end-of-page)
47 from collections
import namedtuple
, OrderedDict
51 opfields
= ("desc", "form", "opcode", "regs", "pcode", "sregs", "page")
52 Ops
= namedtuple("Ops", opfields
)
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]
62 return os
.path
.join(fdir
, "openpower", "isa")
68 self
.instr
= OrderedDict()
72 for pth
in os
.listdir(os
.path
.join(get_isa_dir())):
74 print("examining", get_isa_dir(), pth
)
77 if not pth
.endswith(".mdwn"):
78 print ("warning, file not .mdwn, skipping", pth
)
82 # code which helped add in the keyword "Pseudo-code:" automatically
83 rewrite
= self
.read_file_for_rewrite(pth
)
84 name
= os
.path
.join("/tmp", pth
)
85 with
open(name
, "w") as f
:
86 f
.write('\n'.join(rewrite
) + '\n')
88 def read_file_for_rewrite(self
, fname
):
89 pagename
= fname
.split('.')[0]
90 fname
= os
.path
.join(get_isa_dir(), fname
)
91 with
open(fname
) as f
:
95 l
= lines
.pop(0).rstrip() # get first line
100 # look for HTML comment, if starting, skip line.
101 # XXX this is braindead! it doesn't look for the end
102 # so please put ending of comments on one line:
103 # <!-- line 1 comment -->
104 # <!-- line 2 comment -->
105 if l
.startswith('<!--'):
106 # print ("skipping comment", l)
107 l
= lines
.pop(0).rstrip() # get first line
110 # Ignore blank lines before the first #
111 if len(l
.strip()) == 0:
115 assert l
.startswith('#'), ("# not found in line %s" % l
)
117 # whitespace expected
118 l
= lines
.pop(0).strip()
121 assert len(l
) == 0, ("blank line not found %s" % l
)
125 l
= lines
.pop(0).strip()
126 assert l
.endswith('-Form'), ("line with -Form expected %s" % l
)
129 # whitespace expected
130 l
= lines
.pop(0).strip()
131 assert len(l
) == 0, ("blank line not found %s" % l
)
134 # get list of opcodes
136 l
= lines
.pop(0).strip()
140 assert l
.startswith('*'), ("* not found in line %s" % l
)
142 rewrite
.append("Pseudo-code:")
146 l
= lines
.pop(0).rstrip()
150 assert l
.startswith(' '), ("4spcs not found in line %s" % l
)
152 # "Special Registers Altered" expected
153 l
= lines
.pop(0).rstrip()
154 assert l
.startswith("Special"), ("special not found %s" % l
)
157 # whitespace expected
158 l
= lines
.pop(0).strip()
159 assert len(l
) == 0, ("blank line not found %s" % l
)
164 l
= lines
.pop(0).rstrip()
168 assert l
.startswith(' '), ("4spcs not found in line %s" % l
)
170 # expect and drop whitespace
172 l
= lines
.pop(0).rstrip()
174 if len(l
) != 0 and not l
.startswith('<!--'):
179 def read_file(self
, fname
):
180 pagename
= fname
.split('.')[0]
181 fname
= os
.path
.join(get_isa_dir(), fname
)
182 with
open(fname
) as f
:
183 lines
= f
.readlines()
185 # set up dict with current page name
186 d
= {'page': pagename
}
188 # line-by-line lexer/parser, quite straightforward: pops one
189 # line off the list and checks it. nothing complicated needed,
190 # all sections are mandatory so no need for a full LALR parser.
192 l
= lines
.pop(0).rstrip() # get first line
196 # look for HTML comment, if starting, skip line.
197 # XXX this is braindead! it doesn't look for the end
198 # so please put ending of comments on one line:
199 # <!-- line 1 comment -->
200 # <!-- line 2 comment -->
201 if l
.startswith('<!--'):
202 # print ("skipping comment", l)
203 l
= lines
.pop(0).rstrip() # get next line
206 # Ignore blank lines before the first #
208 l
= lines
.pop(0).rstrip() # get next line
212 assert l
.startswith('#'), ("# not found in line '%s'" % l
)
213 d
['desc'] = l
[1:].strip()
215 # whitespace expected
216 l
= lines
.pop(0).strip()
219 assert len(l
) == 0, ("blank line not found %s" % l
)
222 l
= lines
.pop(0).strip()
223 assert l
.endswith('-Form'), ("line with -Form expected %s" % l
)
224 d
['form'] = l
.split('-')[0]
226 # whitespace expected
227 l
= lines
.pop(0).strip()
228 assert len(l
) == 0, ("blank line not found %s" % l
)
230 # get list of opcodes
233 l
= lines
.pop(0).strip()
236 assert l
.startswith('*'), ("* not found in line %s" % l
)
237 l
= l
[1:].split(' ') # lose star
238 l
= filter(lambda x
: len(x
) != 0, l
) # strip blanks
242 # "Pseudocode" expected
243 l
= lines
.pop(0).rstrip()
244 assert l
.startswith("Pseudo-code:"), ("pseudocode found %s" % l
)
246 # whitespace expected
247 l
= lines
.pop(0).strip()
250 assert len(l
) == 0, ("blank line not found %s" % l
)
255 l
= lines
.pop(0).rstrip()
258 assert l
.startswith(' '), ("4spcs not found in line %s" % l
)
259 l
= l
[4:] # lose 4 spaces
263 # "Special Registers Altered" expected
264 l
= lines
.pop(0).rstrip()
265 assert l
.startswith("Special"), ("special not found %s" % l
)
267 # whitespace expected
268 l
= lines
.pop(0).strip()
269 assert len(l
) == 0, ("blank line not found %s" % l
)
274 l
= lines
.pop(0).rstrip()
277 assert l
.startswith(' '), ("4spcs not found in line %s" % l
)
278 l
= l
[4:] # lose 4 spaces
286 # expect and drop whitespace
288 l
= lines
.pop(0).rstrip()
289 if len(l
) != 0 and not l
.startswith('<!--'):
292 def add_op(self
, o
, d
):
293 opcode
, regs
= o
[0], o
[1:]
297 regs
[0] = regs
[0].split(",")
298 op
['opcode'] = opcode
299 self
.instr
[opcode
] = Ops(**op
)
301 # create list of instructions by form
303 fl
= self
.forms
.get(form
, [])
304 self
.forms
[form
] = fl
+ [opcode
]
306 # create list of instructions by page
308 pl
= self
.page
.get(page
, [])
309 self
.page
[page
] = pl
+ [opcode
]
311 def pprint_ops(self
):
312 for k
, v
in self
.instr
.items():
313 print("# %s %s" % (v
.opcode
, v
.desc
))
314 print("Form: %s Regs: %s" % (v
.form
, v
.regs
))
315 print('\n'.join(map(lambda x
: " %s" % x
, v
.pcode
)))
317 print('\n'.join(map(lambda x
: " %s" % x
, v
.sregs
)))
319 for k
, v
in isa
.forms
.items():
323 if __name__
== '__main__':
326 # example on how to access cmp regs:
327 print ("cmp regs:", isa
.instr
["cmp"].regs
)