insndb: revert recent renaming
[openpower-isa.git] / src / openpower / insndb / asm.py
1 # SPDX-License-Identifier: LGPLv3+
2 # Copyright (C) 2021 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
3 # Funded by NLnet http://nlnet.nl
4
5 """SVP64 OpenPOWER v3.0B assembly translator
6
7 This class takes raw svp64 assembly mnemonics (aliases excluded) and creates
8 an EXT001-encoded "svp64 prefix" (as a .long) followed by a v3.0B opcode.
9
10 It is very simple and straightforward, the only weirdness being the
11 extraction of the register information and conversion to v3.0B numbering.
12
13 Encoding format of svp64: https://libre-soc.org/openpower/sv/svp64/
14 Encoding format of arithmetic: https://libre-soc.org/openpower/sv/normal/
15 Encoding format of LDST: https://libre-soc.org/openpower/sv/ldst/
16 **TODO format of branches: https://libre-soc.org/openpower/sv/branches/**
17 **TODO format of CRs: https://libre-soc.org/openpower/sv/cr_ops/**
18 Bugtracker: https://bugs.libre-soc.org/show_bug.cgi?id=578
19 """
20
21 import functools
22 import os
23 import sys
24 from collections import OrderedDict
25 import inspect
26
27 from openpower.decoder.pseudo.pagereader import ISA
28 from openpower.decoder.power_svp64 import SVP64RM, get_regtype, decode_extra
29 from openpower.decoder.selectable_int import SelectableInt
30 from openpower.consts import SVP64MODE
31 from openpower.insndb.types import SVP64Instruction
32 from openpower.insndb.types import Database
33 from openpower.insndb.types import Style
34 from openpower.insndb.types import WordInstruction
35 from openpower.decoder.power_enums import find_wiki_dir
36
37 # for debug logging
38 from openpower.util import log
39
40
41 DB = Database(find_wiki_dir())
42
43
44 class AssemblerError(ValueError):
45 pass
46
47
48 # decodes svp64 assembly listings and creates EXT001 svp64 prefixes
49 class SVP64Asm:
50 def __init__(self, lst, bigendian=False, macros=None):
51 if macros is None:
52 macros = {}
53 self.macros = macros
54 self.lst = lst
55 self.trans = self.translate(lst)
56 self.isa = ISA() # reads the v3.0B pseudo-code markdown files
57 self.svp64 = SVP64RM() # reads the svp64 Remap entries for registers
58 assert bigendian == False, "error, bigendian not supported yet"
59
60 def __iter__(self):
61 yield from self.trans
62
63 def translate_one(self, insn, macros=None):
64 if macros is None:
65 macros = {}
66 macros.update(self.macros)
67 isa = self.isa
68 svp64 = self.svp64
69 insn_no_comments = insn.partition('#')[0].strip()
70 if not insn_no_comments:
71 return
72
73 # find first space, to get opcode
74 ls = insn_no_comments.split()
75 opcode = ls[0]
76 # now find opcode fields
77 fields = ''.join(ls[1:]).split(',')
78 mfields = list(filter(bool, map(str.strip, fields)))
79 log("opcode, fields", ls, opcode, mfields)
80 fields = []
81 # macro substitution
82 for field in mfields:
83 fields.append(macro_subst(macros, field))
84 log("opcode, fields substed", ls, opcode, fields)
85
86 # identify if it is a word instruction
87 record = DB[opcode]
88 if record is not None:
89 insn = WordInstruction.assemble(record=record, arguments=fields)
90 yield from insn.disassemble(record=record, style=Style.LEGACY)
91 return
92
93 # identify if is a svp64 mnemonic
94 if not opcode.startswith('sv.'):
95 yield insn # unaltered
96 return
97 opcode = opcode[3:] # strip leading "sv"
98
99 # start working on decoding the svp64 op: sv.basev30Bop/vec2/mode
100 opmodes = opcode.split("/") # split at "/"
101 v30b_op = opmodes.pop(0) # first is the v3.0B
102
103 record = DB[v30b_op]
104 if record is not None:
105 insn = SVP64Instruction.assemble(record=record,
106 arguments=fields, specifiers=opmodes)
107 yield from insn.disassemble(record=record, style=Style.LEGACY)
108 return
109
110 raise AssemblerError(insn_no_comments)
111
112 def translate(self, lst):
113 for insn in lst:
114 yield from self.translate_one(insn)
115
116
117 def macro_subst(macros, txt):
118 again = True
119 log("subst", txt, macros)
120 while again:
121 again = False
122 for macro, value in macros.items():
123 if macro == txt:
124 again = True
125 replaced = txt.replace(macro, value)
126 log("macro", txt, "replaced", replaced, macro, value)
127 txt = replaced
128 continue
129 toreplace = '%s.s' % macro
130 if toreplace == txt:
131 again = True
132 replaced = txt.replace(toreplace, "%s.s" % value)
133 log("macro", txt, "replaced", replaced, toreplace, value)
134 txt = replaced
135 continue
136 toreplace = '%s.v' % macro
137 if toreplace == txt:
138 again = True
139 replaced = txt.replace(toreplace, "%s.v" % value)
140 log("macro", txt, "replaced", replaced, toreplace, value)
141 txt = replaced
142 continue
143 toreplace = '*%s' % macro
144 if toreplace in txt:
145 again = True
146 replaced = txt.replace(toreplace, '*%s' % value)
147 log("macro", txt, "replaced", replaced, toreplace, value)
148 txt = replaced
149 continue
150 toreplace = '(%s)' % macro
151 if toreplace in txt:
152 again = True
153 replaced = txt.replace(toreplace, '(%s)' % value)
154 log("macro", txt, "replaced", replaced, toreplace, value)
155 txt = replaced
156 continue
157 log(" processed", txt)
158 return txt
159
160
161 def get_ws(line):
162 # find whitespace
163 ws = ''
164 while line:
165 if not line[0].isspace():
166 break
167 ws += line[0]
168 line = line[1:]
169 return ws, line
170
171
172 def main():
173 # get an input file and an output file
174 args = sys.argv[1:]
175 if len(args) == 0:
176 infile = sys.stdin
177 outfile = sys.stdout
178 # read the whole lot in advance in case of in-place
179 lines = list(infile.readlines())
180 elif len(args) != 2:
181 print("pysvp64asm [infile | -] [outfile | -]", file=sys.stderr)
182 exit(0)
183 else:
184 if args[0] == '--':
185 infile = sys.stdin
186 else:
187 infile = open(args[0], "r")
188 # read the whole lot in advance in case of in-place overwrite
189 lines = list(infile.readlines())
190
191 if args[1] == '--':
192 outfile = sys.stdout
193 else:
194 outfile = open(args[1], "w")
195
196 # read the line, look for custom insn, process it
197 macros = {} # macros which start ".set"
198 isa = SVP64Asm([])
199 for line in lines:
200 op = line.split("#")[0].strip()
201 # identify macros
202 if op.startswith(".set"):
203 macro = op[4:].split(",")
204 (macro, value) = map(str.strip, macro)
205 macros[macro] = value
206
207 if not op or op.startswith("#"):
208 outfile.write(line)
209 continue
210 (ws, line) = get_ws(line)
211 lst = isa.translate_one(op, macros)
212 lst = '; '.join(lst)
213 outfile.write("%s%s # %s\n" % (ws, lst, op))
214
215
216 if __name__ == '__main__':
217 lst = ['slw 3, 1, 4',
218 'extsw 5, 3',
219 'sv.extsw 5, 3',
220 'sv.cmpi 5, 1, 3, 2',
221 'sv.setb 5, 31',
222 'sv.isel 64.v, 3, 2, 65.v',
223 'sv.setb/dm=r3/sm=1<<r3 5, 31',
224 'sv.setb/m=r3 5, 31',
225 'sv.setb/vec2 5, 31',
226 'sv.setb/sw=8/ew=16 5, 31',
227 'sv.extsw./ff=eq 5, 31',
228 'sv.extsw./satu/sz/dz/sm=r3/dm=r3 5, 31',
229 'sv.add. 5.v, 2.v, 1.v',
230 'sv.add./m=r3 5.v, 2.v, 1.v',
231 ]
232 lst += [
233 'sv.stw 5.v, 4(1.v)',
234 'sv.ld 5.v, 4(1.v)',
235 'setvl. 2, 3, 4, 0, 1, 1',
236 'sv.setvl. 2, 3, 4, 0, 1, 1',
237 ]
238 lst = [
239 "sv.stfsu 0.v, 16(4.v)",
240 ]
241 lst = [
242 "sv.stfsu/els 0.v, 16(4)",
243 ]
244 lst = [
245 'sv.add./mr 5.v, 2.v, 1.v',
246 ]
247 macros = {'win2': '50', 'win': '60'}
248 lst = [
249 'sv.addi win2.v, win.v, -1',
250 'sv.add./mrr 5.v, 2.v, 1.v',
251 #'sv.lhzsh 5.v, 11(9.v), 15',
252 #'sv.lwzsh 5.v, 11(9.v), 15',
253 'sv.ffmadds 6.v, 2.v, 4.v, 6.v',
254 ]
255 lst = [
256 #'sv.fmadds 0.v, 8.v, 16.v, 4.v',
257 #'sv.ffadds 0.v, 8.v, 4.v',
258 'svremap 11, 0, 1, 2, 3, 2, 1',
259 'svshape 8, 1, 1, 1, 0',
260 'svshape 8, 1, 1, 1, 1',
261 ]
262 lst = [
263 #'sv.lfssh 4.v, 11(8.v), 15',
264 #'sv.lwzsh 4.v, 11(8.v), 15',
265 #'sv.svstep. 2.v, 4, 0',
266 #'sv.fcfids. 48.v, 64.v',
267 'sv.fcoss. 80.v, 0.v',
268 'sv.fcoss. 20.v, 0.v',
269 ]
270 lst = [
271 'sv.bc/all 3,12,192',
272 'sv.bclr/vsbi 3,81.v,192',
273 'sv.ld 5.v, 4(1.v)',
274 'sv.svstep. 2.v, 4, 0',
275 ]
276 lst = [
277 'minmax 3,12,5,3',
278 'minmax. 3,12,5,4',
279 'avgadd 3,12,5',
280 'absdu 3,12,5',
281 'absds 3,12,5',
282 'absdacu 3,12,5',
283 'absdacs 3,12,5',
284 'cprop 3,12,5',
285 'svindex 0,0,1,0,0,0,0',
286 ]
287 lst = [
288 'sv.svstep./m=r3 2.v, 4, 0',
289 'ternlogi 0,0,0,0x5',
290 'fmvis 5,65535',
291 'fmvis 5,1',
292 'fmvis 5,2',
293 'fmvis 5,4',
294 'fmvis 5,8',
295 'fmvis 5,16',
296 'fmvis 5,32',
297 'fmvis 5,64',
298 'fmvis 5,32768',
299 ]
300 lst = [
301 'sv.andi. *80, *80, 1',
302 'sv.ffmadds. 6.v, 2.v, 4.v, 6.v', # incorrectly inserted 32-bit op
303 'sv.ffmadds 6.v, 2.v, 4.v, 6.v', # correctly converted to .long
304 'svshape2 8, 1, 31, 7, 1, 1',
305 'sv.ld 5.v, 4(1.v)',
306 'sv.stw 5.v, 4(1.v)',
307 'sv.bc/all 3,12,192',
308 'pcdec. 0,0,0,0',
309 ]
310 lst = [
311 #"sv.cmp/ff=gt *0,*1,*2,0",
312 "dsld 5,4,5,3",
313
314 ]
315 isa = SVP64Asm(lst, macros=macros)
316 log("list:\n", "\n\t".join(list(isa)))
317 # running svp64.py is designed to test hard-coded lists
318 # (above) - which strictly speaking should all be unit tests.
319 # if you need to actually do assembler translation at the
320 # commandline use "pysvp64asm" - see setup.py
321 # XXX NO. asm_process()