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 | |
| parent | b330b468b3f37bd0b11765524548dbdbb1dd1a95 (diff) | |
| download | luajit-ba4917b71bba55e61f4ce644100cdb4e114ccfc5.tar.gz luajit-ba4917b71bba55e61f4ce644100cdb4e114ccfc5.tar.bz2 luajit-ba4917b71bba55e61f4ce644100cdb4e114ccfc5.zip | |
MIPS: Add DynASM MIPS module and encoding engine.
| -rw-r--r-- | dynasm/dasm_mips.h | 415 | ||||
| -rw-r--r-- | dynasm/dasm_mips.lua | 948 |
2 files changed, 1363 insertions, 0 deletions
diff --git a/dynasm/dasm_mips.h b/dynasm/dasm_mips.h new file mode 100644 index 00000000..832f9f2e --- /dev/null +++ b/dynasm/dasm_mips.h | |||
| @@ -0,0 +1,415 @@ | |||
| 1 | /* | ||
| 2 | ** DynASM MIPS encoding engine. | ||
| 3 | ** Copyright (C) 2005-2011 Mike Pall. All rights reserved. | ||
| 4 | ** Released under the MIT license. See dynasm.lua for full copyright notice. | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <stddef.h> | ||
| 8 | #include <stdarg.h> | ||
| 9 | #include <string.h> | ||
| 10 | #include <stdlib.h> | ||
| 11 | |||
| 12 | #define DASM_ARCH "mips" | ||
| 13 | |||
| 14 | #ifndef DASM_EXTERN | ||
| 15 | #define DASM_EXTERN(a,b,c,d) 0 | ||
| 16 | #endif | ||
| 17 | |||
| 18 | /* Action definitions. */ | ||
| 19 | enum { | ||
| 20 | DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, | ||
| 21 | /* The following actions need a buffer position. */ | ||
| 22 | DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, | ||
| 23 | /* The following actions also have an argument. */ | ||
| 24 | DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, | ||
| 25 | DASM__MAX | ||
| 26 | }; | ||
| 27 | |||
| 28 | /* Maximum number of section buffer positions for a single dasm_put() call. */ | ||
| 29 | #define DASM_MAXSECPOS 25 | ||
| 30 | |||
| 31 | /* DynASM encoder status codes. Action list offset or number are or'ed in. */ | ||
| 32 | #define DASM_S_OK 0x00000000 | ||
| 33 | #define DASM_S_NOMEM 0x01000000 | ||
| 34 | #define DASM_S_PHASE 0x02000000 | ||
| 35 | #define DASM_S_MATCH_SEC 0x03000000 | ||
| 36 | #define DASM_S_RANGE_I 0x11000000 | ||
| 37 | #define DASM_S_RANGE_SEC 0x12000000 | ||
| 38 | #define DASM_S_RANGE_LG 0x13000000 | ||
| 39 | #define DASM_S_RANGE_PC 0x14000000 | ||
| 40 | #define DASM_S_RANGE_REL 0x15000000 | ||
| 41 | #define DASM_S_UNDEF_LG 0x21000000 | ||
| 42 | #define DASM_S_UNDEF_PC 0x22000000 | ||
| 43 | |||
| 44 | /* Macros to convert positions (8 bit section + 24 bit index). */ | ||
| 45 | #define DASM_POS2IDX(pos) ((pos)&0x00ffffff) | ||
| 46 | #define DASM_POS2BIAS(pos) ((pos)&0xff000000) | ||
| 47 | #define DASM_SEC2POS(sec) ((sec)<<24) | ||
| 48 | #define DASM_POS2SEC(pos) ((pos)>>24) | ||
| 49 | #define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) | ||
| 50 | |||
| 51 | /* Action list type. */ | ||
| 52 | typedef const unsigned int *dasm_ActList; | ||
| 53 | |||
| 54 | /* Per-section structure. */ | ||
| 55 | typedef struct dasm_Section { | ||
| 56 | int *rbuf; /* Biased buffer pointer (negative section bias). */ | ||
| 57 | int *buf; /* True buffer pointer. */ | ||
| 58 | size_t bsize; /* Buffer size in bytes. */ | ||
| 59 | int pos; /* Biased buffer position. */ | ||
| 60 | int epos; /* End of biased buffer position - max single put. */ | ||
| 61 | int ofs; /* Byte offset into section. */ | ||
| 62 | } dasm_Section; | ||
| 63 | |||
| 64 | /* Core structure holding the DynASM encoding state. */ | ||
| 65 | struct dasm_State { | ||
| 66 | size_t psize; /* Allocated size of this structure. */ | ||
| 67 | dasm_ActList actionlist; /* Current actionlist pointer. */ | ||
| 68 | int *lglabels; /* Local/global chain/pos ptrs. */ | ||
| 69 | size_t lgsize; | ||
| 70 | int *pclabels; /* PC label chains/pos ptrs. */ | ||
| 71 | size_t pcsize; | ||
| 72 | void **globals; /* Array of globals (bias -10). */ | ||
| 73 | dasm_Section *section; /* Pointer to active section. */ | ||
| 74 | size_t codesize; /* Total size of all code sections. */ | ||
| 75 | int maxsection; /* 0 <= sectionidx < maxsection. */ | ||
| 76 | int status; /* Status code. */ | ||
| 77 | dasm_Section sections[1]; /* All sections. Alloc-extended. */ | ||
| 78 | }; | ||
| 79 | |||
| 80 | /* The size of the core structure depends on the max. number of sections. */ | ||
| 81 | #define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) | ||
| 82 | |||
| 83 | |||
| 84 | /* Initialize DynASM state. */ | ||
| 85 | void dasm_init(Dst_DECL, int maxsection) | ||
| 86 | { | ||
| 87 | dasm_State *D; | ||
| 88 | size_t psz = 0; | ||
| 89 | int i; | ||
| 90 | Dst_REF = NULL; | ||
| 91 | DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); | ||
| 92 | D = Dst_REF; | ||
| 93 | D->psize = psz; | ||
| 94 | D->lglabels = NULL; | ||
| 95 | D->lgsize = 0; | ||
| 96 | D->pclabels = NULL; | ||
| 97 | D->pcsize = 0; | ||
| 98 | D->globals = NULL; | ||
| 99 | D->maxsection = maxsection; | ||
| 100 | for (i = 0; i < maxsection; i++) { | ||
| 101 | D->sections[i].buf = NULL; /* Need this for pass3. */ | ||
| 102 | D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); | ||
| 103 | D->sections[i].bsize = 0; | ||
| 104 | D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | /* Free DynASM state. */ | ||
| 109 | void dasm_free(Dst_DECL) | ||
| 110 | { | ||
| 111 | dasm_State *D = Dst_REF; | ||
| 112 | int i; | ||
| 113 | for (i = 0; i < D->maxsection; i++) | ||
| 114 | if (D->sections[i].buf) | ||
| 115 | DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); | ||
| 116 | if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); | ||
| 117 | if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); | ||
| 118 | DASM_M_FREE(Dst, D, D->psize); | ||
| 119 | } | ||
| 120 | |||
| 121 | /* Setup global label array. Must be called before dasm_setup(). */ | ||
| 122 | void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) | ||
| 123 | { | ||
| 124 | dasm_State *D = Dst_REF; | ||
| 125 | D->globals = gl - 10; /* Negative bias to compensate for locals. */ | ||
| 126 | DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); | ||
| 127 | } | ||
| 128 | |||
| 129 | /* Grow PC label array. Can be called after dasm_setup(), too. */ | ||
| 130 | void dasm_growpc(Dst_DECL, unsigned int maxpc) | ||
| 131 | { | ||
| 132 | dasm_State *D = Dst_REF; | ||
| 133 | size_t osz = D->pcsize; | ||
| 134 | DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); | ||
| 135 | memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); | ||
| 136 | } | ||
| 137 | |||
| 138 | /* Setup encoder. */ | ||
| 139 | void dasm_setup(Dst_DECL, const void *actionlist) | ||
| 140 | { | ||
| 141 | dasm_State *D = Dst_REF; | ||
| 142 | int i; | ||
| 143 | D->actionlist = (dasm_ActList)actionlist; | ||
| 144 | D->status = DASM_S_OK; | ||
| 145 | D->section = &D->sections[0]; | ||
| 146 | memset((void *)D->lglabels, 0, D->lgsize); | ||
| 147 | if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); | ||
| 148 | for (i = 0; i < D->maxsection; i++) { | ||
| 149 | D->sections[i].pos = DASM_SEC2POS(i); | ||
| 150 | D->sections[i].ofs = 0; | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | |||
| 155 | #ifdef DASM_CHECKS | ||
| 156 | #define CK(x, st) \ | ||
| 157 | do { if (!(x)) { \ | ||
| 158 | D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) | ||
| 159 | #define CKPL(kind, st) \ | ||
| 160 | do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ | ||
| 161 | D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) | ||
| 162 | #else | ||
| 163 | #define CK(x, st) ((void)0) | ||
| 164 | #define CKPL(kind, st) ((void)0) | ||
| 165 | #endif | ||
| 166 | |||
| 167 | /* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ | ||
| 168 | void dasm_put(Dst_DECL, int start, ...) | ||
| 169 | { | ||
| 170 | va_list ap; | ||
| 171 | dasm_State *D = Dst_REF; | ||
| 172 | dasm_ActList p = D->actionlist + start; | ||
| 173 | dasm_Section *sec = D->section; | ||
| 174 | int pos = sec->pos, ofs = sec->ofs; | ||
| 175 | int *b; | ||
| 176 | |||
| 177 | if (pos >= sec->epos) { | ||
| 178 | DASM_M_GROW(Dst, int, sec->buf, sec->bsize, | ||
| 179 | sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); | ||
| 180 | sec->rbuf = sec->buf - DASM_POS2BIAS(pos); | ||
| 181 | sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); | ||
| 182 | } | ||
| 183 | |||
| 184 | b = sec->rbuf; | ||
| 185 | b[pos++] = start; | ||
| 186 | |||
| 187 | va_start(ap, start); | ||
| 188 | while (1) { | ||
| 189 | unsigned int ins = *p++; | ||
| 190 | unsigned int action = (ins >> 16) - 0xff00; | ||
| 191 | if (action >= DASM__MAX) { | ||
| 192 | ofs += 4; | ||
| 193 | } else { | ||
| 194 | int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; | ||
| 195 | switch (action) { | ||
| 196 | case DASM_STOP: goto stop; | ||
| 197 | case DASM_SECTION: | ||
| 198 | n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); | ||
| 199 | D->section = &D->sections[n]; goto stop; | ||
| 200 | case DASM_ESC: p++; ofs += 4; break; | ||
| 201 | case DASM_REL_EXT: break; | ||
| 202 | case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; | ||
| 203 | case DASM_REL_LG: | ||
| 204 | n = (ins & 2047) - 10; pl = D->lglabels + n; | ||
| 205 | if (n >= 0) { CKPL(lg, LG); goto putrel; } /* Bkwd rel or global. */ | ||
| 206 | pl += 10; n = *pl; | ||
| 207 | if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ | ||
| 208 | goto linkrel; | ||
| 209 | case DASM_REL_PC: | ||
| 210 | pl = D->pclabels + n; CKPL(pc, PC); | ||
| 211 | putrel: | ||
| 212 | n = *pl; | ||
| 213 | if (n < 0) { /* Label exists. Get label pos and store it. */ | ||
| 214 | b[pos] = -n; | ||
| 215 | } else { | ||
| 216 | linkrel: | ||
| 217 | b[pos] = n; /* Else link to rel chain, anchored at label. */ | ||
| 218 | *pl = pos; | ||
| 219 | } | ||
| 220 | pos++; | ||
| 221 | break; | ||
| 222 | case DASM_LABEL_LG: | ||
| 223 | pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; | ||
| 224 | case DASM_LABEL_PC: | ||
| 225 | pl = D->pclabels + n; CKPL(pc, PC); | ||
| 226 | putlabel: | ||
| 227 | n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ | ||
| 228 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; | ||
| 229 | } | ||
| 230 | *pl = -pos; /* Label exists now. */ | ||
| 231 | b[pos++] = ofs; /* Store pass1 offset estimate. */ | ||
| 232 | break; | ||
| 233 | case DASM_IMM: | ||
| 234 | #ifdef DASM_CHECKS | ||
| 235 | CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); | ||
| 236 | #endif | ||
| 237 | n >>= ((ins>>10)&31); | ||
| 238 | #ifdef DASM_CHECKS | ||
| 239 | if (ins & 0x8000) | ||
| 240 | CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); | ||
| 241 | else | ||
| 242 | CK((n>>((ins>>5)&31)) == 0, RANGE_I); | ||
| 243 | #endif | ||
| 244 | b[pos++] = n; | ||
| 245 | break; | ||
| 246 | } | ||
| 247 | } | ||
| 248 | } | ||
| 249 | stop: | ||
| 250 | va_end(ap); | ||
| 251 | sec->pos = pos; | ||
| 252 | sec->ofs = ofs; | ||
| 253 | } | ||
| 254 | #undef CK | ||
| 255 | |||
| 256 | /* Pass 2: Link sections, shrink aligns, fix label offsets. */ | ||
| 257 | int dasm_link(Dst_DECL, size_t *szp) | ||
| 258 | { | ||
| 259 | dasm_State *D = Dst_REF; | ||
| 260 | int secnum; | ||
| 261 | int ofs = 0; | ||
| 262 | |||
| 263 | #ifdef DASM_CHECKS | ||
| 264 | *szp = 0; | ||
| 265 | if (D->status != DASM_S_OK) return D->status; | ||
| 266 | { | ||
| 267 | int pc; | ||
| 268 | for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) | ||
| 269 | if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; | ||
| 270 | } | ||
| 271 | #endif | ||
| 272 | |||
| 273 | { /* Handle globals not defined in this translation unit. */ | ||
| 274 | int idx; | ||
| 275 | for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { | ||
| 276 | int n = D->lglabels[idx]; | ||
| 277 | /* Undefined label: Collapse rel chain and replace with marker (< 0). */ | ||
| 278 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } | ||
| 279 | } | ||
| 280 | } | ||
| 281 | |||
| 282 | /* Combine all code sections. No support for data sections (yet). */ | ||
| 283 | for (secnum = 0; secnum < D->maxsection; secnum++) { | ||
| 284 | dasm_Section *sec = D->sections + secnum; | ||
| 285 | int *b = sec->rbuf; | ||
| 286 | int pos = DASM_SEC2POS(secnum); | ||
| 287 | int lastpos = sec->pos; | ||
| 288 | |||
| 289 | while (pos != lastpos) { | ||
| 290 | dasm_ActList p = D->actionlist + b[pos++]; | ||
| 291 | while (1) { | ||
| 292 | unsigned int ins = *p++; | ||
| 293 | unsigned int action = (ins >> 16) - 0xff00; | ||
| 294 | switch (action) { | ||
| 295 | case DASM_STOP: case DASM_SECTION: goto stop; | ||
| 296 | case DASM_ESC: p++; break; | ||
| 297 | case DASM_REL_EXT: break; | ||
| 298 | case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; | ||
| 299 | case DASM_REL_LG: case DASM_REL_PC: pos++; break; | ||
| 300 | case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; | ||
| 301 | case DASM_IMM: pos++; break; | ||
| 302 | } | ||
| 303 | } | ||
| 304 | stop: (void)0; | ||
| 305 | } | ||
| 306 | ofs += sec->ofs; /* Next section starts right after current section. */ | ||
| 307 | } | ||
| 308 | |||
| 309 | D->codesize = ofs; /* Total size of all code sections */ | ||
| 310 | *szp = ofs; | ||
| 311 | return DASM_S_OK; | ||
| 312 | } | ||
| 313 | |||
| 314 | #ifdef DASM_CHECKS | ||
| 315 | #define CK(x, st) \ | ||
| 316 | do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) | ||
| 317 | #else | ||
| 318 | #define CK(x, st) ((void)0) | ||
| 319 | #endif | ||
| 320 | |||
| 321 | /* Pass 3: Encode sections. */ | ||
| 322 | int dasm_encode(Dst_DECL, void *buffer) | ||
| 323 | { | ||
| 324 | dasm_State *D = Dst_REF; | ||
| 325 | char *base = (char *)buffer; | ||
| 326 | unsigned int *cp = (unsigned int *)buffer; | ||
| 327 | int secnum; | ||
| 328 | |||
| 329 | /* Encode all code sections. No support for data sections (yet). */ | ||
| 330 | for (secnum = 0; secnum < D->maxsection; secnum++) { | ||
| 331 | dasm_Section *sec = D->sections + secnum; | ||
| 332 | int *b = sec->buf; | ||
| 333 | int *endb = sec->rbuf + sec->pos; | ||
| 334 | |||
| 335 | while (b != endb) { | ||
| 336 | dasm_ActList p = D->actionlist + *b++; | ||
| 337 | while (1) { | ||
| 338 | unsigned int ins = *p++; | ||
| 339 | unsigned int action = (ins >> 16) - 0xff00; | ||
| 340 | int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; | ||
| 341 | switch (action) { | ||
| 342 | case DASM_STOP: case DASM_SECTION: goto stop; | ||
| 343 | case DASM_ESC: *cp++ = *p++; break; | ||
| 344 | case DASM_REL_EXT: | ||
| 345 | n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1); | ||
| 346 | goto patchrel; | ||
| 347 | case DASM_ALIGN: | ||
| 348 | ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000; | ||
| 349 | break; | ||
| 350 | case DASM_REL_LG: | ||
| 351 | CK(n >= 0, UNDEF_LG); | ||
| 352 | case DASM_REL_PC: | ||
| 353 | CK(n >= 0, UNDEF_PC); | ||
| 354 | n = *DASM_POS2PTR(D, n); | ||
| 355 | if (ins & 2048) | ||
| 356 | n = n - (int)((char *)cp - base); | ||
| 357 | else | ||
| 358 | n = (n + (int)base) & 0x0fffffff; | ||
| 359 | patchrel: | ||
| 360 | CK((n & 3) == 0 && | ||
| 361 | ((n + ((ins & 2048) ? 0x00020000 : 0)) >> | ||
| 362 | ((ins & 2048) ? 18 : 28)) == 0, RANGE_REL); | ||
| 363 | cp[-1] |= ((n>>2) & ((ins & 2048) ? 0x0000ffff: 0x03ffffff)); | ||
| 364 | break; | ||
| 365 | case DASM_LABEL_LG: | ||
| 366 | ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); | ||
| 367 | break; | ||
| 368 | case DASM_LABEL_PC: break; | ||
| 369 | case DASM_IMM: | ||
| 370 | cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); | ||
| 371 | break; | ||
| 372 | default: *cp++ = ins; break; | ||
| 373 | } | ||
| 374 | } | ||
| 375 | stop: (void)0; | ||
| 376 | } | ||
| 377 | } | ||
| 378 | |||
| 379 | if (base + D->codesize != (char *)cp) /* Check for phase errors. */ | ||
| 380 | return DASM_S_PHASE; | ||
| 381 | return DASM_S_OK; | ||
| 382 | } | ||
| 383 | #undef CK | ||
| 384 | |||
| 385 | /* Get PC label offset. */ | ||
| 386 | int dasm_getpclabel(Dst_DECL, unsigned int pc) | ||
| 387 | { | ||
| 388 | dasm_State *D = Dst_REF; | ||
| 389 | if (pc*sizeof(int) < D->pcsize) { | ||
| 390 | int pos = D->pclabels[pc]; | ||
| 391 | if (pos < 0) return *DASM_POS2PTR(D, -pos); | ||
| 392 | if (pos > 0) return -1; /* Undefined. */ | ||
| 393 | } | ||
| 394 | return -2; /* Unused or out of range. */ | ||
| 395 | } | ||
| 396 | |||
| 397 | #ifdef DASM_CHECKS | ||
| 398 | /* Optional sanity checker to call between isolated encoding steps. */ | ||
| 399 | int dasm_checkstep(Dst_DECL, int secmatch) | ||
| 400 | { | ||
| 401 | dasm_State *D = Dst_REF; | ||
| 402 | if (D->status == DASM_S_OK) { | ||
| 403 | int i; | ||
| 404 | for (i = 1; i <= 9; i++) { | ||
| 405 | if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } | ||
| 406 | D->lglabels[i] = 0; | ||
| 407 | } | ||
| 408 | } | ||
| 409 | if (D->status == DASM_S_OK && secmatch >= 0 && | ||
| 410 | D->section != &D->sections[secmatch]) | ||
| 411 | D->status = DASM_S_MATCH_SEC|(D->section-D->sections); | ||
| 412 | return D->status; | ||
| 413 | } | ||
| 414 | #endif | ||
| 415 | |||
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 | |||
