Mercurial > repos > blastem
comparison z80_to_x86.c @ 1761:873a1330c3a9
Fix cycle counts of a few instructions in old Z80 core
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 19 Feb 2019 22:59:14 -0800 |
parents | 31effaadf877 |
children | 8a29c250f352 |
comparison
equal
deleted
inserted
replaced
1760:95e36a227c9d | 1761:873a1330c3a9 |
---|---|
365 break; | 365 break; |
366 case Z80_IX_DISPLACE: | 366 case Z80_IX_DISPLACE: |
367 case Z80_IY_DISPLACE: | 367 case Z80_IY_DISPLACE: |
368 num_cycles += 8; //3 for displacement, 5 for address addition | 368 num_cycles += 8; //3 for displacement, 5 for address addition |
369 break; | 369 break; |
370 } | |
371 if (inst->reg == Z80_USE_IMMED) { | |
372 num_cycles += 3; | |
370 } | 373 } |
371 cycles(&opts->gen, num_cycles); | 374 cycles(&opts->gen, num_cycles); |
372 if (inst->addr_mode & Z80_DIR) { | 375 if (inst->addr_mode & Z80_DIR) { |
373 translate_z80_ea(inst, &dst_op, opts, DONT_READ, MODIFY); | 376 translate_z80_ea(inst, &dst_op, opts, DONT_READ, MODIFY); |
374 translate_z80_reg(inst, &src_op, opts); | 377 translate_z80_reg(inst, &src_op, opts); |
872 if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { | 875 if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { |
873 num_cycles += 8; | 876 num_cycles += 8; |
874 } else if(inst->addr_mode == Z80_IMMED) { | 877 } else if(inst->addr_mode == Z80_IMMED) { |
875 num_cycles += 3; | 878 num_cycles += 3; |
876 } else if(z80_size(inst) == SZ_W) { | 879 } else if(z80_size(inst) == SZ_W) { |
877 num_cycles += 4; | 880 num_cycles += 7; |
878 } | 881 } |
879 cycles(&opts->gen, num_cycles); | 882 cycles(&opts->gen, num_cycles); |
880 translate_z80_reg(inst, &dst_op, opts); | 883 translate_z80_reg(inst, &dst_op, opts); |
881 translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); | 884 translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); |
882 if (dst_op.mode == MODE_REG_DIRECT) { | 885 if (dst_op.mode == MODE_REG_DIRECT) { |
1851 ror_ir(code, 8, opts->gen.scratch1, SZ_W); | 1854 ror_ir(code, 8, opts->gen.scratch1, SZ_W); |
1852 call(code, opts->write_8); | 1855 call(code, opts->write_8); |
1853 break; | 1856 break; |
1854 case Z80_BIT: { | 1857 case Z80_BIT: { |
1855 if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { | 1858 if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { |
1856 num_cycles += 8; | 1859 num_cycles += 4; |
1857 } | 1860 } |
1858 cycles(&opts->gen, num_cycles); | 1861 cycles(&opts->gen, num_cycles); |
1859 uint8_t bit; | 1862 uint8_t bit; |
1860 if ((inst->addr_mode & 0x1F) == Z80_REG && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) { | 1863 if ((inst->addr_mode & 0x1F) == Z80_REG && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) { |
1861 src_op.base = opts->regs[z80_word_reg(inst->ea_reg)]; | 1864 src_op.base = opts->regs[z80_word_reg(inst->ea_reg)]; |
2591 jmp(code, start); | 2594 jmp(code, start); |
2592 *done = code->cur - (done + 1); | 2595 *done = code->cur - (done + 1); |
2593 break; | 2596 break; |
2594 } | 2597 } |
2595 case Z80_OUT: | 2598 case Z80_OUT: |
2596 if (inst->reg == Z80_A) { | 2599 if (inst->addr_mode == Z80_IMMED_INDIRECT) { |
2597 num_cycles += 3; | 2600 num_cycles += 3; |
2598 } | 2601 } |
2599 cycles(&opts->gen, num_cycles);//T States: 4 3/4 | 2602 cycles(&opts->gen, num_cycles);//T States: 4 3/4 |
2600 if ((inst->addr_mode & 0x1F) == Z80_IMMED_INDIRECT) { | 2603 if ((inst->addr_mode & 0x1F) == Z80_IMMED_INDIRECT) { |
2601 mov_ir(code, inst->immed, opts->gen.scratch2, SZ_B); | 2604 mov_ir(code, inst->immed, opts->gen.scratch2, SZ_B); |
2656 xor_rdispr(code, opts->gen.context_reg, zr_off(Z80_B), opts->gen.scratch1, SZ_B); | 2659 xor_rdispr(code, opts->gen.context_reg, zr_off(Z80_B), opts->gen.scratch1, SZ_B); |
2657 } | 2660 } |
2658 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); | 2661 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); |
2659 break; | 2662 break; |
2660 case Z80_OTIR: { | 2663 case Z80_OTIR: { |
2661 code_ptr start = code->cur; | |
2662 cycles(&opts->gen, num_cycles + 1);//T States: 4, 5 | 2664 cycles(&opts->gen, num_cycles + 1);//T States: 4, 5 |
2663 //read from (HL) | 2665 //read from (HL) |
2664 zreg_to_native(opts, Z80_HL, opts->gen.scratch1); | 2666 zreg_to_native(opts, Z80_HL, opts->gen.scratch1); |
2665 call(code, opts->read_8);//T states 3 | 2667 call(code, opts->read_8);//T states 3 |
2666 //undocumented N flag behavior | 2668 //undocumented N flag behavior |
2756 xor_rdispr(code, opts->gen.context_reg, zr_off(Z80_B), opts->gen.scratch1, SZ_B); | 2758 xor_rdispr(code, opts->gen.context_reg, zr_off(Z80_B), opts->gen.scratch1, SZ_B); |
2757 } | 2759 } |
2758 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); | 2760 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); |
2759 break; | 2761 break; |
2760 case Z80_OTDR: { | 2762 case Z80_OTDR: { |
2761 code_ptr start = code->cur; | |
2762 cycles(&opts->gen, num_cycles + 1);//T States: 4, 5 | 2763 cycles(&opts->gen, num_cycles + 1);//T States: 4, 5 |
2763 //read from (HL) | 2764 //read from (HL) |
2764 zreg_to_native(opts, Z80_HL, opts->gen.scratch1); | 2765 zreg_to_native(opts, Z80_HL, opts->gen.scratch1); |
2765 call(code, opts->read_8);//T states 3 | 2766 call(code, opts->read_8);//T states 3 |
2766 //undocumented N flag behavior | 2767 //undocumented N flag behavior |
3418 cmp_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, int_is_nmi), SZ_B); | 3419 cmp_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, int_is_nmi), SZ_B); |
3419 code_ptr is_nmi = code->cur + 1; | 3420 code_ptr is_nmi = code->cur + 1; |
3420 jcc(code, CC_NZ, is_nmi); | 3421 jcc(code, CC_NZ, is_nmi); |
3421 mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff1), SZ_B); | 3422 mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff1), SZ_B); |
3422 mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff2), SZ_B); | 3423 mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff2), SZ_B); |
3424 cycles(&options->gen, 6); //interupt ack cycle | |
3423 code_ptr after_int_disable = code->cur + 1; | 3425 code_ptr after_int_disable = code->cur + 1; |
3424 jmp(code, after_int_disable); | 3426 jmp(code, after_int_disable); |
3425 *is_nmi = code->cur - (is_nmi + 1); | 3427 *is_nmi = code->cur - (is_nmi + 1); |
3426 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, iff1), options->gen.scratch2, SZ_B); | 3428 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, iff1), options->gen.scratch2, SZ_B); |
3427 mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff1), SZ_B); | 3429 mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff1), SZ_B); |
3428 mov_rrdisp(code, options->gen.scratch2, options->gen.context_reg, offsetof(z80_context, iff2), SZ_B); | 3430 mov_rrdisp(code, options->gen.scratch2, options->gen.context_reg, offsetof(z80_context, iff2), SZ_B); |
3431 cycles(&options->gen, 5); //NMI processing cycles | |
3429 *after_int_disable = code->cur - (after_int_disable + 1); | 3432 *after_int_disable = code->cur - (after_int_disable + 1); |
3430 cycles(&options->gen, 7); | |
3431 //save return address (in scratch1) to Z80 stack | 3433 //save return address (in scratch1) to Z80 stack |
3432 sub_ir(code, 2, options->regs[Z80_SP], SZ_W); | 3434 sub_ir(code, 2, options->regs[Z80_SP], SZ_W); |
3433 mov_rr(code, options->regs[Z80_SP], options->gen.scratch2, SZ_W); | 3435 mov_rr(code, options->regs[Z80_SP], options->gen.scratch2, SZ_W); |
3434 //we need to do check_cycles and cycles outside of the write_8 call | 3436 //we need to do check_cycles and cycles outside of the write_8 call |
3435 //so that the stack has the correct depth if we need to return to C | 3437 //so that the stack has the correct depth if we need to return to C |
3451 //dispose of return address as we'll be jumping somewhere else | 3453 //dispose of return address as we'll be jumping somewhere else |
3452 add_ir(code, 16, RSP, SZ_PTR); | 3454 add_ir(code, 16, RSP, SZ_PTR); |
3453 cmp_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, int_is_nmi), SZ_B); | 3455 cmp_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, int_is_nmi), SZ_B); |
3454 is_nmi = code->cur + 1; | 3456 is_nmi = code->cur + 1; |
3455 jcc(code, CC_NZ, is_nmi); | 3457 jcc(code, CC_NZ, is_nmi); |
3456 cycles(&options->gen, 6); //interupt ack cycle | |
3457 //TODO: Support interrupt mode 0, not needed for Genesis sit it seems to read $FF during intack | 3458 //TODO: Support interrupt mode 0, not needed for Genesis sit it seems to read $FF during intack |
3458 //which is conveniently rst $38, i.e. the same thing that im 1 does | 3459 //which is conveniently rst $38, i.e. the same thing that im 1 does |
3459 //check interrupt mode | 3460 //check interrupt mode |
3460 cmp_irdisp(code, 2, options->gen.context_reg, offsetof(z80_context, im), SZ_B); | 3461 cmp_irdisp(code, 2, options->gen.context_reg, offsetof(z80_context, im), SZ_B); |
3461 code_ptr im2 = code->cur + 1; | 3462 code_ptr im2 = code->cur + 1; |
3462 jcc(code, CC_Z, im2); | 3463 jcc(code, CC_Z, im2); |
3463 mov_ir(code, 0x38, options->gen.scratch1, SZ_W); | 3464 mov_ir(code, 0x38, options->gen.scratch1, SZ_W); |
3465 cycles(&options->gen, 1); //total time for mode 0/1 is 13 t-states | |
3464 code_ptr after_int_dest = code->cur + 1; | 3466 code_ptr after_int_dest = code->cur + 1; |
3465 jmp(code, after_int_dest); | 3467 jmp(code, after_int_dest); |
3466 *im2 = code->cur - (im2 + 1); | 3468 *im2 = code->cur - (im2 + 1); |
3467 //read vector address from I << 8 | vector | 3469 //read vector address from I << 8 | vector |
3468 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, regs) + Z80_I, options->gen.scratch1, SZ_B); | 3470 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, regs) + Z80_I, options->gen.scratch1, SZ_B); |
3499 code->stack_off = tmp_stack_off; | 3501 code->stack_off = tmp_stack_off; |
3500 | 3502 |
3501 //HACK | 3503 //HACK |
3502 options->gen.address_size = SZ_D; | 3504 options->gen.address_size = SZ_D; |
3503 options->gen.address_mask = io_address_mask; | 3505 options->gen.address_mask = io_address_mask; |
3506 options->gen.bus_cycles = 4; | |
3504 options->read_io = gen_mem_fun(&options->gen, io_chunks, num_io_chunks, READ_8, NULL); | 3507 options->read_io = gen_mem_fun(&options->gen, io_chunks, num_io_chunks, READ_8, NULL); |
3505 options->write_io = gen_mem_fun(&options->gen, io_chunks, num_io_chunks, WRITE_8, NULL); | 3508 options->write_io = gen_mem_fun(&options->gen, io_chunks, num_io_chunks, WRITE_8, NULL); |
3506 options->gen.address_size = SZ_W; | 3509 options->gen.address_size = SZ_W; |
3507 options->gen.address_mask = 0xFFFF; | 3510 options->gen.address_mask = 0xFFFF; |
3511 options->gen.bus_cycles = 3; | |
3508 | 3512 |
3509 options->read_16 = code->cur; | 3513 options->read_16 = code->cur; |
3510 cycles(&options->gen, 3); | 3514 cycles(&options->gen, 3); |
3511 check_cycles(&options->gen); | 3515 check_cycles(&options->gen); |
3512 //TODO: figure out how to handle the extra wait state for word reads to bank area | 3516 //TODO: figure out how to handle the extra wait state for word reads to bank area |