add CA/CA32 to write regs fields in parser
[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
75 def read_file(self, fname):
76 pagename = fname.split('.')[0]
77 fname = os.path.join(get_isa_dir(), fname)
78 with open(fname) as f:
79 lines = f.readlines()
80
81 # set up dict with current page name
82 d = {'page': pagename}
83
84 l = lines.pop(0).rstrip() # get first line
85 while lines:
86 print (l)
87 # expect get heading
88 assert l.startswith('#'), ("# not found in line %s" % l)
89 d['desc'] = l[1:].strip()
90
91 # whitespace expected
92 l = lines.pop(0).strip()
93 print (repr(l))
94 assert len(l) == 0, ("blank line not found %s" % l)
95
96 # Form expected
97 l = lines.pop(0).strip()
98 assert l.endswith('-Form'), ("line with -Form expected %s" % l)
99 d['form'] = l.split('-')[0]
100
101 # whitespace expected
102 l = lines.pop(0).strip()
103 assert len(l) == 0, ("blank line not found %s" % l)
104
105 # get list of opcodes
106 li = []
107 while True:
108 l = lines.pop(0).strip()
109 if len(l) == 0: break
110 assert l.startswith('*'), ("* not found in line %s" % l)
111 l = l[1:].split(' ') # lose star
112 l = filter(lambda x: len(x) != 0, l) # strip blanks
113 li.append(list(l))
114 opcodes = li
115
116 # get pseudocode
117 li = []
118 while True:
119 l = lines.pop(0).rstrip()
120 if len(l) == 0: break
121 assert l.startswith(' '), ("4spcs not found in line %s" % l)
122 l = l[4:] # lose 4 spaces
123 li.append(l)
124 d['pcode'] = li
125
126 # "Special Registers Altered" expected
127 l = lines.pop(0).rstrip()
128 assert l.startswith("Special"), ("special not found %s" % l)
129
130 # whitespace expected
131 l = lines.pop(0).strip()
132 assert len(l) == 0, ("blank line not found %s" % l)
133
134 # get special regs
135 li = []
136 while lines:
137 l = lines.pop(0).rstrip()
138 if len(l) == 0: break
139 assert l.startswith(' '), ("4spcs not found in line %s" % l)
140 l = l[4:] # lose 4 spaces
141 li.append(l)
142 d['sregs'] = li
143
144 # add in opcode
145 for o in opcodes:
146 self.add_op(o, d)
147
148 # expect and drop whitespace
149 while lines:
150 l = lines.pop(0).rstrip()
151 if len(l) != 0: break
152
153 def add_op(self, o, d):
154 opcode, regs = o[0], o[1:]
155 op = copy(d)
156 op['regs'] = regs
157 regs[0] = regs[0].split(",")
158 op['opcode'] = opcode
159 self.instr[opcode] = Ops(**op)
160
161 # create list of instructions by form
162 form = op['form']
163 fl = self.forms.get(form, [])
164 self.forms[form] = fl + [opcode]
165
166 # create list of instructions by page
167 page = op['page']
168 pl = self.page.get(page, [])
169 self.page[page] = pl + [opcode]
170
171 def pprint_ops(self):
172 for k, v in self.instr.items():
173 print ("# %s %s" % (v.opcode, v.desc))
174 print ("Form: %s Regs: %s" % (v.form, v.regs))
175 print ('\n'.join(map(lambda x: " %s" % x, v.pcode)))
176 print ("Specials")
177 print ('\n'.join(map(lambda x: " %s" % x, v.sregs)))
178 print ()
179 for k, v in isa.forms.items():
180 print (k, v)
181
182 if __name__ == '__main__':
183 isa = ISA()
184 isa.pprint_ops()