| 1 | /* |
| 2 | * z64 |
| 3 | * |
| 4 | * Copyright (C) 2007 ziggy |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; either version 2 of the License, or |
| 9 | * (at your option) any later version. |
| 10 | * |
| 11 | * This program is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | * GNU General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU General Public License along |
| 17 | * with this program; if not, write to the Free Software Foundation, Inc., |
| 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| 19 | * |
| 20 | **/ |
| 21 | |
| 22 | #include "rsp.h" |
| 23 | #include <dlfcn.h> |
| 24 | #include <sys/types.h> |
| 25 | #include <sys/wait.h> |
| 26 | #include <unistd.h> |
| 27 | #include <assert.h> |
| 28 | |
| 29 | #define GENDEBUG |
| 30 | |
| 31 | typedef int (* gen_f)(RSP_REGS & rsp); |
| 32 | |
| 33 | struct gen_t { |
| 34 | UINT32 crc; |
| 35 | void * lib; |
| 36 | gen_f f; |
| 37 | #ifdef GENDEBUG |
| 38 | char name[32]; |
| 39 | #endif |
| 40 | }; |
| 41 | |
| 42 | struct opinfo_t { |
| 43 | int visit, labeled; |
| 44 | int label; |
| 45 | |
| 46 | int nbgen; |
| 47 | int szgen; |
| 48 | gen_t * gentable; |
| 49 | gen_t * curgen; |
| 50 | }; |
| 51 | |
| 52 | struct branch_t { |
| 53 | int start, end; |
| 54 | }; |
| 55 | |
| 56 | static int curvisit; |
| 57 | static opinfo_t opinfo[0x1000/4]; |
| 58 | static int nb_branches; |
| 59 | static branch_t branches[256]; |
| 60 | static int nb_labels; |
| 61 | static int labels[256]; |
| 62 | |
| 63 | #define OPI(pc) opinfo[(pc)>>2] |
| 64 | /*inline*/ void SETLABEL(int pc) { |
| 65 | //printf("%x\n", pc); |
| 66 | //pc &= 0xfff; |
| 67 | assert(pc >= 0 && pc < 0x1000); |
| 68 | if (OPI(pc).labeled != curvisit) { |
| 69 | labels[nb_labels] = pc; |
| 70 | OPI(pc).label = nb_labels++; |
| 71 | assert(nb_labels < sizeof(labels)/sizeof(labels[0])); |
| 72 | OPI(pc).labeled = curvisit; |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | #define ABS(addr) (((addr) << 2) & 0xfff) |
| 77 | #define REL(offset) ((pc + ((offset) << 2)) & 0xfff) |
| 78 | |
| 79 | static UINT32 prep_gen(int pc, UINT32 crc, int & len) |
| 80 | { |
| 81 | UINT32 op; |
| 82 | int br = 0; |
| 83 | |
| 84 | branches[nb_branches].start = pc; |
| 85 | |
| 86 | while ( !br ) |
| 87 | { |
| 88 | if (OPI(pc).visit == curvisit) { |
| 89 | SETLABEL((pc)&0xfff); |
| 90 | SETLABEL((pc+4)&0xfff); |
| 91 | break; |
| 92 | } |
| 93 | |
| 94 | OPI(pc).visit = curvisit; |
| 95 | |
| 96 | op = ROPCODE(pc); |
| 97 | crc = ((crc<<1)|(crc>>31))^op^pc; |
| 98 | pc = (pc+4)&0xfff; |
| 99 | len++; |
| 100 | |
| 101 | switch (op >> 26) |
| 102 | { |
| 103 | case 0x00: /* SPECIAL */ |
| 104 | { |
| 105 | switch (op & 0x3f) |
| 106 | { |
| 107 | case 0x08: /* JR */ |
| 108 | br = 1; |
| 109 | break; |
| 110 | case 0x09: /* JALR */ |
| 111 | //br = 1; |
| 112 | break; |
| 113 | case 0x0d: /* BREAK */ |
| 114 | br = 1; |
| 115 | break; |
| 116 | } |
| 117 | break; |
| 118 | } |
| 119 | |
| 120 | case 0x01: /* REGIMM */ |
| 121 | { |
| 122 | switch (RTREG) |
| 123 | { |
| 124 | case 0x00: /* BLTZ */ |
| 125 | case 0x01: /* BGEZ */ |
| 126 | SETLABEL(REL(SIMM16)); |
| 127 | break; |
| 128 | case 0x11: /* BGEZAL */ |
| 129 | //br = 1; |
| 130 | break; |
| 131 | } |
| 132 | break; |
| 133 | } |
| 134 | |
| 135 | case 0x02: /* J */ |
| 136 | SETLABEL(ABS(UIMM26)); |
| 137 | br = 1; |
| 138 | break; |
| 139 | case 0x04: /* BEQ */ |
| 140 | case 0x05: /* BNE */ |
| 141 | case 0x06: /* BLEZ */ |
| 142 | case 0x07: /* BGTZ */ |
| 143 | SETLABEL(REL(SIMM16)); |
| 144 | break; |
| 145 | case 0x03: /* JAL */ |
| 146 | //SETLABEL(ABS(UIMM26)); |
| 147 | //br = 1; |
| 148 | break; |
| 149 | } |
| 150 | |
| 151 | } |
| 152 | |
| 153 | branches[nb_branches++].end = pc; |
| 154 | assert(nb_branches < sizeof(branches)/sizeof(branches[0])); |
| 155 | |
| 156 | return crc; |
| 157 | } |
| 158 | |
| 159 | static char tmps[1024]; |
| 160 | static char * delayed; |
| 161 | static int has_cond; |
| 162 | |
| 163 | #define COND \ |
| 164 | has_cond = 1, fprintf |
| 165 | |
| 166 | #define NOCOND() \ |
| 167 | if (cont && OPI((pc+4)&0xfff).labeled == curvisit) { \ |
| 168 | COND(fp, "cond = 1; \n"); \ |
| 169 | } else \ |
| 170 | has_cond = 0 |
| 171 | |
| 172 | |
| 173 | static void D_JUMP_ABS(UINT32 addr) |
| 174 | { |
| 175 | int a = addr&0xfff; |
| 176 | sprintf(tmps, "%s { /*if (rsp.inval_gen) { rsp.nextpc=0x%x; return 0; }*/ %s goto L%d; }", has_cond? "if (cond)":"", a, has_cond? "cond=0; ":"", OPI(a).label); |
| 177 | delayed = tmps; |
| 178 | } |
| 179 | |
| 180 | static void D_JUMP_REL(int pc, int offset) |
| 181 | { |
| 182 | D_JUMP_ABS(pc+4 + ((offset) << 2)); |
| 183 | } |
| 184 | |
| 185 | static void D_JUMP() |
| 186 | { |
| 187 | sprintf(tmps, "%s { return 0; }", has_cond? "if (cond)":""); |
| 188 | delayed = tmps; |
| 189 | } |
| 190 | |
| 191 | static void D_JUMPL(int pc) |
| 192 | { |
| 193 | sprintf(tmps, |
| 194 | "%s { \n" |
| 195 | "%s" |
| 196 | " int res;\n" |
| 197 | " if (res = rsp_jump(rsp.nextpc)) return res; \n" |
| 198 | " if (/*rsp.inval_gen || */sp_pc != 0x%x) return 0; \n" |
| 199 | "}", has_cond? "if (cond)":"", has_cond?" cond=0; \n":"", (pc+8)&0xfff); |
| 200 | delayed = tmps; |
| 201 | has_cond = 1; |
| 202 | } |
| 203 | |
| 204 | static void dogen(const char * s, UINT32 op, FILE * fp) |
| 205 | { |
| 206 | fprintf(fp, "#define op 0x%x\n%s\n#undef op\n", op, s); |
| 207 | } |
| 208 | |
| 209 | #define GEN(s) dogen(s, op, fp) |
| 210 | |
| 211 | static void rsp_gen(int pc) |
| 212 | { |
| 213 | int i; |
| 214 | const char * old_delayed; |
| 215 | int oldbr, br; |
| 216 | |
| 217 | curvisit++; |
| 218 | if (!curvisit) { |
| 219 | // we looped, reset all visit counters |
| 220 | for (i=0; i<0x1000/4; i++) { |
| 221 | opinfo[i].visit = 0; |
| 222 | opinfo[i].labeled = 0; |
| 223 | } |
| 224 | curvisit++; |
| 225 | } |
| 226 | |
| 227 | nb_branches = 0; |
| 228 | nb_labels = 0; |
| 229 | |
| 230 | int len = 0; |
| 231 | UINT32 crc = prep_gen(pc, 0, len); |
| 232 | |
| 233 | for (i=0; i<nb_labels; i++) { |
| 234 | if (OPI(labels[i]).visit != curvisit) |
| 235 | crc = prep_gen(labels[i], crc, len); |
| 236 | } |
| 237 | |
| 238 | char src[128]; |
| 239 | char lib[128]; |
| 240 | char sym[128]; |
| 241 | sprintf(lib, "z64/rspgen/%x-%x-%x.so", crc, pc, len); |
| 242 | sprintf(sym, "doit%x", crc); |
| 243 | |
| 244 | opinfo_t * opi = &OPI(pc); |
| 245 | if (opi->gentable) { |
| 246 | for (i=0; i<opi->nbgen; i++) |
| 247 | if (opi->gentable[i].crc == crc) { |
| 248 | opi->curgen = opi->gentable + i; |
| 249 | return; |
| 250 | } |
| 251 | } |
| 252 | if (opi->nbgen >= opi->szgen) { |
| 253 | if (opi->szgen) |
| 254 | opi->szgen *= 2; |
| 255 | else |
| 256 | opi->szgen = 4; |
| 257 | opi->gentable = (gen_t *) realloc(opi->gentable, sizeof(gen_t)*(opi->szgen)); |
| 258 | } |
| 259 | gen_t * gen; |
| 260 | gen = opi->gentable + opi->nbgen++; |
| 261 | opi->curgen = gen; |
| 262 | |
| 263 | #ifdef GENDEBUG |
| 264 | strcpy(gen->name, lib); |
| 265 | #endif |
| 266 | |
| 267 | gen->crc = crc; |
| 268 | gen->lib = dlopen(lib, RTLD_NOW); |
| 269 | if (gen->lib) { |
| 270 | gen->f = (gen_f) dlsym(gen->lib, sym); |
| 271 | assert(gen->f); |
| 272 | fprintf(stderr, "reloaded %s\n", lib); |
| 273 | return; |
| 274 | } |
| 275 | // else |
| 276 | // printf("%s\n", dlerror()); |
| 277 | |
| 278 | sprintf(src, "z64/rspgen/%x-%x-%x.cpp", crc, pc, len); |
| 279 | FILE * fp = fopen(src, "w"); |
| 280 | |
| 281 | fprintf(fp, |
| 282 | "#include \"rsp.h\"\n" |
| 283 | "\n" |
| 284 | "extern \"C\" {\n" |
| 285 | "int %s() {\n" |
| 286 | "int cond=0;\n", |
| 287 | sym); |
| 288 | |
| 289 | for (i=0; i<nb_branches; i++) { |
| 290 | int cont = 1; |
| 291 | delayed = 0; |
| 292 | //fprintf(stderr, "branch %x --> %x\n", branches[i].start, branches[i].end-4); |
| 293 | for (pc=branches[i].start; cont || delayed; pc = (pc+4)&0xfff) { |
| 294 | UINT32 op = ROPCODE(pc); |
| 295 | char s[128]; |
| 296 | rsp_dasm_one(s, pc, op); |
| 297 | if (cont && OPI(pc).labeled == curvisit) |
| 298 | fprintf(fp, "L%d: ;\n", OPI(pc).label); |
| 299 | //fprintf(fp, "/* %3x\t%s */\n", pc, s); |
| 300 | fprintf(fp, "GENTRACE(\"%3x\t%s\\n\");\n", pc, s); |
| 301 | oldbr = br; |
| 302 | br = 0; |
| 303 | old_delayed = delayed; |
| 304 | delayed = 0; |
| 305 | |
| 306 | if (((pc+4)&0xfff)==branches[i].end) |
| 307 | cont = 0; |
| 308 | |
| 309 | switch (op >> 26) |
| 310 | { |
| 311 | case 0x00: /* SPECIAL */ |
| 312 | { |
| 313 | switch (op & 0x3f) |
| 314 | { |
| 315 | case 0x08: /* JR */ |
| 316 | if (!old_delayed) { |
| 317 | br = 1|8|16; |
| 318 | NOCOND(); |
| 319 | D_JUMP(); |
| 320 | } |
| 321 | break; |
| 322 | case 0x09: /* JALR */ |
| 323 | if (!old_delayed) { |
| 324 | br = 1; |
| 325 | NOCOND(); |
| 326 | D_JUMPL(pc); |
| 327 | } |
| 328 | break; |
| 329 | case 0x0d: /* BREAK */ |
| 330 | br = 2|8; |
| 331 | //delayed = "return 1;"; |
| 332 | has_cond = 0; |
| 333 | break; |
| 334 | } |
| 335 | break; |
| 336 | } |
| 337 | |
| 338 | case 0x01: /* REGIMM */ |
| 339 | { |
| 340 | switch (RTREG) |
| 341 | { |
| 342 | case 0x00: /* BLTZ */ |
| 343 | if (!old_delayed) { |
| 344 | COND(fp, " cond=(INT32)(_RSVAL(0x%x)) < 0;\n", op); |
| 345 | D_JUMP_REL(pc, _SIMM16(op)); |
| 346 | br = 4; |
| 347 | } |
| 348 | break; |
| 349 | case 0x01: /* BGEZ */ |
| 350 | if (!old_delayed) { |
| 351 | COND(fp, " cond=(INT32)(_RSVAL(0x%x)) >= 0;\n", op); |
| 352 | D_JUMP_REL(pc, _SIMM16(op)); |
| 353 | br = 4; |
| 354 | } |
| 355 | break; |
| 356 | case 0x11: /* BGEZAL */ |
| 357 | br = 1; |
| 358 | COND(fp, "cond=(INT32)(_RSVAL(0x%x)) >= 0;\n", op); |
| 359 | D_JUMPL(pc); |
| 360 | break; |
| 361 | } |
| 362 | break; |
| 363 | } |
| 364 | |
| 365 | case 0x02: /* J */ |
| 366 | if (!old_delayed) { |
| 367 | NOCOND(); |
| 368 | D_JUMP_ABS(_UIMM26(op) <<2); |
| 369 | br = 4|8|16; |
| 370 | } |
| 371 | break; |
| 372 | case 0x04: /* BEQ */ |
| 373 | if (!old_delayed) { |
| 374 | COND(fp, " cond=_RSVAL(0x%0x) == _RTVAL(0x%0x);\n", op, op); |
| 375 | D_JUMP_REL(pc, _SIMM16(op)); |
| 376 | br = 4; |
| 377 | } |
| 378 | break; |
| 379 | case 0x05: /* BNE */ |
| 380 | if (!old_delayed) { |
| 381 | COND(fp, " cond=_RSVAL(0x%0x) != _RTVAL(0x%0x);\n", op, op); |
| 382 | D_JUMP_REL(pc, _SIMM16(op)); |
| 383 | br = 4; |
| 384 | } |
| 385 | break; |
| 386 | case 0x06: /* BLEZ */ |
| 387 | if (!old_delayed) { |
| 388 | COND(fp, " cond=(INT32)_RSVAL(0x%0x) <= 0;\n", op); |
| 389 | D_JUMP_REL(pc, _SIMM16(op)); |
| 390 | br = 4; |
| 391 | } |
| 392 | break; |
| 393 | case 0x07: /* BGTZ */ |
| 394 | if (!old_delayed) { |
| 395 | COND(fp, " cond=(INT32)_RSVAL(0x%0x) > 0;\n", op); |
| 396 | D_JUMP_REL(pc, _SIMM16(op)); |
| 397 | br = 4; |
| 398 | } |
| 399 | break; |
| 400 | case 0x03: /* JAL */ |
| 401 | if (!old_delayed) { |
| 402 | br = 1; |
| 403 | NOCOND(); |
| 404 | D_JUMPL(pc); |
| 405 | } |
| 406 | break; |
| 407 | } |
| 408 | |
| 409 | if (!(br&4) && (!old_delayed || !br)) { |
| 410 | if (br && !(br&16)) { |
| 411 | fprintf(fp, "sp_pc = 0x%x;\n", (pc + 4)&0xfff); |
| 412 | } |
| 413 | //fprintf(fp, "rsp_execute_one(0x%x);\n", op); |
| 414 | |
| 415 | |
| 416 | |
| 417 | |
| 418 | |
| 419 | switch (op >> 26) |
| 420 | { |
| 421 | case 0x00: /* SPECIAL */ |
| 422 | { |
| 423 | switch (op & 0x3f) |
| 424 | { |
| 425 | case 0x00: /* SLL */ if (RDREG) GEN("RDVAL = (UINT32)RTVAL << SHIFT;"); break; |
| 426 | case 0x02: /* SRL */ if (RDREG) GEN("RDVAL = (UINT32)RTVAL >> SHIFT; "); break; |
| 427 | case 0x03: /* SRA */ if (RDREG) GEN("RDVAL = (INT32)RTVAL >> SHIFT; "); break; |
| 428 | case 0x04: /* SLLV */ if (RDREG) GEN("RDVAL = (UINT32)RTVAL << (RSVAL & 0x1f); "); break; |
| 429 | case 0x06: /* SRLV */ if (RDREG) GEN("RDVAL = (UINT32)RTVAL >> (RSVAL & 0x1f); "); break; |
| 430 | case 0x07: /* SRAV */ if (RDREG) GEN("RDVAL = (INT32)RTVAL >> (RSVAL & 0x1f); "); break; |
| 431 | case 0x08: /* JR */ GEN("JUMP_PC(RSVAL); "); break; |
| 432 | case 0x09: /* JALR */ GEN("JUMP_PC_L(RSVAL, RDREG); "); break; |
| 433 | case 0x0d: /* BREAK */ |
| 434 | { |
| 435 | GEN( |
| 436 | " \ |
| 437 | *z64_rspinfo.SP_STATUS_REG |= (SP_STATUS_HALT | SP_STATUS_BROKE ); \ |
| 438 | if ((*z64_rspinfo.SP_STATUS_REG & SP_STATUS_INTR_BREAK) != 0 ) { \ |
| 439 | *z64_rspinfo.MI_INTR_REG |= 1; \ |
| 440 | z64_rspinfo.CheckInterrupts(); \ |
| 441 | } \ |
| 442 | rsp.nextpc = ~0; \ |
| 443 | return 1; \ |
| 444 | "); |
| 445 | break; |
| 446 | } |
| 447 | case 0x20: /* ADD */ if (RDREG) GEN("RDVAL = (INT32)(RSVAL + RTVAL); "); break; |
| 448 | case 0x21: /* ADDU */ if (RDREG) GEN("RDVAL = (INT32)(RSVAL + RTVAL); "); break; |
| 449 | case 0x22: /* SUB */ if (RDREG) GEN("RDVAL = (INT32)(RSVAL - RTVAL); "); break; |
| 450 | case 0x23: /* SUBU */ if (RDREG) GEN("RDVAL = (INT32)(RSVAL - RTVAL); "); break; |
| 451 | case 0x24: /* AND */ if (RDREG) GEN("RDVAL = RSVAL & RTVAL; "); break; |
| 452 | case 0x25: /* OR */ if (RDREG) GEN("RDVAL = RSVAL | RTVAL; "); break; |
| 453 | case 0x26: /* XOR */ if (RDREG) GEN("RDVAL = RSVAL ^ RTVAL; "); break; |
| 454 | case 0x27: /* NOR */ if (RDREG) GEN("RDVAL = ~(RSVAL | RTVAL); "); break; |
| 455 | case 0x2a: /* SLT */ if (RDREG) GEN("RDVAL = (INT32)RSVAL < (INT32)RTVAL; "); break; |
| 456 | case 0x2b: /* SLTU */ if (RDREG) GEN("RDVAL = (UINT32)RSVAL < (UINT32)RTVAL; "); break; |
| 457 | default: GEN("unimplemented_opcode(op); "); break; |
| 458 | } |
| 459 | break; |
| 460 | } |
| 461 | |
| 462 | case 0x01: /* REGIMM */ |
| 463 | { |
| 464 | switch (RTREG) |
| 465 | { |
| 466 | case 0x00: /* BLTZ */ GEN("if ((INT32)(RSVAL) < 0) JUMP_REL(SIMM16); "); break; |
| 467 | case 0x01: /* BGEZ */ GEN("if ((INT32)(RSVAL) >= 0) JUMP_REL(SIMM16); "); break; |
| 468 | // VP according to the doc, link is performed even when condition fails |
| 469 | case 0x11: /* BGEZAL */ GEN("LINK(31); if ((INT32)(RSVAL) >= 0) JUMP_REL(SIMM16); "); break; |
| 470 | //case 0x11: /* BGEZAL */ if ((INT32)(RSVAL) >= 0) JUMP_REL_L(SIMM16, 31); break; |
| 471 | default: GEN("unimplemented_opcode(op); "); break; |
| 472 | } |
| 473 | break; |
| 474 | } |
| 475 | |
| 476 | case 0x02: /* J */ GEN("JUMP_ABS(UIMM26); "); break; |
| 477 | case 0x03: /* JAL */ GEN("JUMP_ABS_L(UIMM26, 31); "); break; |
| 478 | case 0x04: /* BEQ */ GEN("if (RSVAL == RTVAL) JUMP_REL(SIMM16); "); break; |
| 479 | case 0x05: /* BNE */ GEN("if (RSVAL != RTVAL) JUMP_REL(SIMM16); "); break; |
| 480 | case 0x06: /* BLEZ */ GEN("if ((INT32)RSVAL <= 0) JUMP_REL(SIMM16); "); break; |
| 481 | case 0x07: /* BGTZ */ GEN("if ((INT32)RSVAL > 0) JUMP_REL(SIMM16); "); break; |
| 482 | case 0x08: /* ADDI */ if (RTREG) GEN("RTVAL = (INT32)(RSVAL + SIMM16); "); break; |
| 483 | case 0x09: /* ADDIU */ if (RTREG) GEN("RTVAL = (INT32)(RSVAL + SIMM16); "); break; |
| 484 | case 0x0a: /* SLTI */ if (RTREG) GEN("RTVAL = (INT32)(RSVAL) < ((INT32)SIMM16); "); break; |
| 485 | case 0x0b: /* SLTIU */ if (RTREG) GEN("RTVAL = (UINT32)(RSVAL) < (UINT32)((INT32)SIMM16); "); break; |
| 486 | case 0x0c: /* ANDI */ if (RTREG) GEN("RTVAL = RSVAL & UIMM16; "); break; |
| 487 | case 0x0d: /* ORI */ if (RTREG) GEN("RTVAL = RSVAL | UIMM16; "); break; |
| 488 | case 0x0e: /* XORI */ if (RTREG) GEN("RTVAL = RSVAL ^ UIMM16; "); break; |
| 489 | case 0x0f: /* LUI */ if (RTREG) GEN("RTVAL = UIMM16 << 16; "); break; |
| 490 | |
| 491 | case 0x10: /* COP0 */ |
| 492 | { |
| 493 | switch ((op >> 21) & 0x1f) |
| 494 | { |
| 495 | case 0x00: /* MFC0 */ if (RTREG) GEN("RTVAL = get_cop0_reg(rsp, RDREG); "); break; |
| 496 | case 0x04: /* MTC0 */ |
| 497 | { |
| 498 | GEN("set_cop0_reg(rsp, RDREG, RTVAL); \n"); |
| 499 | if (RDREG == 0x08/4) { |
| 500 | fprintf(fp, |
| 501 | "if (rsp.inval_gen) {\n" |
| 502 | " rsp.inval_gen = 0;\n" |
| 503 | " sp_pc = 0x%x; \n" |
| 504 | " return 2; \n" |
| 505 | "}\n" |
| 506 | , (pc + 4)&0xfff); |
| 507 | } |
| 508 | break; |
| 509 | } |
| 510 | default: |
| 511 | log(M64MSG_WARNING, "unimplemented cop0 %x (%x)\n", (op >> 21) & 0x1f, op); |
| 512 | break; |
| 513 | } |
| 514 | break; |
| 515 | } |
| 516 | |
| 517 | case 0x12: /* COP2 */ |
| 518 | { |
| 519 | switch ((op >> 21) & 0x1f) |
| 520 | { |
| 521 | case 0x00: /* MFC2 */ |
| 522 | { |
| 523 | // 31 25 20 15 10 6 0 |
| 524 | // --------------------------------------------------- |
| 525 | // | 010010 | 00000 | TTTTT | DDDDD | IIII | 0000000 | |
| 526 | // --------------------------------------------------- |
| 527 | // |
| 528 | if (RTREG) GEN("\ |
| 529 | {int el = (op >> 7) & 0xf;\ |
| 530 | UINT16 b1 = VREG_B(VS1REG, (el+0) & 0xf);\ |
| 531 | UINT16 b2 = VREG_B(VS1REG, (el+1) & 0xf);\ |
| 532 | RTVAL = (INT32)(INT16)((b1 << 8) | (b2));}\ |
| 533 | "); |
| 534 | break; |
| 535 | } |
| 536 | case 0x02: /* CFC2 */ |
| 537 | { |
| 538 | // 31 25 20 15 10 0 |
| 539 | // ------------------------------------------------ |
| 540 | // | 010010 | 00010 | TTTTT | DDDDD | 00000000000 | |
| 541 | // ------------------------------------------------ |
| 542 | // |
| 543 | |
| 544 | // VP to sign extend or to not sign extend ? |
| 545 | //if (RTREG) RTVAL = (INT16)rsp.flag[RDREG]; |
| 546 | if (RTREG) GEN("RTVAL = rsp.flag[RDREG];"); |
| 547 | break; |
| 548 | } |
| 549 | case 0x04: /* MTC2 */ |
| 550 | { |
| 551 | // 31 25 20 15 10 6 0 |
| 552 | // --------------------------------------------------- |
| 553 | // | 010010 | 00100 | TTTTT | DDDDD | IIII | 0000000 | |
| 554 | // --------------------------------------------------- |
| 555 | // |
| 556 | GEN("\ |
| 557 | {int el = (op >> 7) & 0xf;\ |
| 558 | VREG_B(VS1REG, (el+0) & 0xf) = (RTVAL >> 8) & 0xff;\ |
| 559 | VREG_B(VS1REG, (el+1) & 0xf) = (RTVAL >> 0) & 0xff;}\ |
| 560 | "); |
| 561 | break; |
| 562 | } |
| 563 | case 0x06: /* CTC2 */ |
| 564 | { |
| 565 | // 31 25 20 15 10 0 |
| 566 | // ------------------------------------------------ |
| 567 | // | 010010 | 00110 | TTTTT | DDDDD | 00000000000 | |
| 568 | // ------------------------------------------------ |
| 569 | // |
| 570 | |
| 571 | GEN("rsp.flag[RDREG] = RTVAL & 0xffff;"); |
| 572 | break; |
| 573 | } |
| 574 | |
| 575 | case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: |
| 576 | case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: |
| 577 | { |
| 578 | GEN("handle_vector_ops(rsp, op);"); |
| 579 | break; |
| 580 | } |
| 581 | |
| 582 | default: GEN("unimplemented_opcode(op); "); break; |
| 583 | } |
| 584 | break; |
| 585 | } |
| 586 | |
| 587 | case 0x20: /* LB */ if (RTREG) GEN("RTVAL = (INT32)(INT8)READ8(RSVAL + SIMM16); "); break; |
| 588 | case 0x21: /* LH */ if (RTREG) GEN("RTVAL = (INT32)(INT16)READ16(RSVAL + SIMM16); "); break; |
| 589 | case 0x23: /* LW */ if (RTREG) GEN("RTVAL = READ32(RSVAL + SIMM16); "); break; |
| 590 | case 0x24: /* LBU */ if (RTREG) GEN("RTVAL = (UINT8)READ8(RSVAL + SIMM16); "); break; |
| 591 | case 0x25: /* LHU */ if (RTREG) GEN("RTVAL = (UINT16)READ16(RSVAL + SIMM16); "); break; |
| 592 | case 0x28: /* SB */ GEN("WRITE8(RSVAL + SIMM16, RTVAL); "); break; |
| 593 | case 0x29: /* SH */ GEN("WRITE16(RSVAL + SIMM16, RTVAL); "); break; |
| 594 | case 0x2b: /* SW */ GEN("WRITE32(RSVAL + SIMM16, RTVAL); "); break; |
| 595 | case 0x32: /* LWC2 */ GEN("handle_lwc2(rsp, op); "); break; |
| 596 | case 0x3a: /* SWC2 */ GEN("handle_swc2(rsp, op); "); break; |
| 597 | |
| 598 | default: |
| 599 | { |
| 600 | GEN("unimplemented_opcode(op);"); |
| 601 | break; |
| 602 | } |
| 603 | } |
| 604 | |
| 605 | |
| 606 | |
| 607 | |
| 608 | // if (br) { |
| 609 | // if (br & 2) |
| 610 | // fprintf(fp, "return 1;\n"); |
| 611 | // else |
| 612 | // fprintf(fp, "return 0;\n"); |
| 613 | // } |
| 614 | } |
| 615 | if (old_delayed) |
| 616 | fprintf(fp, "%s\n", old_delayed); |
| 617 | } |
| 618 | if (!((/*br|*/oldbr)&8) && ((!oldbr && !(br&2)) || has_cond)) { |
| 619 | fprintf(fp, "/* jumping back to %x */\ngoto L%d;\n", pc, OPI(pc).label); |
| 620 | assert(OPI(pc).labeled == curvisit); |
| 621 | } |
| 622 | } |
| 623 | |
| 624 | fprintf(fp, "}}\n"); |
| 625 | |
| 626 | fclose(fp); |
| 627 | |
| 628 | pid_t pid = fork(); |
| 629 | // SDL redirect these signals, but we need them untouched for waitpid call |
| 630 | signal(17, 0); |
| 631 | signal(11, 0); |
| 632 | if (!pid) { |
| 633 | // char s[128]; |
| 634 | // atexit(0); |
| 635 | // sprintf(s, "gcc -Iz64 -g -shared -O2 %s -o %s", src, lib); |
| 636 | // system(s); |
| 637 | // exit(0); |
| 638 | |
| 639 | //setsid(); |
| 640 | //execl("/usr/bin/gcc", "/usr/bin/gcc", "-Iz64", "-shared", "-g", "-O3", "-fomit-frame-pointer", src, "-o", lib, "-finline-limit=10000", 0); |
| 641 | //execl("/usr/bin/gcc", "/usr/bin/gcc", "-Iz64", "-shared", "-O3", src, "-o", lib, "-fomit-frame-pointer", "-ffast-math", "-funroll-loops", "-fforce-addr", "-finline-limit=10000", 0); |
| 642 | //execl("/usr/bin/gcc", "/usr/bin/gcc", "-Iz64", "-shared", "-O3", src, "-o", lib, "-fomit-frame-pointer", "-ffast-math", "-funroll-loops", "-fforce-addr", "-finline-limit=10000", "-m3dnow", "-mmmx", "-msse", "-msse2", "-mfpmath=sse", 0); |
| 643 | execl("/usr/bin/gcc", "/usr/bin/gcc", "-Iz64", "-shared", "-O6", src, "-o", lib, "-fomit-frame-pointer", "-ffast-math", "-funroll-loops", "-fforce-addr", "-finline-limit=10000", "-m3dnow", "-mmmx", "-msse", "-msse2", 0); |
| 644 | printf("gnii ??\n"); |
| 645 | exit(0); |
| 646 | } |
| 647 | waitpid(pid, 0, __WALL); |
| 648 | |
| 649 | gen->lib = dlopen(lib, RTLD_NOW); |
| 650 | if (!gen->lib) |
| 651 | log(M64MSG_WARNING, "%s\n", dlerror()); |
| 652 | assert(gen->lib); |
| 653 | log(M64MSG_VERBOSE, "created and loaded %s\n", lib); |
| 654 | gen->f = (gen_f) dlsym(gen->lib, sym); |
| 655 | assert(gen->f); |
| 656 | } |
| 657 | |
| 658 | void rsp_invalidate(int begin, int len) |
| 659 | { |
| 660 | //printf("invalidate %x %x\n", begin, len); |
| 661 | begin = 0; len = 0x1000; |
| 662 | assert(begin+len<=0x1000); |
| 663 | while (len > 0) { |
| 664 | OPI(begin).curgen = 0; |
| 665 | begin += 4; |
| 666 | len -= 4; |
| 667 | } |
| 668 | rsp.inval_gen = 1; |
| 669 | } |
| 670 | |
| 671 | int rsp_jump(int pc) |
| 672 | { |
| 673 | pc &= 0xfff; |
| 674 | sp_pc = pc; |
| 675 | rsp.nextpc = ~0; |
| 676 | opinfo_t * opi = &OPI(pc); |
| 677 | gen_t * gen = opi->curgen; |
| 678 | if (!gen) rsp_gen(pc); |
| 679 | gen = opi->curgen; |
| 680 | GENTRACE("rsp_jump %x (%s)\n", pc, gen->name); |
| 681 | int res = gen->f(rsp); |
| 682 | GENTRACE("r31 %x from %x nextpc %x pc %x res %d (%s)\n", rsp.r[31], pc, rsp.nextpc, sp_pc, res, gen->name); |
| 683 | if (rsp.nextpc != ~0) |
| 684 | { |
| 685 | sp_pc = (rsp.nextpc & 0xfff); |
| 686 | rsp.nextpc = ~0; |
| 687 | } |
| 688 | else |
| 689 | { |
| 690 | //sp_pc = ((sp_pc+4)&0xfff); |
| 691 | } |
| 692 | return res; |
| 693 | } |