diff options
author | Mike Pall <mike> | 2010-08-26 02:09:15 +0200 |
---|---|---|
committer | Mike Pall <mike> | 2010-08-26 02:09:15 +0200 |
commit | 4f47d31fefbe8a690fbf85e8bf2b74598e72a183 (patch) | |
tree | 3c06e40b536f7a94370c75cfc9fb9e3e513935e0 | |
parent | 5526fa23122a0192c4315a1955a44bbaa2607d43 (diff) | |
download | luajit-4f47d31fefbe8a690fbf85e8bf2b74598e72a183.tar.gz luajit-4f47d31fefbe8a690fbf85e8bf2b74598e72a183.tar.bz2 luajit-4f47d31fefbe8a690fbf85e8bf2b74598e72a183.zip |
PPC: Add DynASM PowerPC module. Standard instructions only.
-rw-r--r-- | dynasm/dasm_ppc.lua | 926 |
1 files changed, 926 insertions, 0 deletions
diff --git a/dynasm/dasm_ppc.lua b/dynasm/dasm_ppc.lua new file mode 100644 index 00000000..acea7cc1 --- /dev/null +++ b/dynasm/dasm_ppc.lua | |||
@@ -0,0 +1,926 @@ | |||
1 | ------------------------------------------------------------------------------ | ||
2 | -- DynASM PPC module. | ||
3 | -- | ||
4 | -- Copyright (C) 2005-2010 Mike Pall. All rights reserved. | ||
5 | -- See dynasm.lua for full copyright notice. | ||
6 | ------------------------------------------------------------------------------ | ||
7 | |||
8 | -- Module information: | ||
9 | local _info = { | ||
10 | arch = "ppc", | ||
11 | description = "DynASM PPC module", | ||
12 | version = "1.2.1", | ||
13 | vernum = 10201, | ||
14 | release = "2010-XX-XX", | ||
15 | author = "Mike Pall", | ||
16 | license = "MIT", | ||
17 | } | ||
18 | |||
19 | -- Exported glue functions for the arch-specific module. | ||
20 | local _M = { _info = _info } | ||
21 | |||
22 | -- Cache library functions. | ||
23 | local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs | ||
24 | local assert, setmetatable = assert, setmetatable | ||
25 | local _s = string | ||
26 | local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char | ||
27 | local match, gmatch = _s.match, _s.gmatch | ||
28 | local concat, sort = table.concat, table.sort | ||
29 | |||
30 | -- Inherited tables and callbacks. | ||
31 | local g_opt, g_arch | ||
32 | local wline, werror, wfatal, wwarn | ||
33 | |||
34 | -- Action name list. | ||
35 | -- CHECK: Keep this in sync with the C code! | ||
36 | local action_names = { | ||
37 | "STOP", "SECTION", "ESC", "REL_EXT", | ||
38 | "ALIGN", "REL_LG", "LABEL_LG", | ||
39 | "REL_PC", "LABEL_PC", "IMM", | ||
40 | } | ||
41 | |||
42 | -- Maximum number of section buffer positions for dasm_put(). | ||
43 | -- CHECK: Keep this in sync with the C code! | ||
44 | local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. | ||
45 | |||
46 | -- Action name -> action number. | ||
47 | local map_action = {} | ||
48 | for n,name in ipairs(action_names) do | ||
49 | map_action[name] = n-1 | ||
50 | end | ||
51 | |||
52 | -- Action list buffer. | ||
53 | local actlist = {} | ||
54 | |||
55 | -- Argument list for next dasm_put(). Start with offset 0 into action list. | ||
56 | local actargs = { 0 } | ||
57 | |||
58 | -- Current number of section buffer positions for dasm_put(). | ||
59 | local secpos = 1 | ||
60 | |||
61 | ------------------------------------------------------------------------------ | ||
62 | |||
63 | -- Return 8 digit hex number. | ||
64 | local function tohex(x) | ||
65 | return sub(format("%08x", x), -8) -- Avoid 64 bit portability problem in Lua. | ||
66 | end | ||
67 | |||
68 | -- Dump action names and numbers. | ||
69 | local function dumpactions(out) | ||
70 | out:write("DynASM encoding engine action codes:\n") | ||
71 | for n,name in ipairs(action_names) do | ||
72 | local num = map_action[name] | ||
73 | out:write(format(" %-10s %02X %d\n", name, num, num)) | ||
74 | end | ||
75 | out:write("\n") | ||
76 | end | ||
77 | |||
78 | -- Write action list buffer as a huge static C array. | ||
79 | local function writeactions(out, name) | ||
80 | local nn = #actlist | ||
81 | if nn == 0 then nn = 1; actlist[0] = map_action.STOP end | ||
82 | out:write("static const unsigned int ", name, "[", nn, "] = {\n") | ||
83 | for i = 1,nn-1 do | ||
84 | assert(out:write("0x", tohex(actlist[i]), ",\n")) | ||
85 | end | ||
86 | assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) | ||
87 | end | ||
88 | |||
89 | ------------------------------------------------------------------------------ | ||
90 | |||
91 | -- Add word to action list. | ||
92 | local function wputxw(n) | ||
93 | assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") | ||
94 | actlist[#actlist+1] = n | ||
95 | end | ||
96 | |||
97 | -- Add action to list with optional arg. Advance buffer pos, too. | ||
98 | local function waction(action, val, a, num) | ||
99 | local w = assert(map_action[action], "bad action name `"..action.."'") | ||
100 | wputxw(w * 0x10000 + (val or 0)) | ||
101 | if a then actargs[#actargs+1] = a end | ||
102 | if a or num then secpos = secpos + (num or 1) end | ||
103 | end | ||
104 | |||
105 | -- Flush action list (intervening C code or buffer pos overflow). | ||
106 | local function wflush(term) | ||
107 | if #actlist == actargs[1] then return end -- Nothing to flush. | ||
108 | if not term then waction("STOP") end -- Terminate action list. | ||
109 | wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) | ||
110 | actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). | ||
111 | secpos = 1 -- The actionlist offset occupies a buffer position, too. | ||
112 | end | ||
113 | |||
114 | -- Put escaped word. | ||
115 | local function wputw(n) | ||
116 | if n <= 0xffffff then waction("ESC") end | ||
117 | wputxw(n) | ||
118 | end | ||
119 | |||
120 | -- Reserve position for word. | ||
121 | local function wpos() | ||
122 | local pos = #actlist+1 | ||
123 | actlist[pos] = "" | ||
124 | return pos | ||
125 | end | ||
126 | |||
127 | -- Store word to reserved position. | ||
128 | local function wputpos(pos, n) | ||
129 | assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") | ||
130 | actlist[pos] = n | ||
131 | end | ||
132 | |||
133 | ------------------------------------------------------------------------------ | ||
134 | |||
135 | -- Global label name -> global label number. With auto assignment on 1st use. | ||
136 | local next_global = 20 | ||
137 | local map_global = setmetatable({}, { __index = function(t, name) | ||
138 | if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end | ||
139 | local n = next_global | ||
140 | if n > 2047 then werror("too many global labels") end | ||
141 | next_global = n + 1 | ||
142 | t[name] = n | ||
143 | return n | ||
144 | end}) | ||
145 | |||
146 | -- Dump global labels. | ||
147 | local function dumpglobals(out, lvl) | ||
148 | local t = {} | ||
149 | for name, n in pairs(map_global) do t[n] = name end | ||
150 | out:write("Global labels:\n") | ||
151 | for i=20,next_global-1 do | ||
152 | out:write(format(" %s\n", t[i])) | ||
153 | end | ||
154 | out:write("\n") | ||
155 | end | ||
156 | |||
157 | -- Write global label enum. | ||
158 | local function writeglobals(out, prefix) | ||
159 | local t = {} | ||
160 | for name, n in pairs(map_global) do t[n] = name end | ||
161 | out:write("enum {\n") | ||
162 | for i=20,next_global-1 do | ||
163 | out:write(" ", prefix, t[i], ",\n") | ||
164 | end | ||
165 | out:write(" ", prefix, "_MAX\n};\n") | ||
166 | end | ||
167 | |||
168 | -- Write global label names. | ||
169 | local function writeglobalnames(out, name) | ||
170 | local t = {} | ||
171 | for name, n in pairs(map_global) do t[n] = name end | ||
172 | out:write("static const char *const ", name, "[] = {\n") | ||
173 | for i=20,next_global-1 do | ||
174 | out:write(" \"", t[i], "\",\n") | ||
175 | end | ||
176 | out:write(" (const char *)0\n};\n") | ||
177 | end | ||
178 | |||
179 | ------------------------------------------------------------------------------ | ||
180 | |||
181 | -- Extern label name -> extern label number. With auto assignment on 1st use. | ||
182 | local next_extern = 0 | ||
183 | local map_extern_ = {} | ||
184 | local map_extern = setmetatable({}, { __index = function(t, name) | ||
185 | -- No restrictions on the name for now. | ||
186 | local n = next_extern | ||
187 | if n > 2047 then werror("too many extern labels") end | ||
188 | next_extern = n + 1 | ||
189 | t[name] = n | ||
190 | map_extern_[n] = name | ||
191 | return n | ||
192 | end}) | ||
193 | |||
194 | -- Dump extern labels. | ||
195 | local function dumpexterns(out, lvl) | ||
196 | out:write("Extern labels:\n") | ||
197 | for i=0,next_extern-1 do | ||
198 | out:write(format(" %s\n", map_extern_[i])) | ||
199 | end | ||
200 | out:write("\n") | ||
201 | end | ||
202 | |||
203 | -- Write extern label names. | ||
204 | local function writeexternnames(out, name) | ||
205 | out:write("static const char *const ", name, "[] = {\n") | ||
206 | for i=0,next_extern-1 do | ||
207 | out:write(" \"", map_extern_[i], "\",\n") | ||
208 | end | ||
209 | out:write(" (const char *)0\n};\n") | ||
210 | end | ||
211 | |||
212 | ------------------------------------------------------------------------------ | ||
213 | |||
214 | -- Arch-specific maps. | ||
215 | local map_archdef = { sp = "r1" } -- Ext. register name -> int. name. | ||
216 | |||
217 | local map_type = {} -- Type name -> { ctype, reg } | ||
218 | local ctypenum = 0 -- Type number (for Dt... macros). | ||
219 | |||
220 | -- Reverse defines for registers. | ||
221 | function _M.revdef(s) | ||
222 | if s == "r1" then return "sp" end | ||
223 | return s | ||
224 | end | ||
225 | |||
226 | local map_cond = { | ||
227 | lt = 0, gt = 1, eq = 2, so = 3, | ||
228 | ge = 4, le = 5, ne = 6, ns = 7, | ||
229 | } | ||
230 | |||
231 | ------------------------------------------------------------------------------ | ||
232 | |||
233 | -- Template strings for PPC instructions. | ||
234 | local map_op = { | ||
235 | tdi_3 = "08000000ARI", | ||
236 | twi_3 = "0c000000ARI", | ||
237 | mulli_3 = "1c000000RRI", | ||
238 | subfic_3 = "20000000RRI", | ||
239 | cmplwi_3 = "28000000XRU", | ||
240 | cmplwi_2 = "28000000-RU", | ||
241 | cmpldi_3 = "28200000XRU", | ||
242 | cmpldi_2 = "28200000-RU", | ||
243 | cmpwi_3 = "2c000000XRI", | ||
244 | cmpwi_2 = "2c000000-RI", | ||
245 | cmpdi_3 = "2c200000XRI", | ||
246 | cmpdi_2 = "2c200000-RI", | ||
247 | addic_3 = "30000000RRI", | ||
248 | ["addic._3"] = "34000000RRI", | ||
249 | addi_3 = "38000000RRI", | ||
250 | li_2 = "38000000RI", | ||
251 | addis_3 = "3c000000RRI", | ||
252 | lis_2 = "3c000000RI", | ||
253 | lus_2 = "3c000000RU", | ||
254 | la_2 = "3c000000RD", | ||
255 | bc_3 = "40000000AAK", | ||
256 | bcl_3 = "40000001AAK", | ||
257 | bdnz_1 = "42000000K", | ||
258 | bdz_1 = "42400000K", | ||
259 | sc_0 = "44000000", | ||
260 | b_1 = "48000000J", | ||
261 | bl_1 = "48000001J", | ||
262 | rlwimi_5 = "50000000RR~AAA.", | ||
263 | rlwinm_5 = "54000000RR~AAA.", | ||
264 | rlwnm_5 = "5c000000RR~RAA.", | ||
265 | ori_3 = "60000000RR~U", | ||
266 | nop_0 = "60000000", | ||
267 | oris_3 = "64000000RR~U", | ||
268 | xori_3 = "68000000RR~U", | ||
269 | xoris_3 = "6c000000RR~U", | ||
270 | ["andi._3"] = "70000000RR~U", | ||
271 | ["andis._3"] = "74000000RR~U", | ||
272 | lwz_2 = "80000000RD", | ||
273 | lwzu_2 = "84000000RD", | ||
274 | lbz_2 = "88000000RD", | ||
275 | lbzu_2 = "8c000000RD", | ||
276 | stw_2 = "90000000RD", | ||
277 | stwu_2 = "94000000RD", | ||
278 | stb_2 = "98000000RD", | ||
279 | stbu_2 = "9c000000RD", | ||
280 | lhz_2 = "a0000000RD", | ||
281 | lhzu_2 = "a4000000RD", | ||
282 | lha_2 = "a8000000RD", | ||
283 | lhau_2 = "ac000000RD", | ||
284 | sth_2 = "b0000000RD", | ||
285 | sthu_2 = "b4000000RD", | ||
286 | lmw_2 = "b8000000RD", | ||
287 | stmw_2 = "bc000000RD", | ||
288 | lfs_2 = "c0000000FD", | ||
289 | lfsu_2 = "c4000000FD", | ||
290 | lfd_2 = "c8000000FD", | ||
291 | lfdu_2 = "cc000000FD", | ||
292 | stfs_2 = "d0000000FD", | ||
293 | stfsu_2 = "d4000000FD", | ||
294 | stfd_2 = "d8000000FD", | ||
295 | stfdu_2 = "dc000000FD", | ||
296 | ld_2 = "e8000000RD", -- NYI: displacement must be divisible by 4. | ||
297 | ldu_2 = "e8000001RD", | ||
298 | lwa_2 = "e8000002RD", | ||
299 | std_2 = "f8000000RD", | ||
300 | stdu_2 = "f8000001RD", | ||
301 | |||
302 | -- Primary opcode 19: | ||
303 | mcrf_2 = "4c000000XX", | ||
304 | isync_0 = "4c00012c", | ||
305 | crnor_3 = "4c000042CCC", | ||
306 | crnot_2 = "4c000042CC=", | ||
307 | crandc_3 = "4c000102CCC", | ||
308 | crxor_3 = "4c000182CCC", | ||
309 | crclr_1 = "4c000182C==", | ||
310 | crnand_3 = "4c0001c2CCC", | ||
311 | crand_3 = "4c000202CCC", | ||
312 | creqv_3 = "4c000242CCC", | ||
313 | crset_1 = "4c000242C==", | ||
314 | crorc_3 = "4c000342CCC", | ||
315 | cror_3 = "4c000382CCC", | ||
316 | crmove_2 = "4c000382CC=", | ||
317 | bclr_2 = "4c000020AA", | ||
318 | bclrl_2 = "4c000021AA", | ||
319 | bcctr_2 = "4c000420AA", | ||
320 | bcctrl_2 = "4c000421AA", | ||
321 | blr_0 = "4e800020", | ||
322 | blrl_0 = "4e800021", | ||
323 | bctr_0 = "4e800420", | ||
324 | bctrl_0 = "4e800421", | ||
325 | |||
326 | -- Primary opcode 31: | ||
327 | cmpw_3 = "7c000000XRR", | ||
328 | cmpw_2 = "7c000000-RR", | ||
329 | cmpd_3 = "7c200000XRR", | ||
330 | cmpd_2 = "7c200000-RR", | ||
331 | tw_3 = "7c000008ARR", | ||
332 | subfc_3 = "7c000010RRR.", | ||
333 | subc_3 = "7c000010RRR~.", | ||
334 | mulhdu_3 = "7c000012RRR.", | ||
335 | addc_3 = "7c000014RRR.", | ||
336 | mulhwu_3 = "7c000016RRR.", | ||
337 | isel_4 = "7c00001eRRRC", | ||
338 | isellt_3 = "7c00001eRRR", | ||
339 | iselgt_3 = "7c00005eRRR", | ||
340 | iseleq_3 = "7c00009eRRR", | ||
341 | mfcr_1 = "7c000026R", | ||
342 | -- NYI: mtcrf, mtocrf, mfocrf | ||
343 | lwarx_3 = "7c000028RRR", | ||
344 | ldx_3 = "7c00002aRRR", | ||
345 | lwzx_3 = "7c00002eRRR", | ||
346 | slw_3 = "7c000030RR~R.", | ||
347 | cntlzw_2 = "7c000034RR~", | ||
348 | sld_3 = "7c000036RR~R.", | ||
349 | and_3 = "7c000038RR~R.", | ||
350 | cmplw_3 = "7c000040XRR", | ||
351 | cmplw_2 = "7c000040-RR", | ||
352 | cmpld_3 = "7c200040XRR", | ||
353 | cmpld_2 = "7c200040-RR", | ||
354 | subf_3 = "7c000050RRR.", | ||
355 | sub_3 = "7c000050RRR~.", | ||
356 | ldux_3 = "7c00006aRRR", | ||
357 | dcbst_2 = "7c00006c-RR", | ||
358 | lwzux_3 = "7c00006eRRR", | ||
359 | cntlzd_2 = "7c000074RR~", | ||
360 | andc_3 = "7c000078RR~R.", | ||
361 | td_3 = "7c000088ARR", | ||
362 | mulhd_3 = "7c000092RRR.", | ||
363 | mulhw_3 = "7c000096RRR.", | ||
364 | ldarx_3 = "7c0000a8RRR", | ||
365 | dcbf_2 = "7c0000ac-RR", | ||
366 | lbzx_3 = "7c0000aeRRR", | ||
367 | neg_2 = "7c0000d0RR.", | ||
368 | lbzux_3 = "7c0000eeRRR", | ||
369 | popcntb_2 = "7c0000f4RR~", | ||
370 | not_2 = "7c0000f8RR~%.", | ||
371 | nor_3 = "7c0000f8RR~R.", | ||
372 | subfe_3 = "7c000110RRR.", | ||
373 | adde_3 = "7c000114RRR.", | ||
374 | stdx_3 = "7c00012aRRR", | ||
375 | stwcx_3 = "7c00012cRRR.", | ||
376 | stwx_3 = "7c00012eRRR", | ||
377 | prtyw_2 = "7c000134RR~", | ||
378 | stdux_3 = "7c00016aRRR", | ||
379 | stwux_3 = "7c00016eRRR", | ||
380 | prtyd_2 = "7c000174RR~", | ||
381 | subfze_2 = "7c000190RR.", | ||
382 | addze_2 = "7c000194RR.", | ||
383 | stdcx_3 = "7c0001acRRR.", | ||
384 | stbx_3 = "7c0001aeRRR", | ||
385 | subfme_2 = "7c0001d0RR.", | ||
386 | mulld_3 = "7c0001d2RRR.", | ||
387 | addme_2 = "7c0001d4RR.", | ||
388 | mullw_3 = "7c0001d6RRR.", | ||
389 | dcbtst_2 = "7c0001ec-RR", | ||
390 | stbux_3 = "7c0001eeRRR", | ||
391 | add_3 = "7c000214RRR.", | ||
392 | dcbt_2 = "7c00022c-RR", | ||
393 | lhzx_3 = "7c00022eRRR", | ||
394 | eqv_3 = "7c000238RR~R.", | ||
395 | eciwx_3 = "7c00026cRRR", | ||
396 | lhzux_3 = "7c00026eRRR", | ||
397 | xor_3 = "7c000278RR~R.", | ||
398 | mfspefscr_1 = "7c0082a6R", | ||
399 | mfxer_1 = "7c0102a6R", | ||
400 | mflr_1 = "7c0802a6R", | ||
401 | mfctr_1 = "7c0902a6R", | ||
402 | lwax_3 = "7c0002aaRRR", | ||
403 | lhax_3 = "7c0002aeRRR", | ||
404 | mftb_1 = "7c0c42e6R", | ||
405 | mftbu_1 = "7c0d42e6R", | ||
406 | lwaux_3 = "7c0002eaRRR", | ||
407 | lhaux_3 = "7c0002eeRRR", | ||
408 | sthx_3 = "7c00032eRRR", | ||
409 | orc_3 = "7c000338RR~R.", | ||
410 | ecowx_3 = "7c00036cRRR", | ||
411 | sthux_3 = "7c00036eRRR", | ||
412 | or_3 = "7c000378RR~R.", | ||
413 | mr_2 = "7c000378RR~%.", | ||
414 | divdu_3 = "7c000392RRR.", | ||
415 | divwu_3 = "7c000396RRR.", | ||
416 | mtspefscr_1 = "7c0083a6R", | ||
417 | mtxer_1 = "7c0103a6R", | ||
418 | mtlr_1 = "7c0803a6R", | ||
419 | mtctr_1 = "7c0903a6R", | ||
420 | dcbi_2 = "7c0003ac-RR", | ||
421 | nand_3 = "7c0003b8RR~R.", | ||
422 | divd_3 = "7c0003d2RRR.", | ||
423 | divw_3 = "7c0003d6RRR.", | ||
424 | cmpb_3 = "7c0003f8RR~R.", | ||
425 | mcrxr_1 = "7c000400X", | ||
426 | subfco_3 = "7c000410RRR.", | ||
427 | addco_3 = "7c000414RRR.", | ||
428 | ldbrx_3 = "7c000428RRR", | ||
429 | lswx_3 = "7c00042aRRR", | ||
430 | lwbrx_3 = "7c00042cRRR", | ||
431 | lfsx_3 = "7c00042eFRR", | ||
432 | srw_3 = "7c000430RR~R.", | ||
433 | srd_3 = "7c000436RR~R.", | ||
434 | subfo_3 = "7c000450RRR.", | ||
435 | lfsux_3 = "7c00046eFRR", | ||
436 | lswi_3 = "7c0004aaRRA", | ||
437 | sync_0 = "7c0004ac", | ||
438 | lwsync_0 = "7c2004ac", | ||
439 | ptesync_0 = "7c4004ac", | ||
440 | lfdx_3 = "7c0004aeFRR", | ||
441 | nego_2 = "7c0004d0RR.", | ||
442 | lfdux_3 = "7c0004eeFRR", | ||
443 | subfeo_3 = "7c000510RRR.", | ||
444 | addeo_3 = "7c000514RRR.", | ||
445 | stdbrx_3 = "7c000528RRR", | ||
446 | stswx_3 = "7c00052aRRR", | ||
447 | stwbrx_3 = "7c00052cRRR", | ||
448 | stfsx_3 = "7c00052eFRR", | ||
449 | stfsux_3 = "7c00056eFRR", | ||
450 | subfzeo_2 = "7c000590RR.", | ||
451 | addzeo_2 = "7c000594RR.", | ||
452 | stswi_3 = "7c0005aaRRA", | ||
453 | stfdx_3 = "7c0005aeFRR", | ||
454 | subfmeo_2 = "7c0005d0RR.", | ||
455 | mulldo_3 = "7c0005d2RRR.", | ||
456 | addmeo_2 = "7c0005d4RR.", | ||
457 | mullwo_3 = "7c0005d6RRR.", | ||
458 | dcba_2 = "7c0005ec-RR", | ||
459 | stfdux_3 = "7c0005eeFRR", | ||
460 | addo_3 = "7c000614RRR.", | ||
461 | lhbrx_3 = "7c00062cRRR", | ||
462 | sraw_3 = "7c000630RR~R.", | ||
463 | srad_3 = "7c000634RR~R.", | ||
464 | srawi_3 = "7c000670RR~A.", | ||
465 | eieio_0 = "7c0006ac", | ||
466 | lfiwax_3 = "7c0006aeFRR", | ||
467 | sthbrx_3 = "7c00072cRRR", | ||
468 | extsh_2 = "7c000734RR~.", | ||
469 | extsb_2 = "7c000774RR~.", | ||
470 | divduo_3 = "7c000792RRR.", | ||
471 | divwou_3 = "7c000796RRR.", | ||
472 | icbi_2 = "7c0007ac-RR", | ||
473 | stfiwx_3 = "7c0007aeFRR", | ||
474 | extsw_2 = "7c0007b4RR~.", | ||
475 | divdo_3 = "7c0007d2RRR.", | ||
476 | divwo_3 = "7c0007d6RRR.", | ||
477 | dcbz_2 = "7c0007ec-RR", | ||
478 | |||
479 | -- Primary opcode 59: | ||
480 | fdivs_3 = "ec000024FFF.", | ||
481 | fsubs_3 = "ec000028FFF.", | ||
482 | fadds_3 = "ec00002aFFF.", | ||
483 | fsqrts_2 = "ec00002cF-F.", | ||
484 | fres_2 = "ec000030F-F.", | ||
485 | fmuls_3 = "ec000032FF-F.", | ||
486 | frsqrtes_2 = "ec000034F-F.", | ||
487 | fmsubs_4 = "ec000038FFFF~.", | ||
488 | fmadds_4 = "ec00003aFFFF~.", | ||
489 | fnmsubs_4 = "ec00003cFFFF~.", | ||
490 | fnmadds_4 = "ec00003eFFFF~.", | ||
491 | |||
492 | -- Primary opcode 63: | ||
493 | fdiv_3 = "fc000024FFF.", | ||
494 | fsub_3 = "fc000028FFF.", | ||
495 | fadd_3 = "fc00002aFFF.", | ||
496 | fsqrt_2 = "fc00002cF-F.", | ||
497 | fsel_4 = "fc00002eFFFF~.", | ||
498 | fre_2 = "fc000030F-F.", | ||
499 | fmul_3 = "fc000032FF-F.", | ||
500 | frsqrte_2 = "fc000034F-F.", | ||
501 | fmsub_4 = "fc000038FFFF~.", | ||
502 | fmadd_4 = "fc00003aFFFF~.", | ||
503 | fnmsub_4 = "fc00003cFFFF~.", | ||
504 | fnmadd_4 = "fc00003eFFFF~.", | ||
505 | fcmpu_3 = "fc000000XFF", | ||
506 | fcpsgn_3 = "fc000010FFF.", | ||
507 | fcmpo_3 = "fc000040XFF", | ||
508 | mtfsb1_1 = "fc00004cA", | ||
509 | fneg_2 = "fc000050F-F.", | ||
510 | mcrfs_2 = "fc000080XX", | ||
511 | mtfsb0_1 = "fc00008cA", | ||
512 | fmr_2 = "fc000090F-F.", | ||
513 | frsp_2 = "fc000018F-F.", | ||
514 | fctiw_2 = "fc00001cF-F.", | ||
515 | fctiwz_2 = "fc00001eF-F.", | ||
516 | mtfsfi_2 = "fc00010cAA", -- NYI: upshift. | ||
517 | fnabs_2 = "fc000110F-F.", | ||
518 | fabs_2 = "fc000210F-F.", | ||
519 | frin_2 = "fc000310F-F.", | ||
520 | friz_2 = "fc000350F-F.", | ||
521 | frip_2 = "fc000390F-F.", | ||
522 | frim_2 = "fc0003d0F-F.", | ||
523 | mffs_1 = "fc00048eF.", | ||
524 | mtfsf_1 = "fc00058eF.", | ||
525 | fctid_2 = "fc00065cF-F.", | ||
526 | fctidz_2 = "fc00065eF-F.", | ||
527 | fcfid_2 = "fc00069cF-F.", | ||
528 | |||
529 | -- NYI: some 64 bit PowerPC and Book E instructions: | ||
530 | -- rldicl, rldicr, rldic, rldimi, rldcl, rldcr, sradi, 64 bit ext. add/sub, | ||
531 | -- extended addressing branches, cache management, loads and stores | ||
532 | } | ||
533 | |||
534 | -- Add mnemonics for "." variants. | ||
535 | do | ||
536 | local t = {} | ||
537 | for k,v in pairs(map_op) do | ||
538 | if sub(v, -1) == "." then | ||
539 | local v2 = sub(v, 1, 7)..char(byte(v, 8)+1)..sub(v, 9, -2) | ||
540 | t[sub(k, 1, -3).."."..sub(k, -2)] = v2 | ||
541 | end | ||
542 | end | ||
543 | for k,v in pairs(t) do | ||
544 | map_op[k] = v | ||
545 | end | ||
546 | end | ||
547 | |||
548 | -- Add more branch mnemonics. | ||
549 | for cond,c in pairs(map_cond) do | ||
550 | local b1 = "b"..cond | ||
551 | local c1 = (c%4)*0x00010000 + (c < 4 and 0x01000000 or 0) | ||
552 | -- bX | ||
553 | map_op[b1.."_1"] = tohex(0x40800000 + c1).."K" | ||
554 | map_op[b1.."_2"] = tohex(0x40800000 + c1).."-XK" | ||
555 | -- bXlr[l] | ||
556 | map_op[b1.."lr".."_0"] = tohex(0x4c800020 + c1) | ||
557 | map_op[b1.."lrl".."_0"] = tohex(0x4c800021 + c1) | ||
558 | map_op[b1.."ctr".."_0"] = tohex(0x4c800420 + c1) | ||
559 | map_op[b1.."ctrl".."_0"] = tohex(0x4c800421 + c1) | ||
560 | -- bXctr[l] | ||
561 | map_op[b1.."lr".."_1"] = tohex(0x4c800020 + c1).."-X" | ||
562 | map_op[b1.."lrl".."_1"] = tohex(0x4c800021 + c1).."-X" | ||
563 | map_op[b1.."ctr".."_1"] = tohex(0x4c800420 + c1).."-X" | ||
564 | map_op[b1.."ctrl".."_1"] = tohex(0x4c800421 + c1).."-X" | ||
565 | end | ||
566 | |||
567 | ------------------------------------------------------------------------------ | ||
568 | |||
569 | local function parse_gpr(expr) | ||
570 | local tname, ovreg = match(expr, "^([%w_]+):(r[0-9][0-9]?)$") | ||
571 | local tp = map_type[tname or expr] | ||
572 | if tp then | ||
573 | local reg = ovreg or tp.reg | ||
574 | if not reg then | ||
575 | werror("type `"..(tname or expr).."' needs a register override") | ||
576 | end | ||
577 | expr = reg | ||
578 | end | ||
579 | local r = match(expr, "^r([1-3]?[0-9])$") | ||
580 | if r then | ||
581 | r = tonumber(r) | ||
582 | if r <= 31 then return r, tp end | ||
583 | end | ||
584 | werror("bad register name `"..expr.."'") | ||
585 | end | ||
586 | |||
587 | local function parse_fpr(expr) | ||
588 | local r = match(expr, "^f([1-3]?[0-9])$") | ||
589 | if r then | ||
590 | r = tonumber(r) | ||
591 | if r <= 31 then return r end | ||
592 | end | ||
593 | werror("bad register name `"..expr.."'") | ||
594 | end | ||
595 | |||
596 | local function parse_cr(expr) | ||
597 | local r = match(expr, "^cr([0-7])$") | ||
598 | if r then return tonumber(r) end | ||
599 | werror("bad condition register name `"..expr.."'") | ||
600 | end | ||
601 | |||
602 | local function parse_cond(expr) | ||
603 | local r, cond = match(expr, "^4%*cr([0-7])%+(%w%w)$") | ||
604 | if r then | ||
605 | r = tonumber(r) | ||
606 | local c = map_cond[cond] | ||
607 | if c and c < 4 then return r*4+c end | ||
608 | end | ||
609 | werror("bad condition bit name `"..expr.."'") | ||
610 | end | ||
611 | |||
612 | local function parse_imm(imm, bits, shift, scale, signed) | ||
613 | local n = tonumber(imm) | ||
614 | if n then | ||
615 | if n % 2^scale == 0 then | ||
616 | n = n / 2^scale | ||
617 | if signed then | ||
618 | if n >= 0 then | ||
619 | if n < 2^(bits-1) then return n*2^shift end | ||
620 | else | ||
621 | if n >= -(2^(bits-1))-1 then return (n+2^bits)*2^shift end | ||
622 | end | ||
623 | else | ||
624 | if n >= 0 and n <= 2^bits-1 then return n*2^shift end | ||
625 | end | ||
626 | end | ||
627 | werror("out of range immediate `"..imm.."'") | ||
628 | else | ||
629 | waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm) | ||
630 | return 0 | ||
631 | end | ||
632 | end | ||
633 | |||
634 | local function parse_disp(disp) | ||
635 | local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$") | ||
636 | if imm then | ||
637 | local r = parse_gpr(reg) | ||
638 | if r == 0 then werror("cannot use r0 in displacement") end | ||
639 | return r*65536 + parse_imm(imm, 16, 0, 0, true) | ||
640 | end | ||
641 | local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$") | ||
642 | if reg and tailr ~= "" then | ||
643 | local r, tp = parse_gpr(reg) | ||
644 | if r == 0 then werror("cannot use r0 in displacement") end | ||
645 | if tp then | ||
646 | waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr)) | ||
647 | return r*65536 | ||
648 | end | ||
649 | end | ||
650 | werror("bad displacement `"..disp.."'") | ||
651 | end | ||
652 | |||
653 | local function parse_u5disp(disp, scale) | ||
654 | local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$") | ||
655 | if imm then | ||
656 | local r = parse_gpr(reg) | ||
657 | if r == 0 then werror("cannot use r0 in displacement") end | ||
658 | return r*65536 + parse_imm(imm, 5, 11, scale, false) | ||
659 | end | ||
660 | local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$") | ||
661 | if reg and tailr ~= "" then | ||
662 | local r, tp = parse_gpr(reg) | ||
663 | if r == 0 then werror("cannot use r0 in displacement") end | ||
664 | if tp then | ||
665 | waction("IMM", scale*1024+5*32+11, format(tp.ctypefmt, tailr)) | ||
666 | return r*65536 | ||
667 | end | ||
668 | end | ||
669 | werror("bad displacement `"..disp.."'") | ||
670 | end | ||
671 | |||
672 | local function parse_label(label, def) | ||
673 | local prefix = sub(label, 1, 2) | ||
674 | -- =>label (pc label reference) | ||
675 | if prefix == "=>" then | ||
676 | return "PC", 0, sub(label, 3) | ||
677 | end | ||
678 | -- ->name (global label reference) | ||
679 | if prefix == "->" then | ||
680 | return "LG", map_global[sub(label, 3)] | ||
681 | end | ||
682 | if def then | ||
683 | -- [1-9] (local label definition) | ||
684 | if match(label, "^[1-9]$") then | ||
685 | return "LG", 10+tonumber(label) | ||
686 | end | ||
687 | else | ||
688 | -- [<>][1-9] (local label reference) | ||
689 | local dir, lnum = match(label, "^([<>])([1-9])$") | ||
690 | if dir then -- Fwd: 1-9, Bkwd: 11-19. | ||
691 | return "LG", lnum + (dir == ">" and 0 or 10) | ||
692 | end | ||
693 | -- extern label (extern label reference) | ||
694 | local extname = match(label, "^extern%s+(%S+)$") | ||
695 | if extname then | ||
696 | return "EXT", map_extern[extname] | ||
697 | end | ||
698 | end | ||
699 | werror("bad label `"..label.."'") | ||
700 | end | ||
701 | |||
702 | ------------------------------------------------------------------------------ | ||
703 | |||
704 | -- Handle opcodes defined with template strings. | ||
705 | map_op[".template__"] = function(params, template, nparams) | ||
706 | if not params then return sub(template, 9) end | ||
707 | local op = tonumber(sub(template, 1, 8), 16) | ||
708 | local n, rs = 1, 26 | ||
709 | |||
710 | -- Limit number of section buffer positions used by a single dasm_put(). | ||
711 | -- A single opcode needs a maximum of 3 positions (rlwinm). | ||
712 | if secpos+3 > maxsecpos then wflush() end | ||
713 | local pos = wpos() | ||
714 | |||
715 | -- Process each character. | ||
716 | for p in gmatch(sub(template, 9), ".") do | ||
717 | if p == "R" then | ||
718 | rs = rs - 5; op = op + parse_gpr(params[n]) * 2^rs; n = n + 1 | ||
719 | elseif p == "F" then | ||
720 | rs = rs - 5; op = op + parse_fpr(params[n]) * 2^rs; n = n + 1 | ||
721 | elseif p == "A" then | ||
722 | rs = rs - 5; op = op + parse_imm(params[n], 5, rs, 0, false); n = n + 1 | ||
723 | elseif p == "I" then | ||
724 | op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1 | ||
725 | elseif p == "U" then | ||
726 | op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1 | ||
727 | elseif p == "D" then | ||
728 | op = op + parse_disp(params[n]); n = n + 1 | ||
729 | elseif p == "C" then | ||
730 | rs = rs - 5; op = op + parse_cond(params[n]) * 2^rs; n = n + 1 | ||
731 | elseif p == "X" then | ||
732 | rs = rs - 5; op = op + parse_cr(params[n]) * 2^(rs+2); n = n + 1 | ||
733 | elseif p == "J" or p == "K" then | ||
734 | local mode, n, s = parse_label(params[n], false) | ||
735 | if p == "K" then n = n + 2048 end | ||
736 | waction("REL_"..mode, n, s, 1) | ||
737 | n = n + 1 | ||
738 | elseif p == "=" or p == "%" then | ||
739 | local mm = 2^(rs + (p == "%" and 5 or 0)) | ||
740 | local t = ((op - op % mm) / mm) % 32 | ||
741 | rs = rs - 5 | ||
742 | op = op + t * 2^rs | ||
743 | elseif p == "~" then | ||
744 | local mm = 2^rs | ||
745 | local t1l = op % mm | ||
746 | local t1h = (op - t1l) / mm | ||
747 | local t2l = t1h % 32 | ||
748 | local t2h = (t1h - t2l) / 32 | ||
749 | local t3l = t2h % 32 | ||
750 | op = ((t2h - t3l + t2l)*32 + t3l)*mm + t1l | ||
751 | elseif p == "-" then | ||
752 | rs = rs - 5 | ||
753 | elseif p == "." then | ||
754 | -- Ignored. | ||
755 | else | ||
756 | assert(false) | ||
757 | end | ||
758 | end | ||
759 | wputpos(pos, op) | ||
760 | end | ||
761 | |||
762 | ------------------------------------------------------------------------------ | ||
763 | |||
764 | -- Pseudo-opcode to mark the position where the action list is to be emitted. | ||
765 | map_op[".actionlist_1"] = function(params) | ||
766 | if not params then return "cvar" end | ||
767 | local name = params[1] -- No syntax check. You get to keep the pieces. | ||
768 | wline(function(out) writeactions(out, name) end) | ||
769 | end | ||
770 | |||
771 | -- Pseudo-opcode to mark the position where the global enum is to be emitted. | ||
772 | map_op[".globals_1"] = function(params) | ||
773 | if not params then return "prefix" end | ||
774 | local prefix = params[1] -- No syntax check. You get to keep the pieces. | ||
775 | wline(function(out) writeglobals(out, prefix) end) | ||
776 | end | ||
777 | |||
778 | -- Pseudo-opcode to mark the position where the global names are to be emitted. | ||
779 | map_op[".globalnames_1"] = function(params) | ||
780 | if not params then return "cvar" end | ||
781 | local name = params[1] -- No syntax check. You get to keep the pieces. | ||
782 | wline(function(out) writeglobalnames(out, name) end) | ||
783 | end | ||
784 | |||
785 | -- Pseudo-opcode to mark the position where the extern names are to be emitted. | ||
786 | map_op[".externnames_1"] = function(params) | ||
787 | if not params then return "cvar" end | ||
788 | local name = params[1] -- No syntax check. You get to keep the pieces. | ||
789 | wline(function(out) writeexternnames(out, name) end) | ||
790 | end | ||
791 | |||
792 | ------------------------------------------------------------------------------ | ||
793 | |||
794 | -- Label pseudo-opcode (converted from trailing colon form). | ||
795 | map_op[".label_1"] = function(params) | ||
796 | if not params then return "[1-9] | ->global | =>pcexpr" end | ||
797 | if secpos+1 > maxsecpos then wflush() end | ||
798 | local mode, n, s = parse_label(params[1], true) | ||
799 | if mode == "EXT" then werror("bad label definition") end | ||
800 | waction("LABEL_"..mode, n, s, 1) | ||
801 | end | ||
802 | |||
803 | ------------------------------------------------------------------------------ | ||
804 | |||
805 | -- Pseudo-opcodes for data storage. | ||
806 | map_op[".long_*"] = function(params) | ||
807 | if not params then return "imm..." end | ||
808 | for _,p in ipairs(params) do | ||
809 | local n = tonumber(p) | ||
810 | if not n then werror("bad immediate `"..p.."'") end | ||
811 | if n < 0 then n = n + 2^32 end | ||
812 | wputw(n) | ||
813 | if secpos+2 > maxsecpos then wflush() end | ||
814 | end | ||
815 | end | ||
816 | |||
817 | -- Alignment pseudo-opcode. | ||
818 | map_op[".align_1"] = function(params) | ||
819 | if not params then return "numpow2" end | ||
820 | if secpos+1 > maxsecpos then wflush() end | ||
821 | local align = tonumber(params[1]) | ||
822 | if align then | ||
823 | local x = align | ||
824 | -- Must be a power of 2 in the range (2 ... 256). | ||
825 | for i=1,8 do | ||
826 | x = x / 2 | ||
827 | if x == 1 then | ||
828 | waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. | ||
829 | return | ||
830 | end | ||
831 | end | ||
832 | end | ||
833 | werror("bad alignment") | ||
834 | end | ||
835 | |||
836 | ------------------------------------------------------------------------------ | ||
837 | |||
838 | -- Pseudo-opcode for (primitive) type definitions (map to C types). | ||
839 | map_op[".type_3"] = function(params, nparams) | ||
840 | if not params then | ||
841 | return nparams == 2 and "name, ctype" or "name, ctype, reg" | ||
842 | end | ||
843 | local name, ctype, reg = params[1], params[2], params[3] | ||
844 | if not match(name, "^[%a_][%w_]*$") then | ||
845 | werror("bad type name `"..name.."'") | ||
846 | end | ||
847 | local tp = map_type[name] | ||
848 | if tp then | ||
849 | werror("duplicate type `"..name.."'") | ||
850 | end | ||
851 | -- Add #type to defines. A bit unclean to put it in map_archdef. | ||
852 | map_archdef["#"..name] = "sizeof("..ctype..")" | ||
853 | -- Add new type and emit shortcut define. | ||
854 | local num = ctypenum + 1 | ||
855 | map_type[name] = { | ||
856 | ctype = ctype, | ||
857 | ctypefmt = format("Dt%X(%%s)", num), | ||
858 | reg = reg, | ||
859 | } | ||
860 | wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) | ||
861 | ctypenum = num | ||
862 | end | ||
863 | map_op[".type_2"] = map_op[".type_3"] | ||
864 | |||
865 | -- Dump type definitions. | ||
866 | local function dumptypes(out, lvl) | ||
867 | local t = {} | ||
868 | for name in pairs(map_type) do t[#t+1] = name end | ||
869 | sort(t) | ||
870 | out:write("Type definitions:\n") | ||
871 | for _,name in ipairs(t) do | ||
872 | local tp = map_type[name] | ||
873 | local reg = tp.reg or "" | ||
874 | out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) | ||
875 | end | ||
876 | out:write("\n") | ||
877 | end | ||
878 | |||
879 | ------------------------------------------------------------------------------ | ||
880 | |||
881 | -- Set the current section. | ||
882 | function _M.section(num) | ||
883 | waction("SECTION", num) | ||
884 | wflush(true) -- SECTION is a terminal action. | ||
885 | end | ||
886 | |||
887 | ------------------------------------------------------------------------------ | ||
888 | |||
889 | -- Dump architecture description. | ||
890 | function _M.dumparch(out) | ||
891 | out:write(format("DynASM %s version %s, released %s\n\n", | ||
892 | _info.arch, _info.version, _info.release)) | ||
893 | dumpactions(out) | ||
894 | end | ||
895 | |||
896 | -- Dump all user defined elements. | ||
897 | function _M.dumpdef(out, lvl) | ||
898 | dumptypes(out, lvl) | ||
899 | dumpglobals(out, lvl) | ||
900 | dumpexterns(out, lvl) | ||
901 | end | ||
902 | |||
903 | ------------------------------------------------------------------------------ | ||
904 | |||
905 | -- Pass callbacks from/to the DynASM core. | ||
906 | function _M.passcb(wl, we, wf, ww) | ||
907 | wline, werror, wfatal, wwarn = wl, we, wf, ww | ||
908 | return wflush | ||
909 | end | ||
910 | |||
911 | -- Setup the arch-specific module. | ||
912 | function _M.setup(arch, opt) | ||
913 | g_arch, g_opt = arch, opt | ||
914 | end | ||
915 | |||
916 | -- Merge the core maps and the arch-specific maps. | ||
917 | function _M.mergemaps(map_coreop, map_def) | ||
918 | setmetatable(map_op, { __index = map_coreop }) | ||
919 | setmetatable(map_def, { __index = map_archdef }) | ||
920 | return map_op, map_def | ||
921 | end | ||
922 | |||
923 | return _M | ||
924 | |||
925 | ------------------------------------------------------------------------------ | ||
926 | |||