Mercurial > repos > blastem
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 |