diff options
author | Mike Pall <mike> | 2011-12-16 21:33:40 +0100 |
---|---|---|
committer | Mike Pall <mike> | 2011-12-16 21:33:40 +0100 |
commit | ba4917b71bba55e61f4ce644100cdb4e114ccfc5 (patch) | |
tree | 0d01ba2a34eeb138004cf7c7e3a8df86f4813eb3 /dynasm/dasm_mips.lua | |
parent | b330b468b3f37bd0b11765524548dbdbb1dd1a95 (diff) | |
download | luajit-ba4917b71bba55e61f4ce644100cdb4e114ccfc5.tar.gz luajit-ba4917b71bba55e61f4ce644100cdb4e114ccfc5.tar.bz2 luajit-ba4917b71bba55e61f4ce644100cdb4e114ccfc5.zip |
MIPS: Add DynASM MIPS module and encoding engine.
Diffstat (limited to '')
-rw-r--r-- | dynasm/dasm_mips.lua | 948 |
1 files changed, 948 insertions, 0 deletions
diff --git a/dynasm/dasm_mips.lua b/dynasm/dasm_mips.lua new file mode 100644 index 00000000..5cbae8ba --- /dev/null +++ b/dynasm/dasm_mips.lua | |||
@@ -0,0 +1,948 @@ | |||
1 | ------------------------------------------------------------------------------ | ||
2 | -- DynASM MIPS module. | ||
3 | -- | ||
4 | -- Copyright (C) 2005-2011 Mike Pall. All rights reserved. | ||
5 | -- See dynasm.lua for full copyright notice. | ||
6 | ------------------------------------------------------------------------------ | ||
7 | |||
8 | -- Module information: | ||
9 | local _info = { | ||
10 | arch = "mips", | ||
11 | description = "DynASM MIPS module", | ||
12 | version = "1.3.0", | ||
13 | vernum = 10300, | ||
14 | release = "2011-12-16", | ||
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(0xff000000 + 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 >= 0xff000000 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="r29", ra="r31" } -- 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 == "r29" then return "sp" | ||
223 | elseif s == "r31" then return "ra" end | ||
224 | return s | ||
225 | end | ||
226 | |||
227 | ------------------------------------------------------------------------------ | ||
228 | |||
229 | -- Template strings for MIPS instructions. | ||
230 | local map_op = { | ||
231 | -- First-level opcodes. | ||
232 | j_1 = "08000000J", | ||
233 | jal_1 = "0c000000J", | ||
234 | b_1 = "10000000B", | ||
235 | beqz_2 = "10000000SB", | ||
236 | beq_3 = "10000000STB", | ||
237 | bnez_2 = "14000000SB", | ||
238 | bne_3 = "14000000STB", | ||
239 | blez_2 = "18000000SB", | ||
240 | bgtz_2 = "1c000000SB", | ||
241 | addi_3 = "20000000TSI", | ||
242 | li_2 = "24000000TI", | ||
243 | addiu_3 = "24000000TSI", | ||
244 | slti_3 = "28000000TSI", | ||
245 | sltiu_3 = "2c000000TSI", | ||
246 | andi_3 = "30000000TSU", | ||
247 | lu_2 = "34000000TU", | ||
248 | ori_3 = "34000000TSU", | ||
249 | xori_3 = "38000000TSU", | ||
250 | lui_2 = "3c000000TU", | ||
251 | beqzl_2 = "50000000SB", | ||
252 | beql_3 = "50000000STB", | ||
253 | bnezl_2 = "54000000SB", | ||
254 | bnel_3 = "54000000STB", | ||
255 | blezl_2 = "58000000SB", | ||
256 | bgtzl_2 = "5c000000SB", | ||
257 | lb_2 = "80000000TO", | ||
258 | lh_2 = "84000000TO", | ||
259 | lwl_2 = "88000000TO", | ||
260 | lw_2 = "8c000000TO", | ||
261 | lbu_2 = "90000000TO", | ||
262 | lhu_2 = "94000000TO", | ||
263 | lwr_2 = "98000000TO", | ||
264 | sb_2 = "a0000000TO", | ||
265 | sh_2 = "a4000000TO", | ||
266 | swl_2 = "a8000000TO", | ||
267 | sw_2 = "ac000000TO", | ||
268 | swr_2 = "b8000000TO", | ||
269 | cache_2 = "bc000000NO", | ||
270 | ll_2 = "c0000000TO", | ||
271 | lwc1_2 = "c4000000HO", | ||
272 | pref_2 = "cc000000NO", | ||
273 | ldc1_2 = "d4000000HO", | ||
274 | sc_2 = "e0000000TO", | ||
275 | swc1_2 = "e4000000HO", | ||
276 | sdc1_2 = "f4000000HO", | ||
277 | |||
278 | -- Opcode SPECIAL. | ||
279 | nop_0 = "00000000", | ||
280 | sll_3 = "00000000DTA", | ||
281 | movf_3 = "00000001DSC", | ||
282 | movt_3 = "00010001DSC", | ||
283 | srl_3 = "00000002DTA", | ||
284 | rotr_3 = "00200002DTA", | ||
285 | sra_3 = "00000003DTA", | ||
286 | sllv_3 = "00000004DTS", | ||
287 | srlv_3 = "00000006DTS", | ||
288 | rotrv_3 = "00000046DTS", | ||
289 | srav_3 = "00000007DTS", | ||
290 | jr_1 = "00000008S", | ||
291 | jalr_1 = "0000f809S", | ||
292 | jalr_2 = "00000009DS", | ||
293 | movz_3 = "0000000aDST", | ||
294 | movn_3 = "0000000bDST", | ||
295 | syscall_0 = "0000000c", | ||
296 | syscall_1 = "0000000cY", | ||
297 | break_0 = "0000000d", | ||
298 | break_1 = "0000000dY", | ||
299 | sync_0 = "0000000f", | ||
300 | mfhi_1 = "00000010D", | ||
301 | mthi_1 = "00000011S", | ||
302 | mflo_1 = "00000012D", | ||
303 | mtlo_1 = "00000013S", | ||
304 | mult_2 = "00000018ST", | ||
305 | multu_2 = "00000019ST", | ||
306 | div_2 = "0000001aST", | ||
307 | divu_2 = "0000001bST", | ||
308 | add_3 = "00000020DST", | ||
309 | move_2 = "00000021DS", | ||
310 | addu_3 = "00000021DST", | ||
311 | sub_3 = "00000022DST", | ||
312 | subu_3 = "00000023DST", | ||
313 | and_3 = "00000024DST", | ||
314 | or_3 = "00000025DST", | ||
315 | xor_3 = "00000026DST", | ||
316 | nor_3 = "00000027DST", | ||
317 | slt_3 = "0000002aDST", | ||
318 | sltu_3 = "0000002bDST", | ||
319 | tge_2 = "00000030ST", | ||
320 | tge_3 = "00000030STZ", | ||
321 | tgeu_2 = "00000031ST", | ||
322 | tgeu_3 = "00000031STZ", | ||
323 | tlt_2 = "00000032ST", | ||
324 | tlt_3 = "00000032STZ", | ||
325 | tltu_2 = "00000033ST", | ||
326 | tltu_3 = "00000033STZ", | ||
327 | teq_2 = "00000034ST", | ||
328 | teq_3 = "00000034STZ", | ||
329 | tne_2 = "00000036ST", | ||
330 | tne_3 = "00000036STZ", | ||
331 | |||
332 | -- Opcode REGIMM. | ||
333 | bltz_2 = "04000000SB", | ||
334 | bgez_2 = "04010000SB", | ||
335 | bltzl_2 = "04020000SB", | ||
336 | bgezl_2 = "04030000SB", | ||
337 | tgei_2 = "04080000SI", | ||
338 | tgeiu_2 = "04090000SI", | ||
339 | tlti_2 = "040a0000SI", | ||
340 | tltiu_2 = "040b0000SI", | ||
341 | teqi_2 = "040c0000SI", | ||
342 | tnei_2 = "040e0000SI", | ||
343 | bltzal_2 = "04100000SB", | ||
344 | bgezal_2 = "04110000SB", | ||
345 | bltzall_2 = "04120000SB", | ||
346 | bgezall_2 = "04130000SB", | ||
347 | synci_1 = "041f0000O", | ||
348 | |||
349 | -- Opcode SPECIAL2. | ||
350 | madd_2 = "70000000ST", | ||
351 | maddu_2 = "70000001ST", | ||
352 | mul_3 = "70000002DST", | ||
353 | msub_2 = "70000004ST", | ||
354 | msubu_2 = "70000005ST", | ||
355 | clz_2 = "70000020DS=", | ||
356 | clo_2 = "70000021DS=", | ||
357 | sdbbp_0 = "7000003f", | ||
358 | sdbbp_1 = "7000003fY", | ||
359 | |||
360 | -- Opcode SPECIAL3. | ||
361 | ext_4 = "7c000000TSAM", -- Note: last arg is msbd = size-1 | ||
362 | ins_4 = "7c000004TSAM", -- Note: last arg is msb = pos+size-1 | ||
363 | wsbh_2 = "7c0000a0DT", | ||
364 | seb_2 = "7c000420DT", | ||
365 | seh_2 = "7c000620DT", | ||
366 | rdhwr_2 = "7c00003bTD", | ||
367 | |||
368 | -- Opcode COP0. | ||
369 | mfc0_2 = "40000000TD", | ||
370 | mfc0_3 = "40000000TDW", | ||
371 | mtc0_2 = "40800000TD", | ||
372 | mtc0_3 = "40800000TDW", | ||
373 | rdpgpr_2 = "41400000DT", | ||
374 | di_0 = "41606000", | ||
375 | di_1 = "41606000T", | ||
376 | ei_0 = "41606020", | ||
377 | ei_1 = "41606020T", | ||
378 | wrpgpr_2 = "41c00000DT", | ||
379 | tlbr_0 = "42000001", | ||
380 | tlbwi_0 = "42000002", | ||
381 | tlbwr_0 = "42000006", | ||
382 | tlbp_0 = "42000008", | ||
383 | eret_0 = "42000018", | ||
384 | deret_0 = "4200001f", | ||
385 | wait_0 = "42000020", | ||
386 | |||
387 | -- Opcode COP1. | ||
388 | mfc1_2 = "44000000TG", | ||
389 | cfc1_2 = "44400000TG", | ||
390 | mfhc1_2 = "44600000TG", | ||
391 | mtc1_2 = "44800000TG", | ||
392 | ctc1_2 = "44c00000TG", | ||
393 | mthc1_2 = "44e00000TG", | ||
394 | |||
395 | bc1f_1 = "45000000B", | ||
396 | bc1f_2 = "45000000CB", | ||
397 | bc1t_1 = "45010000B", | ||
398 | bc1t_2 = "45010000CB", | ||
399 | bc1fl_1 = "45020000B", | ||
400 | bc1fl_2 = "45020000CB", | ||
401 | bc1tl_1 = "45030000B", | ||
402 | bc1tl_2 = "45030000CB", | ||
403 | |||
404 | ["add.s_3"] = "46000000FGH", | ||
405 | ["sub.s_3"] = "46000001FGH", | ||
406 | ["mul.s_3"] = "46000002FGH", | ||
407 | ["div.s_3"] = "46000003FGH", | ||
408 | ["sqrt.s_2"] = "46000004FG", | ||
409 | ["abs.s_2"] = "46000005FG", | ||
410 | ["mov.s_2"] = "46000006FG", | ||
411 | ["neg.s_2"] = "46000007FG", | ||
412 | ["round.l.s_2"] = "46000008FG", | ||
413 | ["trunc.l.s_2"] = "46000009FG", | ||
414 | ["ceil.l.s_2"] = "4600000aFG", | ||
415 | ["floor.l.s_2"] = "4600000bFG", | ||
416 | ["round.w.s_2"] = "4600000cFG", | ||
417 | ["trunc.w.s_2"] = "4600000dFG", | ||
418 | ["ceil.w.s_2"] = "4600000eFG", | ||
419 | ["floor.w.s_2"] = "4600000fFG", | ||
420 | ["movf.s_2"] = "46000011FG", | ||
421 | ["movf.s_3"] = "46000011FGC", | ||
422 | ["movt.s_2"] = "46010011FG", | ||
423 | ["movt.s_3"] = "46010011FGC", | ||
424 | ["movz.s_3"] = "46000012FGT", | ||
425 | ["movn.s_3"] = "46000013FGT", | ||
426 | ["recip.s_2"] = "46000015FG", | ||
427 | ["rsqrt.s_2"] = "46000016FG", | ||
428 | ["cvt.d.s_2"] = "46000021FG", | ||
429 | ["cvt.w.s_2"] = "46000024FG", | ||
430 | ["cvt.l.s_2"] = "46000025FG", | ||
431 | ["cvt.ps.s_3"] = "46000026FGH", | ||
432 | ["c.f.s_2"] = "46000030GH", | ||
433 | ["c.f.s_3"] = "46000030VGH", | ||
434 | ["c.un.s_2"] = "46000031GH", | ||
435 | ["c.un.s_3"] = "46000031VGH", | ||
436 | ["c.eq.s_2"] = "46000032GH", | ||
437 | ["c.eq.s_3"] = "46000032VGH", | ||
438 | ["c.ueq.s_2"] = "46000033GH", | ||
439 | ["c.ueq.s_3"] = "46000033VGH", | ||
440 | ["c.olt.s_2"] = "46000034GH", | ||
441 | ["c.olt.s_3"] = "46000034VGH", | ||
442 | ["c.ult.s_2"] = "46000035GH", | ||
443 | ["c.ult.s_3"] = "46000035VGH", | ||
444 | ["c.ole.s_2"] = "46000036GH", | ||
445 | ["c.ole.s_3"] = "46000036VGH", | ||
446 | ["c.ule.s_2"] = "46000037GH", | ||
447 | ["c.ule.s_3"] = "46000037VGH", | ||
448 | ["c.sf.s_2"] = "46000038GH", | ||
449 | ["c.sf.s_3"] = "46000038VGH", | ||
450 | ["c.ngle.s_2"] = "46000039GH", | ||
451 | ["c.ngle.s_3"] = "46000039VGH", | ||
452 | ["c.seq.s_2"] = "4600003aGH", | ||
453 | ["c.seq.s_3"] = "4600003aVGH", | ||
454 | ["c.ngl.s_2"] = "4600003bGH", | ||
455 | ["c.ngl.s_3"] = "4600003bVGH", | ||
456 | ["c.lt.s_2"] = "4600003cGH", | ||
457 | ["c.lt.s_3"] = "4600003cVGH", | ||
458 | ["c.nge.s_2"] = "4600003dGH", | ||
459 | ["c.nge.s_3"] = "4600003dVGH", | ||
460 | ["c.le.s_2"] = "4600003eGH", | ||
461 | ["c.le.s_3"] = "4600003eVGH", | ||
462 | ["c.ngt.s_2"] = "4600003fGH", | ||
463 | ["c.ngt.s_3"] = "4600003fVGH", | ||
464 | |||
465 | ["add.d_3"] = "46200000FGH", | ||
466 | ["sub.d_3"] = "46200001FGH", | ||
467 | ["mul.d_3"] = "46200002FGH", | ||
468 | ["div.d_3"] = "46200003FGH", | ||
469 | ["sqrt.d_2"] = "46200004FG", | ||
470 | ["abs.d_2"] = "46200005FG", | ||
471 | ["mov.d_2"] = "46200006FG", | ||
472 | ["neg.d_2"] = "46200007FG", | ||
473 | ["round.l.d_2"] = "46200008FG", | ||
474 | ["trunc.l.d_2"] = "46200009FG", | ||
475 | ["ceil.l.d_2"] = "4620000aFG", | ||
476 | ["floor.l.d_2"] = "4620000bFG", | ||
477 | ["round.w.d_2"] = "4620000cFG", | ||
478 | ["trunc.w.d_2"] = "4620000dFG", | ||
479 | ["ceil.w.d_2"] = "4620000eFG", | ||
480 | ["floor.w.d_2"] = "4620000fFG", | ||
481 | ["movf.d_2"] = "46200011FG", | ||
482 | ["movf.d_3"] = "46200011FGC", | ||
483 | ["movt.d_2"] = "46210011FG", | ||
484 | ["movt.d_3"] = "46210011FGC", | ||
485 | ["movz.d_3"] = "46200012FGT", | ||
486 | ["movn.d_3"] = "46200013FGT", | ||
487 | ["recip.d_2"] = "46200015FG", | ||
488 | ["rsqrt.d_2"] = "46200016FG", | ||
489 | ["cvt.s.d_2"] = "46200020FG", | ||
490 | ["cvt.w.d_2"] = "46200024FG", | ||
491 | ["cvt.l.d_2"] = "46200025FG", | ||
492 | ["c.f.d_2"] = "46200030GH", | ||
493 | ["c.f.d_3"] = "46200030VGH", | ||
494 | ["c.un.d_2"] = "46200031GH", | ||
495 | ["c.un.d_3"] = "46200031VGH", | ||
496 | ["c.eq.d_2"] = "46200032GH", | ||
497 | ["c.eq.d_3"] = "46200032VGH", | ||
498 | ["c.ueq.d_2"] = "46200033GH", | ||
499 | ["c.ueq.d_3"] = "46200033VGH", | ||
500 | ["c.olt.d_2"] = "46200034GH", | ||
501 | ["c.olt.d_3"] = "46200034VGH", | ||
502 | ["c.ult.d_2"] = "46200035GH", | ||
503 | ["c.ult.d_3"] = "46200035VGH", | ||
504 | ["c.ole.d_2"] = "46200036GH", | ||
505 | ["c.ole.d_3"] = "46200036VGH", | ||
506 | ["c.ule.d_2"] = "46200037GH", | ||
507 | ["c.ule.d_3"] = "46200037VGH", | ||
508 | ["c.sf.d_2"] = "46200038GH", | ||
509 | ["c.sf.d_3"] = "46200038VGH", | ||
510 | ["c.ngle.d_2"] = "46200039GH", | ||
511 | ["c.ngle.d_3"] = "46200039VGH", | ||
512 | ["c.seq.d_2"] = "4620003aGH", | ||
513 | ["c.seq.d_3"] = "4620003aVGH", | ||
514 | ["c.ngl.d_2"] = "4620003bGH", | ||
515 | ["c.ngl.d_3"] = "4620003bVGH", | ||
516 | ["c.lt.d_2"] = "4620003cGH", | ||
517 | ["c.lt.d_3"] = "4620003cVGH", | ||
518 | ["c.nge.d_2"] = "4620003dGH", | ||
519 | ["c.nge.d_3"] = "4620003dVGH", | ||
520 | ["c.le.d_2"] = "4620003eGH", | ||
521 | ["c.le.d_3"] = "4620003eVGH", | ||
522 | ["c.ngt.d_2"] = "4620003fGH", | ||
523 | ["c.ngt.d_3"] = "4620003fVGH", | ||
524 | |||
525 | ["add.ps_3"] = "46c00000FGH", | ||
526 | ["sub.ps_3"] = "46c00001FGH", | ||
527 | ["mul.ps_3"] = "46c00002FGH", | ||
528 | ["abs.ps_2"] = "46c00005FG", | ||
529 | ["mov.ps_2"] = "46c00006FG", | ||
530 | ["neg.ps_2"] = "46c00007FG", | ||
531 | ["movf.ps_2"] = "46c00011FG", | ||
532 | ["movf.ps_3"] = "46c00011FGC", | ||
533 | ["movt.ps_2"] = "46c10011FG", | ||
534 | ["movt.ps_3"] = "46c10011FGC", | ||
535 | ["movz.ps_3"] = "46c00012FGT", | ||
536 | ["movn.ps_3"] = "46c00013FGT", | ||
537 | ["cvt.s.pu_2"] = "46c00020FG", | ||
538 | ["cvt.s.pl_2"] = "46c00028FG", | ||
539 | ["pll.ps_3"] = "46c0002cFGH", | ||
540 | ["plu.ps_3"] = "46c0002dFGH", | ||
541 | ["pul.ps_3"] = "46c0002eFGH", | ||
542 | ["puu.ps_3"] = "46c0002fFGH", | ||
543 | ["c.f.ps_2"] = "46c00030GH", | ||
544 | ["c.f.ps_3"] = "46c00030VGH", | ||
545 | ["c.un.ps_2"] = "46c00031GH", | ||
546 | ["c.un.ps_3"] = "46c00031VGH", | ||
547 | ["c.eq.ps_2"] = "46c00032GH", | ||
548 | ["c.eq.ps_3"] = "46c00032VGH", | ||
549 | ["c.ueq.ps_2"] = "46c00033GH", | ||
550 | ["c.ueq.ps_3"] = "46c00033VGH", | ||
551 | ["c.olt.ps_2"] = "46c00034GH", | ||
552 | ["c.olt.ps_3"] = "46c00034VGH", | ||
553 | ["c.ult.ps_2"] = "46c00035GH", | ||
554 | ["c.ult.ps_3"] = "46c00035VGH", | ||
555 | ["c.ole.ps_2"] = "46c00036GH", | ||
556 | ["c.ole.ps_3"] = "46c00036VGH", | ||
557 | ["c.ule.ps_2"] = "46c00037GH", | ||
558 | ["c.ule.ps_3"] = "46c00037VGH", | ||
559 | ["c.sf.ps_2"] = "46c00038GH", | ||
560 | ["c.sf.ps_3"] = "46c00038VGH", | ||
561 | ["c.ngle.ps_2"] = "46c00039GH", | ||
562 | ["c.ngle.ps_3"] = "46c00039VGH", | ||
563 | ["c.seq.ps_2"] = "46c0003aGH", | ||
564 | ["c.seq.ps_3"] = "46c0003aVGH", | ||
565 | ["c.ngl.ps_2"] = "46c0003bGH", | ||
566 | ["c.ngl.ps_3"] = "46c0003bVGH", | ||
567 | ["c.lt.ps_2"] = "46c0003cGH", | ||
568 | ["c.lt.ps_3"] = "46c0003cVGH", | ||
569 | ["c.nge.ps_2"] = "46c0003dGH", | ||
570 | ["c.nge.ps_3"] = "46c0003dVGH", | ||
571 | ["c.le.ps_2"] = "46c0003eGH", | ||
572 | ["c.le.ps_3"] = "46c0003eVGH", | ||
573 | ["c.ngt.ps_2"] = "46c0003fGH", | ||
574 | ["c.ngt.ps_3"] = "46c0003fVGH", | ||
575 | |||
576 | ["cvt.s.w_2"] = "46800020FG", | ||
577 | ["cvt.d.w_2"] = "46800021FG", | ||
578 | |||
579 | ["cvt.s.l_2"] = "46a00020FG", | ||
580 | ["cvt.d.l_2"] = "46a00021FG", | ||
581 | |||
582 | -- Opcode COP1X. | ||
583 | lwxc1_2 = "4c000000FX", | ||
584 | ldxc1_2 = "4c000001FX", | ||
585 | luxc1_2 = "4c000005FX", | ||
586 | swxc1_2 = "4c000008FX", | ||
587 | sdxc1_2 = "4c000009FX", | ||
588 | suxc1_2 = "4c00000dFX", | ||
589 | prefx_2 = "4c00000fMX", | ||
590 | ["alnv.ps_4"] = "4c00001eFGHS", | ||
591 | ["madd.s_4"] = "4c000020FRGH", | ||
592 | ["madd.d_4"] = "4c000021FRGH", | ||
593 | ["madd.ps_4"] = "4c000026FRGH", | ||
594 | ["msub.s_4"] = "4c000028FRGH", | ||
595 | ["msub.d_4"] = "4c000029FRGH", | ||
596 | ["msub.ps_4"] = "4c00002eFRGH", | ||
597 | ["nmadd.s_4"] = "4c000030FRGH", | ||
598 | ["nmadd.d_4"] = "4c000031FRGH", | ||
599 | ["nmadd.ps_4"] = "4c000036FRGH", | ||
600 | ["nmsub.s_4"] = "4c000038FRGH", | ||
601 | ["nmsub.d_4"] = "4c000039FRGH", | ||
602 | ["nmsub.ps_4"] = "4c00003eFRGH", | ||
603 | } | ||
604 | |||
605 | ------------------------------------------------------------------------------ | ||
606 | |||
607 | local function parse_gpr(expr) | ||
608 | local tname, ovreg = match(expr, "^([%w_]+):(r[1-3]?[0-9])$") | ||
609 | local tp = map_type[tname or expr] | ||
610 | if tp then | ||
611 | local reg = ovreg or tp.reg | ||
612 | if not reg then | ||
613 | werror("type `"..(tname or expr).."' needs a register override") | ||
614 | end | ||
615 | expr = reg | ||
616 | end | ||
617 | local r = match(expr, "^r([1-3]?[0-9])$") | ||
618 | if r then | ||
619 | r = tonumber(r) | ||
620 | if r <= 31 then return r, tp end | ||
621 | end | ||
622 | werror("bad register name `"..expr.."'") | ||
623 | end | ||
624 | |||
625 | local function parse_fpr(expr) | ||
626 | local r = match(expr, "^f([1-3]?[0-9])$") | ||
627 | if r then | ||
628 | r = tonumber(r) | ||
629 | if r <= 31 then return r end | ||
630 | end | ||
631 | werror("bad register name `"..expr.."'") | ||
632 | end | ||
633 | |||
634 | local function parse_imm(imm, bits, shift, scale, signed) | ||
635 | local n = tonumber(imm) | ||
636 | if n then | ||
637 | if n % 2^scale == 0 then | ||
638 | n = n / 2^scale | ||
639 | if signed then | ||
640 | if n >= 0 then | ||
641 | if n < 2^(bits-1) then return n*2^shift end | ||
642 | else | ||
643 | if n >= -(2^(bits-1))-1 then return (n+2^bits)*2^shift end | ||
644 | end | ||
645 | else | ||
646 | if n >= 0 and n <= 2^bits-1 then return n*2^shift end | ||
647 | end | ||
648 | end | ||
649 | werror("out of range immediate `"..imm.."'") | ||
650 | elseif match(imm, "^[rf]([1-3]?[0-9])$") or | ||
651 | match(imm, "^([%w_]+):([rf][1-3]?[0-9])$") then | ||
652 | werror("expected immediate operand, got register") | ||
653 | else | ||
654 | waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm) | ||
655 | return 0 | ||
656 | end | ||
657 | end | ||
658 | |||
659 | local function parse_disp(disp) | ||
660 | local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$") | ||
661 | if imm then | ||
662 | local r = parse_gpr(reg) | ||
663 | return r*2^21 + parse_imm(imm, 16, 0, 0, true) | ||
664 | end | ||
665 | local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$") | ||
666 | if reg and tailr ~= "" then | ||
667 | local r, tp = parse_gpr(reg) | ||
668 | if tp then | ||
669 | waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr)) | ||
670 | return r*2^21 | ||
671 | end | ||
672 | end | ||
673 | werror("bad displacement `"..disp.."'") | ||
674 | end | ||
675 | |||
676 | local function parse_index(idx) | ||
677 | local rt, rs = match(idx, "^(.*)%(([%w_:]+)%)$") | ||
678 | if rt then | ||
679 | rt = parse_gpr(rt) | ||
680 | rs = parse_gpr(rs) | ||
681 | return rt*2^16 + rs*2^21 | ||
682 | end | ||
683 | werror("bad index `"..idx.."'") | ||
684 | end | ||
685 | |||
686 | local function parse_label(label, def) | ||
687 | local prefix = sub(label, 1, 2) | ||
688 | -- =>label (pc label reference) | ||
689 | if prefix == "=>" then | ||
690 | return "PC", 0, sub(label, 3) | ||
691 | end | ||
692 | -- ->name (global label reference) | ||
693 | if prefix == "->" then | ||
694 | return "LG", map_global[sub(label, 3)] | ||
695 | end | ||
696 | if def then | ||
697 | -- [1-9] (local label definition) | ||
698 | if match(label, "^[1-9]$") then | ||
699 | return "LG", 10+tonumber(label) | ||
700 | end | ||
701 | else | ||
702 | -- [<>][1-9] (local label reference) | ||
703 | local dir, lnum = match(label, "^([<>])([1-9])$") | ||
704 | if dir then -- Fwd: 1-9, Bkwd: 11-19. | ||
705 | return "LG", lnum + (dir == ">" and 0 or 10) | ||
706 | end | ||
707 | -- extern label (extern label reference) | ||
708 | local extname = match(label, "^extern%s+(%S+)$") | ||
709 | if extname then | ||
710 | return "EXT", map_extern[extname] | ||
711 | end | ||
712 | end | ||
713 | werror("bad label `"..label.."'") | ||
714 | end | ||
715 | |||
716 | ------------------------------------------------------------------------------ | ||
717 | |||
718 | -- Handle opcodes defined with template strings. | ||
719 | map_op[".template__"] = function(params, template, nparams) | ||
720 | if not params then return sub(template, 9) end | ||
721 | local op = tonumber(sub(template, 1, 8), 16) | ||
722 | local n = 1 | ||
723 | |||
724 | -- Limit number of section buffer positions used by a single dasm_put(). | ||
725 | -- A single opcode needs a maximum of 2 positions (ins/ext). | ||
726 | if secpos+2 > maxsecpos then wflush() end | ||
727 | local pos = wpos() | ||
728 | |||
729 | -- Process each character. | ||
730 | for p in gmatch(sub(template, 9), ".") do | ||
731 | if p == "D" then | ||
732 | op = op + parse_gpr(params[n]) * 2^11; n = n + 1 | ||
733 | elseif p == "T" then | ||
734 | op = op + parse_gpr(params[n]) * 2^16; n = n + 1 | ||
735 | elseif p == "S" then | ||
736 | op = op + parse_gpr(params[n]) * 2^21; n = n + 1 | ||
737 | elseif p == "F" then | ||
738 | op = op + parse_fpr(params[n]) * 2^6; n = n + 1 | ||
739 | elseif p == "G" then | ||
740 | op = op + parse_fpr(params[n]) * 2^11; n = n + 1 | ||
741 | elseif p == "H" then | ||
742 | op = op + parse_fpr(params[n]) * 2^16; n = n + 1 | ||
743 | elseif p == "R" then | ||
744 | op = op + parse_fpr(params[n]) * 2^21; n = n + 1 | ||
745 | elseif p == "I" then | ||
746 | op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1 | ||
747 | elseif p == "U" then | ||
748 | op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1 | ||
749 | elseif p == "O" then | ||
750 | op = op + parse_disp(params[n]); n = n + 1 | ||
751 | elseif p == "X" then | ||
752 | op = op + parse_index(params[n]); n = n + 1 | ||
753 | elseif p == "B" or p == "J" then | ||
754 | local mode, n, s = parse_label(params[n], false) | ||
755 | if p == "B" then n = n + 2048 end | ||
756 | waction("REL_"..mode, n, s, 1) | ||
757 | n = n + 1 | ||
758 | elseif p == "A" then | ||
759 | op = op + parse_imm(params[n], 5, 6, 0, false); n = n + 1 | ||
760 | elseif p == "M" then | ||
761 | op = op + parse_imm(params[n], 5, 11, 0, false); n = n + 1 | ||
762 | elseif p == "N" then | ||
763 | op = op + parse_imm(params[n], 5, 16, 0, false); n = n + 1 | ||
764 | elseif p == "C" then | ||
765 | op = op + parse_imm(params[n], 3, 18, 0, false); n = n + 1 | ||
766 | elseif p == "V" then | ||
767 | op = op + parse_imm(params[n], 3, 8, 0, false); n = n + 1 | ||
768 | elseif p == "W" then | ||
769 | op = op + parse_imm(params[n], 3, 0, 0, false); n = n + 1 | ||
770 | elseif p == "Y" then | ||
771 | op = op + parse_imm(params[n], 20, 6, 0, false); n = n + 1 | ||
772 | elseif p == "Z" then | ||
773 | op = op + parse_imm(params[n], 10, 6, 0, false); n = n + 1 | ||
774 | elseif p == "=" then | ||
775 | local d = ((op - op % 2^11) / 2^11) % 32 | ||
776 | op = op + d * 2^16 -- Copy D to T for clz, clo. | ||
777 | else | ||
778 | assert(false) | ||
779 | end | ||
780 | end | ||
781 | wputpos(pos, op) | ||
782 | end | ||
783 | |||
784 | ------------------------------------------------------------------------------ | ||
785 | |||
786 | -- Pseudo-opcode to mark the position where the action list is to be emitted. | ||
787 | map_op[".actionlist_1"] = function(params) | ||
788 | if not params then return "cvar" end | ||
789 | local name = params[1] -- No syntax check. You get to keep the pieces. | ||
790 | wline(function(out) writeactions(out, name) end) | ||
791 | end | ||
792 | |||
793 | -- Pseudo-opcode to mark the position where the global enum is to be emitted. | ||
794 | map_op[".globals_1"] = function(params) | ||
795 | if not params then return "prefix" end | ||
796 | local prefix = params[1] -- No syntax check. You get to keep the pieces. | ||
797 | wline(function(out) writeglobals(out, prefix) end) | ||
798 | end | ||
799 | |||
800 | -- Pseudo-opcode to mark the position where the global names are to be emitted. | ||
801 | map_op[".globalnames_1"] = function(params) | ||
802 | if not params then return "cvar" end | ||
803 | local name = params[1] -- No syntax check. You get to keep the pieces. | ||
804 | wline(function(out) writeglobalnames(out, name) end) | ||
805 | end | ||
806 | |||
807 | -- Pseudo-opcode to mark the position where the extern names are to be emitted. | ||
808 | map_op[".externnames_1"] = function(params) | ||
809 | if not params then return "cvar" end | ||
810 | local name = params[1] -- No syntax check. You get to keep the pieces. | ||
811 | wline(function(out) writeexternnames(out, name) end) | ||
812 | end | ||
813 | |||
814 | ------------------------------------------------------------------------------ | ||
815 | |||
816 | -- Label pseudo-opcode (converted from trailing colon form). | ||
817 | map_op[".label_1"] = function(params) | ||
818 | if not params then return "[1-9] | ->global | =>pcexpr" end | ||
819 | if secpos+1 > maxsecpos then wflush() end | ||
820 | local mode, n, s = parse_label(params[1], true) | ||
821 | if mode == "EXT" then werror("bad label definition") end | ||
822 | waction("LABEL_"..mode, n, s, 1) | ||
823 | end | ||
824 | |||
825 | ------------------------------------------------------------------------------ | ||
826 | |||
827 | -- Pseudo-opcodes for data storage. | ||
828 | map_op[".long_*"] = function(params) | ||
829 | if not params then return "imm..." end | ||
830 | for _,p in ipairs(params) do | ||
831 | local n = tonumber(p) | ||
832 | if not n then werror("bad immediate `"..p.."'") end | ||
833 | if n < 0 then n = n + 2^32 end | ||
834 | wputw(n) | ||
835 | if secpos+2 > maxsecpos then wflush() end | ||
836 | end | ||
837 | end | ||
838 | |||
839 | -- Alignment pseudo-opcode. | ||
840 | map_op[".align_1"] = function(params) | ||
841 | if not params then return "numpow2" end | ||
842 | if secpos+1 > maxsecpos then wflush() end | ||
843 | local align = tonumber(params[1]) | ||
844 | if align then | ||
845 | local x = align | ||
846 | -- Must be a power of 2 in the range (2 ... 256). | ||
847 | for i=1,8 do | ||
848 | x = x / 2 | ||
849 | if x == 1 then | ||
850 | waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. | ||
851 | return | ||
852 | end | ||
853 | end | ||
854 | end | ||
855 | werror("bad alignment") | ||
856 | end | ||
857 | |||
858 | ------------------------------------------------------------------------------ | ||
859 | |||
860 | -- Pseudo-opcode for (primitive) type definitions (map to C types). | ||
861 | map_op[".type_3"] = function(params, nparams) | ||
862 | if not params then | ||
863 | return nparams == 2 and "name, ctype" or "name, ctype, reg" | ||
864 | end | ||
865 | local name, ctype, reg = params[1], params[2], params[3] | ||
866 | if not match(name, "^[%a_][%w_]*$") then | ||
867 | werror("bad type name `"..name.."'") | ||
868 | end | ||
869 | local tp = map_type[name] | ||
870 | if tp then | ||
871 | werror("duplicate type `"..name.."'") | ||
872 | end | ||
873 | -- Add #type to defines. A bit unclean to put it in map_archdef. | ||
874 | map_archdef["#"..name] = "sizeof("..ctype..")" | ||
875 | -- Add new type and emit shortcut define. | ||
876 | local num = ctypenum + 1 | ||
877 | map_type[name] = { | ||
878 | ctype = ctype, | ||
879 | ctypefmt = format("Dt%X(%%s)", num), | ||
880 | reg = reg, | ||
881 | } | ||
882 | wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) | ||
883 | ctypenum = num | ||
884 | end | ||
885 | map_op[".type_2"] = map_op[".type_3"] | ||
886 | |||
887 | -- Dump type definitions. | ||
888 | local function dumptypes(out, lvl) | ||
889 | local t = {} | ||
890 | for name in pairs(map_type) do t[#t+1] = name end | ||
891 | sort(t) | ||
892 | out:write("Type definitions:\n") | ||
893 | for _,name in ipairs(t) do | ||
894 | local tp = map_type[name] | ||
895 | local reg = tp.reg or "" | ||
896 | out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) | ||
897 | end | ||
898 | out:write("\n") | ||
899 | end | ||
900 | |||
901 | ------------------------------------------------------------------------------ | ||
902 | |||
903 | -- Set the current section. | ||
904 | function _M.section(num) | ||
905 | waction("SECTION", num) | ||
906 | wflush(true) -- SECTION is a terminal action. | ||
907 | end | ||
908 | |||
909 | ------------------------------------------------------------------------------ | ||
910 | |||
911 | -- Dump architecture description. | ||
912 | function _M.dumparch(out) | ||
913 | out:write(format("DynASM %s version %s, released %s\n\n", | ||
914 | _info.arch, _info.version, _info.release)) | ||
915 | dumpactions(out) | ||
916 | end | ||
917 | |||
918 | -- Dump all user defined elements. | ||
919 | function _M.dumpdef(out, lvl) | ||
920 | dumptypes(out, lvl) | ||
921 | dumpglobals(out, lvl) | ||
922 | dumpexterns(out, lvl) | ||
923 | end | ||
924 | |||
925 | ------------------------------------------------------------------------------ | ||
926 | |||
927 | -- Pass callbacks from/to the DynASM core. | ||
928 | function _M.passcb(wl, we, wf, ww) | ||
929 | wline, werror, wfatal, wwarn = wl, we, wf, ww | ||
930 | return wflush | ||
931 | end | ||
932 | |||
933 | -- Setup the arch-specific module. | ||
934 | function _M.setup(arch, opt) | ||
935 | g_arch, g_opt = arch, opt | ||
936 | end | ||
937 | |||
938 | -- Merge the core maps and the arch-specific maps. | ||
939 | function _M.mergemaps(map_coreop, map_def) | ||
940 | setmetatable(map_op, { __index = map_coreop }) | ||
941 | setmetatable(map_def, { __index = map_archdef }) | ||
942 | return map_op, map_def | ||
943 | end | ||
944 | |||
945 | return _M | ||
946 | |||
947 | ------------------------------------------------------------------------------ | ||
948 | |||