pysvp64asm: drop obsolete code
[openpower-isa.git] / src / openpower / sv / trans / svp64.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.decoder.power_insn import SVP64Instruction
32 from openpower.decoder.power_insn import Database
33 from openpower.decoder.power_insn import Style
34 from openpower.decoder.power_insn 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 = None
88 record = DB[opcode]
89 if record is not None:
90 insn = WordInstruction.assemble(db=DB,
91 entry=opcode, arguments=fields)
92 yield from insn.disassemble(db=DB, style=Style.LEGACY)
93 return
94
95 # identify if is a svp64 mnemonic
96 if not opcode.startswith('sv.'):
97 yield insn # unaltered
98 return
99 opcode = opcode[3:] # strip leading "sv"
100
101 # start working on decoding the svp64 op: sv.basev30Bop/vec2/mode
102 opmodes = opcode.split("/") # split at "/"
103 v30b_op_orig = opmodes.pop(0) # first is the v3.0B
104 # check instruction ends with dot
105 rc_mode = v30b_op_orig.endswith('.')
106 if rc_mode:
107 v30b_op = v30b_op_orig[:-1]
108 else:
109 v30b_op = v30b_op_orig
110
111 record = None
112 record = DB[v30b_op]
113 if record is not None:
114 insn = SVP64Instruction.assemble(db=DB,
115 entry=v30b_op_orig,
116 arguments=fields,
117 specifiers=opmodes)
118 yield from insn.disassemble(db=DB, style=Style.LEGACY)
119 return
120
121 raise AssemblerError(insn_no_comments)
122
123 def translate(self, lst):
124 for insn in lst:
125 yield from self.translate_one(insn)
126
127
128 def macro_subst(macros, txt):
129 again = True
130 log("subst", txt, macros)
131 while again:
132 again = False
133 for macro, value in macros.items():
134 if macro == txt:
135 again = True
136 replaced = txt.replace(macro, value)
137 log("macro", txt, "replaced", replaced, macro, value)
138 txt = replaced
139 continue
140 toreplace = '%s.s' % macro
141 if toreplace == txt:
142 again = True
143 replaced = txt.replace(toreplace, "%s.s" % value)
144 log("macro", txt, "replaced", replaced, toreplace, value)
145 txt = replaced
146 continue
147 toreplace = '%s.v' % macro
148 if toreplace == txt:
149 again = True
150 replaced = txt.replace(toreplace, "%s.v" % value)
151 log("macro", txt, "replaced", replaced, toreplace, value)
152 txt = replaced
153 continue
154 toreplace = '*%s' % macro
155 if toreplace in txt:
156 again = True
157 replaced = txt.replace(toreplace, '*%s' % value)
158 log("macro", txt, "replaced", replaced, toreplace, value)
159 txt = replaced
160 continue
161 toreplace = '(%s)' % macro
162 if toreplace in txt:
163 again = True
164 replaced = txt.replace(toreplace, '(%s)' % value)
165 log("macro", txt, "replaced", replaced, toreplace, value)
166 txt = replaced
167 continue
168 log(" processed", txt)
169 return txt
170
171
172 def get_ws(line):
173 # find whitespace
174 ws = ''
175 while line:
176 if not line[0].isspace():
177 break
178 ws += line[0]
179 line = line[1:]
180 return ws, line
181
182
183 def asm_process():
184 # get an input file and an output file
185 args = sys.argv[1:]
186 if len(args) == 0:
187 infile = sys.stdin
188 outfile = sys.stdout
189 # read the whole lot in advance in case of in-place
190 lines = list(infile.readlines())
191 elif len(args) != 2:
192 print("pysvp64asm [infile | -] [outfile | -]", file=sys.stderr)
193 exit(0)
194 else:
195 if args[0] == '--':
196 infile = sys.stdin
197 else:
198 infile = open(args[0], "r")
199 # read the whole lot in advance in case of in-place overwrite
200 lines = list(infile.readlines())
201
202 if args[1] == '--':
203 outfile = sys.stdout
204 else:
205 outfile = open(args[1], "w")
206
207 # read the line, look for custom insn, process it
208 macros = {} # macros which start ".set"
209 isa = SVP64Asm([])
210 for line in lines:
211 op = line.split("#")[0].strip()
212 # identify macros
213 if op.startswith(".set"):
214 macro = op[4:].split(",")
215 (macro, value) = map(str.strip, macro)
216 macros[macro] = value
217
218 if not op or op.startswith("#"):
219 outfile.write(line)
220 continue
221 (ws, line) = get_ws(line)
222 lst = isa.translate_one(op, macros)
223 lst = '; '.join(lst)
224 outfile.write("%s%s # %s\n" % (ws, lst, op))
225
226
227 if __name__ == '__main__':
228 lst = ['slw 3, 1, 4',
229 'extsw 5, 3',
230 'sv.extsw 5, 3',
231 'sv.cmpi 5, 1, 3, 2',
232 'sv.setb 5, 31',
233 'sv.isel 64.v, 3, 2, 65.v',
234 'sv.setb/dm=r3/sm=1<<r3 5, 31',
235 'sv.setb/m=r3 5, 31',
236 'sv.setb/vec2 5, 31',
237 'sv.setb/sw=8/ew=16 5, 31',
238 'sv.extsw./ff=eq 5, 31',
239 'sv.extsw./satu/sz/dz/sm=r3/dm=r3 5, 31',
240 'sv.extsw./pr=eq 5.v, 31',
241 'sv.add. 5.v, 2.v, 1.v',
242 'sv.add./m=r3 5.v, 2.v, 1.v',
243 ]
244 lst += [
245 'sv.stw 5.v, 4(1.v)',
246 'sv.ld 5.v, 4(1.v)',
247 'setvl. 2, 3, 4, 0, 1, 1',
248 'sv.setvl. 2, 3, 4, 0, 1, 1',
249 ]
250 lst = [
251 "sv.stfsu 0.v, 16(4.v)",
252 ]
253 lst = [
254 "sv.stfsu/els 0.v, 16(4)",
255 ]
256 lst = [
257 'sv.add./mr 5.v, 2.v, 1.v',
258 ]
259 macros = {'win2': '50', 'win': '60'}
260 lst = [
261 'sv.addi win2.v, win.v, -1',
262 'sv.add./mrr 5.v, 2.v, 1.v',
263 #'sv.lhzsh 5.v, 11(9.v), 15',
264 #'sv.lwzsh 5.v, 11(9.v), 15',
265 'sv.ffmadds 6.v, 2.v, 4.v, 6.v',
266 ]
267 lst = [
268 #'sv.fmadds 0.v, 8.v, 16.v, 4.v',
269 #'sv.ffadds 0.v, 8.v, 4.v',
270 'svremap 11, 0, 1, 2, 3, 2, 1',
271 'svshape 8, 1, 1, 1, 0',
272 'svshape 8, 1, 1, 1, 1',
273 ]
274 lst = [
275 #'sv.lfssh 4.v, 11(8.v), 15',
276 #'sv.lwzsh 4.v, 11(8.v), 15',
277 #'sv.svstep. 2.v, 4, 0',
278 #'sv.fcfids. 48.v, 64.v',
279 'sv.fcoss. 80.v, 0.v',
280 'sv.fcoss. 20.v, 0.v',
281 ]
282 lst = [
283 'sv.bc/all 3,12,192',
284 'sv.bclr/vsbi 3,81.v,192',
285 'sv.ld 5.v, 4(1.v)',
286 'sv.svstep. 2.v, 4, 0',
287 ]
288 lst = [
289 'maxs 3,12,5',
290 'maxs. 3,12,5',
291 'avgadd 3,12,5',
292 'absdu 3,12,5',
293 'absds 3,12,5',
294 'absdacu 3,12,5',
295 'absdacs 3,12,5',
296 'cprop 3,12,5',
297 'svindex 0,0,1,0,0,0,0',
298 ]
299 lst = [
300 'sv.svstep./m=r3 2.v, 4, 0',
301 'ternlogi 0,0,0,0x5',
302 'fmvis 5,65535',
303 'fmvis 5,1',
304 'fmvis 5,2',
305 'fmvis 5,4',
306 'fmvis 5,8',
307 'fmvis 5,16',
308 'fmvis 5,32',
309 'fmvis 5,64',
310 'fmvis 5,32768',
311 ]
312 lst = [
313 'sv.andi. *80, *80, 1',
314 'sv.ffmadds. 6.v, 2.v, 4.v, 6.v', # incorrectly inserted 32-bit op
315 'sv.ffmadds 6.v, 2.v, 4.v, 6.v', # correctly converted to .long
316 'svshape2 8, 1, 31, 7, 1, 1',
317 'sv.ld 5.v, 4(1.v)',
318 'sv.stw 5.v, 4(1.v)',
319 'sv.bc/all 3,12,192',
320 'pcdec. 0,0,0,0',
321 ]
322 lst = [
323 #"sv.cmp/ff=gt *0,*1,*2,0",
324 "dsld 5,4,5,3",
325
326 ]
327 isa = SVP64Asm(lst, macros=macros)
328 log("list:\n", "\n\t".join(list(isa)))
329 # running svp64.py is designed to test hard-coded lists
330 # (above) - which strictly speaking should all be unit tests.
331 # if you need to actually do assembler translation at the
332 # commandline use "pysvp64asm" - see setup.py
333 # XXX NO. asm_process()