comparison m68k_core.c @ 1298:d5a47597b61f

Prevent blowing past our native translated instruction size of 255 bytes when translating movem with a large register list. Fixes bug in which Fantastic Dizzy was completely broken on 32-bit builds
author Michael Pavone <pavone@retrodev.com>
date Sat, 25 Mar 2017 00:21:32 -0700
parents c5821f9de325
children c9dc2603b087
comparison
equal deleted inserted replaced
1297:71b1a080b30c 1298:d5a47597b61f
383 } 383 }
384 native_to_areg(opts, reg, 8); 384 native_to_areg(opts, reg, 8);
385 } 385 }
386 } 386 }
387 387
388 static void translate_movem_regtomem_reglist(m68k_options * opts, m68kinst *inst)
389 {
390 code_info *code = &opts->gen.code;
391 int8_t bit,reg,dir;
392 if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
393 reg = 15;
394 dir = -1;
395 } else {
396 reg = 0;
397 dir = 1;
398 }
399 for(bit=0; reg < 16 && reg >= 0; reg += dir, bit++) {
400 if (inst->src.params.immed & (1 << bit)) {
401 if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
402 subi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch2);
403 }
404 push_native(opts, opts->gen.scratch2);
405 if (reg > 7) {
406 areg_to_native(opts, reg-8, opts->gen.scratch1);
407 } else {
408 dreg_to_native(opts, reg, opts->gen.scratch1);
409 }
410 if (inst->extra.size == OPSIZE_LONG) {
411 call(code, opts->write_32_lowfirst);
412 } else {
413 call(code, opts->write_16);
414 }
415 pop_native(opts, opts->gen.scratch2);
416 if (inst->dst.addr_mode != MODE_AREG_PREDEC) {
417 addi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch2);
418 }
419 }
420 }
421 }
422
423 static void translate_movem_memtoreg_reglist(m68k_options * opts, m68kinst *inst)
424 {
425 code_info *code = &opts->gen.code;
426 for(uint8_t reg = 0; reg < 16; reg ++) {
427 if (inst->dst.params.immed & (1 << reg)) {
428 push_native(opts, opts->gen.scratch1);
429 if (inst->extra.size == OPSIZE_LONG) {
430 call(code, opts->read_32);
431 } else {
432 call(code, opts->read_16);
433 }
434 if (inst->extra.size == OPSIZE_WORD) {
435 sign_extend16_native(opts, opts->gen.scratch1);
436 }
437 if (reg > 7) {
438 native_to_areg(opts, opts->gen.scratch1, reg-8);
439 } else {
440 native_to_dreg(opts, opts->gen.scratch1, reg);
441 }
442 pop_native(opts, opts->gen.scratch1);
443 addi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch1);
444 }
445 }
446 }
447
448 static code_ptr get_movem_impl(m68k_options *opts, m68kinst *inst)
449 {
450 uint8_t reg_to_mem = inst->src.addr_mode == MODE_REG;
451 uint8_t size = inst->extra.size;
452 int8_t dir = reg_to_mem && inst->dst.addr_mode == MODE_AREG_PREDEC ? -1 : 1;
453 uint16_t reglist = reg_to_mem ? inst->src.params.immed : inst->dst.params.immed;
454 for (uint32_t i = 0; i < opts->num_movem; i++)
455 {
456 if (
457 opts->big_movem[i].reglist == reglist && opts->big_movem[i].reg_to_mem == reg_to_mem
458 && opts->big_movem[i].size == size && opts->big_movem[i].dir == dir
459 ) {
460 return opts->big_movem[i].impl;
461 }
462 }
463 if (opts->num_movem == opts->movem_storage) {
464 opts->movem_storage *= 2;
465 opts->big_movem = realloc(opts->big_movem, sizeof(movem_fun) * opts->movem_storage);
466 }
467 if (!opts->extra_code.cur) {
468 init_code_info(&opts->extra_code);
469 }
470 check_alloc_code(&opts->extra_code, 512);
471 code_ptr impl = opts->extra_code.cur;
472 code_info tmp = opts->gen.code;
473 opts->gen.code = opts->extra_code;
474 if (reg_to_mem) {
475 translate_movem_regtomem_reglist(opts, inst);
476 } else {
477 translate_movem_memtoreg_reglist(opts, inst);
478 }
479 opts->extra_code = opts->gen.code;
480 opts->gen.code = tmp;
481
482 rts(&opts->extra_code);
483 return impl;
484 }
485
388 static void translate_m68k_movem(m68k_options * opts, m68kinst * inst) 486 static void translate_m68k_movem(m68k_options * opts, m68kinst * inst)
389 { 487 {
390 code_info *code = &opts->gen.code; 488 code_info *code = &opts->gen.code;
391 int8_t bit,reg,sec_reg;
392 uint8_t early_cycles; 489 uint8_t early_cycles;
490 uint16_t num_regs = inst->src.addr_mode == MODE_REG ? inst->src.params.immed : inst->dst.params.immed;
491 {
492 //TODO: Move this popcount alg to a utility function
493 uint16_t a = (num_regs & 0b1010101010101010) >> 1;
494 uint16_t b = num_regs & 0b0101010101010101;
495 num_regs = a + b;
496 a = (num_regs & 0b1100110011001100) >> 2;
497 b = num_regs & 0b0011001100110011;
498 num_regs = a + b;
499 a = (num_regs & 0b1111000011110000) >> 4;
500 b = num_regs & 0b0000111100001111;
501 num_regs = a + b;
502 a = (num_regs & 0b1111111100000000) >> 8;
503 b = num_regs & 0b0000000011111111;
504 num_regs = a + b;
505 }
393 if(inst->src.addr_mode == MODE_REG) { 506 if(inst->src.addr_mode == MODE_REG) {
394 //reg to mem 507 //reg to mem
395 early_cycles = 8; 508 early_cycles = 8;
396 int8_t dir;
397 switch (inst->dst.addr_mode) 509 switch (inst->dst.addr_mode)
398 { 510 {
399 case MODE_AREG_INDIRECT: 511 case MODE_AREG_INDIRECT:
400 case MODE_AREG_PREDEC: 512 case MODE_AREG_PREDEC:
401 areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2); 513 areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2);
424 break; 536 break;
425 default: 537 default:
426 m68k_disasm(inst, disasm_buf); 538 m68k_disasm(inst, disasm_buf);
427 fatal_error("%X: %s\naddress mode %d not implemented (movem dst)\n", inst->address, disasm_buf, inst->dst.addr_mode); 539 fatal_error("%X: %s\naddress mode %d not implemented (movem dst)\n", inst->address, disasm_buf, inst->dst.addr_mode);
428 } 540 }
429 if (inst->dst.addr_mode == MODE_AREG_PREDEC) { 541
430 reg = 15; 542 cycles(&opts->gen, early_cycles);
431 dir = -1; 543 if (num_regs <= 9) {
544 translate_movem_regtomem_reglist(opts, inst);
432 } else { 545 } else {
433 reg = 0; 546 call(code, get_movem_impl(opts, inst));
434 dir = 1;
435 }
436 cycles(&opts->gen, early_cycles);
437 for(bit=0; reg < 16 && reg >= 0; reg += dir, bit++) {
438 if (inst->src.params.immed & (1 << bit)) {
439 if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
440 subi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch2);
441 }
442 push_native(opts, opts->gen.scratch2);
443 if (reg > 7) {
444 areg_to_native(opts, reg-8, opts->gen.scratch1);
445 } else {
446 dreg_to_native(opts, reg, opts->gen.scratch1);
447 }
448 if (inst->extra.size == OPSIZE_LONG) {
449 call(code, opts->write_32_lowfirst);
450 } else {
451 call(code, opts->write_16);
452 }
453 pop_native(opts, opts->gen.scratch2);
454 if (inst->dst.addr_mode != MODE_AREG_PREDEC) {
455 addi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch2);
456 }
457 }
458 } 547 }
459 if (inst->dst.addr_mode == MODE_AREG_PREDEC) { 548 if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
460 native_to_areg(opts, opts->gen.scratch2, inst->dst.params.regs.pri); 549 native_to_areg(opts, opts->gen.scratch2, inst->dst.params.regs.pri);
461 } 550 }
462 } else { 551 } else {
468 case MODE_AREG_POSTINC: 557 case MODE_AREG_POSTINC:
469 areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1); 558 areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1);
470 break; 559 break;
471 case MODE_AREG_DISPLACE: 560 case MODE_AREG_DISPLACE:
472 early_cycles += BUS; 561 early_cycles += BUS;
473 reg = opts->gen.scratch2;
474 calc_areg_displace(opts, &inst->src, opts->gen.scratch1); 562 calc_areg_displace(opts, &inst->src, opts->gen.scratch1);
475 break; 563 break;
476 case MODE_AREG_INDEX_DISP8: 564 case MODE_AREG_INDEX_DISP8:
477 early_cycles += 6; 565 early_cycles += 6;
478 calc_areg_index_disp8(opts, &inst->src, opts->gen.scratch1); 566 calc_areg_index_disp8(opts, &inst->src, opts->gen.scratch1);
495 default: 583 default:
496 m68k_disasm(inst, disasm_buf); 584 m68k_disasm(inst, disasm_buf);
497 fatal_error("%X: %s\naddress mode %d not implemented (movem src)\n", inst->address, disasm_buf, inst->src.addr_mode); 585 fatal_error("%X: %s\naddress mode %d not implemented (movem src)\n", inst->address, disasm_buf, inst->src.addr_mode);
498 } 586 }
499 cycles(&opts->gen, early_cycles); 587 cycles(&opts->gen, early_cycles);
500 for(reg = 0; reg < 16; reg ++) { 588
501 if (inst->dst.params.immed & (1 << reg)) { 589 if (num_regs <= 9) {
502 push_native(opts, opts->gen.scratch1); 590 translate_movem_memtoreg_reglist(opts, inst);
503 if (inst->extra.size == OPSIZE_LONG) { 591 } else {
504 call(code, opts->read_32); 592 call(code, get_movem_impl(opts, inst));
505 } else {
506 call(code, opts->read_16);
507 }
508 if (inst->extra.size == OPSIZE_WORD) {
509 sign_extend16_native(opts, opts->gen.scratch1);
510 }
511 if (reg > 7) {
512 native_to_areg(opts, opts->gen.scratch1, reg-8);
513 } else {
514 native_to_dreg(opts, opts->gen.scratch1, reg);
515 }
516 pop_native(opts, opts->gen.scratch1);
517 addi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch1);
518 }
519 } 593 }
520 if (inst->src.addr_mode == MODE_AREG_POSTINC) { 594 if (inst->src.addr_mode == MODE_AREG_POSTINC) {
521 native_to_areg(opts, opts->gen.scratch1, inst->src.params.regs.pri); 595 native_to_areg(opts, opts->gen.scratch1, inst->src.params.regs.pri);
522 } 596 }
523 //Extra read 597 //Extra read