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