Mercurial > repos > blastem
comparison z80_to_x86.c @ 593:5ef3fe516da9
Z80 core is sort of working again
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Mon, 22 Dec 2014 20:55:10 -0800 |
parents | 4ff7bbb3943b |
children | 086de8692932 |
comparison
equal
deleted
inserted
replaced
592:4ff7bbb3943b | 593:5ef3fe516da9 |
---|---|
25 #ifdef DO_DEBUG_PRINT | 25 #ifdef DO_DEBUG_PRINT |
26 #define dprintf printf | 26 #define dprintf printf |
27 #else | 27 #else |
28 #define dprintf | 28 #define dprintf |
29 #endif | 29 #endif |
30 | |
31 void z80_read_byte(); | |
32 void z80_read_word(); | |
33 void z80_write_byte(); | |
34 void z80_write_word_highfirst(); | |
35 void z80_write_word_lowfirst(); | |
36 void z80_save_context(); | |
37 void z80_native_addr(); | |
38 void z80_do_sync(); | |
39 void z80_handle_cycle_limit_int(); | |
40 void z80_retrans_stub(); | |
41 void z80_io_read(); | |
42 void z80_io_write(); | |
43 void z80_halt(); | |
44 void z80_save_context(); | |
45 void z80_load_context(); | |
46 | 30 |
47 uint8_t z80_size(z80inst * inst) | 31 uint8_t z80_size(z80inst * inst) |
48 { | 32 { |
49 uint8_t reg = (inst->reg & 0x1F); | 33 uint8_t reg = (inst->reg & 0x1F); |
50 if (reg != Z80_UNUSED && reg != Z80_USE_IMMED) { | 34 if (reg != Z80_UNUSED && reg != Z80_USE_IMMED) { |
182 if (read) { | 166 if (read) { |
183 /*if (modify) { | 167 /*if (modify) { |
184 push_r(code, opts->gen.scratch1); | 168 push_r(code, opts->gen.scratch1); |
185 }*/ | 169 }*/ |
186 if (size == SZ_B) { | 170 if (size == SZ_B) { |
187 call(code, (uint8_t *)z80_read_byte); | 171 call(code, opts->read_8); |
188 } else { | 172 } else { |
189 call(code, (uint8_t *)z80_read_word); | 173 call(code, opts->read_16); |
190 } | 174 } |
191 if (modify) { | 175 if (modify) { |
192 //pop_r(code, opts->gen.scratch2); | 176 //pop_r(code, opts->gen.scratch2); |
193 mov_ir(code, inst->immed, opts->gen.scratch2, SZ_W); | 177 mov_ir(code, inst->immed, opts->gen.scratch2, SZ_W); |
194 } | 178 } |
205 if (modify) { | 189 if (modify) { |
206 //push_r(code, opts->gen.scratch1); | 190 //push_r(code, opts->gen.scratch1); |
207 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_W); | 191 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_W); |
208 } | 192 } |
209 if (size == SZ_B) { | 193 if (size == SZ_B) { |
210 call(code, (uint8_t *)z80_read_byte); | 194 call(code, opts->read_8); |
211 } else { | 195 } else { |
212 call(code, (uint8_t *)z80_read_word); | 196 call(code, opts->read_16); |
213 } | 197 } |
214 if (modify) { | 198 if (modify) { |
215 //pop_r(code, opts->gen.scratch2); | 199 //pop_r(code, opts->gen.scratch2); |
216 mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, scratch1), opts->gen.scratch2, SZ_W); | 200 mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, scratch1), opts->gen.scratch2, SZ_W); |
217 } | 201 } |
246 } | 230 } |
247 } | 231 } |
248 } | 232 } |
249 } | 233 } |
250 | 234 |
251 void z80_save_result(code_info *code, z80inst * inst) | 235 void z80_save_result(z80_options *opts, z80inst * inst) |
252 { | 236 { |
253 switch(inst->addr_mode & 0x1f) | 237 switch(inst->addr_mode & 0x1f) |
254 { | 238 { |
255 case Z80_REG_INDIRECT: | 239 case Z80_REG_INDIRECT: |
256 case Z80_IMMED_INDIRECT: | 240 case Z80_IMMED_INDIRECT: |
257 case Z80_IX_DISPLACE: | 241 case Z80_IX_DISPLACE: |
258 case Z80_IY_DISPLACE: | 242 case Z80_IY_DISPLACE: |
259 if (z80_size(inst) == SZ_B) { | 243 if (z80_size(inst) == SZ_B) { |
260 call(code, (uint8_t *)z80_write_byte); | 244 call(&opts->gen.code, opts->write_8); |
261 } else { | 245 } else { |
262 call(code, (uint8_t *)z80_write_word_lowfirst); | 246 call(&opts->gen.code, opts->write_16_lowfirst); |
263 } | 247 } |
264 } | 248 } |
265 } | 249 } |
266 | 250 |
267 enum { | 251 enum { |
367 mov_rdispr(code, src_op.base, src_op.disp, dst_op.base, size); | 351 mov_rdispr(code, src_op.base, src_op.disp, dst_op.base, size); |
368 } | 352 } |
369 z80_save_reg(inst, opts); | 353 z80_save_reg(inst, opts); |
370 z80_save_ea(code, inst, opts); | 354 z80_save_ea(code, inst, opts); |
371 if (inst->addr_mode & Z80_DIR) { | 355 if (inst->addr_mode & Z80_DIR) { |
372 z80_save_result(code, inst); | 356 z80_save_result(opts, inst); |
373 } | 357 } |
374 break; | 358 break; |
375 case Z80_PUSH: | 359 case Z80_PUSH: |
376 cycles(&opts->gen, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 9 : 5); | 360 cycles(&opts->gen, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 9 : 5); |
377 sub_ir(code, 2, opts->regs[Z80_SP], SZ_W); | 361 sub_ir(code, 2, opts->regs[Z80_SP], SZ_W); |
392 } else { | 376 } else { |
393 translate_z80_reg(inst, &src_op, opts); | 377 translate_z80_reg(inst, &src_op, opts); |
394 mov_rr(code, src_op.base, opts->gen.scratch1, SZ_W); | 378 mov_rr(code, src_op.base, opts->gen.scratch1, SZ_W); |
395 } | 379 } |
396 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); | 380 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); |
397 call(code, (uint8_t *)z80_write_word_highfirst); | 381 call(code, opts->write_16_highfirst); |
398 //no call to save_z80_reg needed since there's no chance we'll use the only | 382 //no call to save_z80_reg needed since there's no chance we'll use the only |
399 //the upper half of a register pair | 383 //the upper half of a register pair |
400 break; | 384 break; |
401 case Z80_POP: | 385 case Z80_POP: |
402 cycles(&opts->gen, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 8 : 4); | 386 cycles(&opts->gen, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 8 : 4); |
403 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); | 387 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); |
404 call(code, (uint8_t *)z80_read_word); | 388 call(code, opts->read_16); |
405 add_ir(code, 2, opts->regs[Z80_SP], SZ_W); | 389 add_ir(code, 2, opts->regs[Z80_SP], SZ_W); |
406 if (inst->reg == Z80_AF) { | 390 if (inst->reg == Z80_AF) { |
407 | 391 |
408 bt_ir(code, 0, opts->gen.scratch1, SZ_W); | 392 bt_ir(code, 0, opts->gen.scratch1, SZ_W); |
409 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); | 393 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); |
450 } else { | 434 } else { |
451 xchg_rr(code, opts->regs[Z80_DE], opts->regs[Z80_HL], SZ_W); | 435 xchg_rr(code, opts->regs[Z80_DE], opts->regs[Z80_HL], SZ_W); |
452 } | 436 } |
453 } else { | 437 } else { |
454 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); | 438 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); |
455 call(code, (uint8_t *)z80_read_byte); | 439 call(code, opts->read_8); |
456 xchg_rr(code, opts->regs[inst->reg], opts->gen.scratch1, SZ_B); | 440 xchg_rr(code, opts->regs[inst->reg], opts->gen.scratch1, SZ_B); |
457 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); | 441 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); |
458 call(code, (uint8_t *)z80_write_byte); | 442 call(code, opts->write_8); |
459 cycles(&opts->gen, 1); | 443 cycles(&opts->gen, 1); |
460 uint8_t high_reg = z80_high_reg(inst->reg); | 444 uint8_t high_reg = z80_high_reg(inst->reg); |
461 uint8_t use_reg; | 445 uint8_t use_reg; |
462 //even though some of the upper halves can be used directly | 446 //even though some of the upper halves can be used directly |
463 //the limitations on mixing *H regs with the REX prefix | 447 //the limitations on mixing *H regs with the REX prefix |
464 //prevent us from taking advantage of it | 448 //prevent us from taking advantage of it |
465 use_reg = opts->regs[inst->reg]; | 449 use_reg = opts->regs[inst->reg]; |
466 ror_ir(code, 8, use_reg, SZ_W); | 450 ror_ir(code, 8, use_reg, SZ_W); |
467 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); | 451 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); |
468 add_ir(code, 1, opts->gen.scratch1, SZ_W); | 452 add_ir(code, 1, opts->gen.scratch1, SZ_W); |
469 call(code, (uint8_t *)z80_read_byte); | 453 call(code, opts->read_8); |
470 xchg_rr(code, use_reg, opts->gen.scratch1, SZ_B); | 454 xchg_rr(code, use_reg, opts->gen.scratch1, SZ_B); |
471 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); | 455 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); |
472 add_ir(code, 1, opts->gen.scratch2, SZ_W); | 456 add_ir(code, 1, opts->gen.scratch2, SZ_W); |
473 call(code, (uint8_t *)z80_write_byte); | 457 call(code, opts->write_8); |
474 //restore reg to normal rotation | 458 //restore reg to normal rotation |
475 ror_ir(code, 8, use_reg, SZ_W); | 459 ror_ir(code, 8, use_reg, SZ_W); |
476 cycles(&opts->gen, 2); | 460 cycles(&opts->gen, 2); |
477 } | 461 } |
478 break; | 462 break; |
489 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_E), SZ_W); | 473 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_E), SZ_W); |
490 break; | 474 break; |
491 case Z80_LDI: { | 475 case Z80_LDI: { |
492 cycles(&opts->gen, 8); | 476 cycles(&opts->gen, 8); |
493 mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); | 477 mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); |
494 call(code, (uint8_t *)z80_read_byte); | 478 call(code, opts->read_8); |
495 mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); | 479 mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); |
496 call(code, (uint8_t *)z80_write_byte); | 480 call(code, opts->write_8); |
497 cycles(&opts->gen, 2); | 481 cycles(&opts->gen, 2); |
498 add_ir(code, 1, opts->regs[Z80_DE], SZ_W); | 482 add_ir(code, 1, opts->regs[Z80_DE], SZ_W); |
499 add_ir(code, 1, opts->regs[Z80_HL], SZ_W); | 483 add_ir(code, 1, opts->regs[Z80_HL], SZ_W); |
500 sub_ir(code, 1, opts->regs[Z80_BC], SZ_W); | 484 sub_ir(code, 1, opts->regs[Z80_BC], SZ_W); |
501 //TODO: Implement half-carry | 485 //TODO: Implement half-carry |
504 break; | 488 break; |
505 } | 489 } |
506 case Z80_LDIR: { | 490 case Z80_LDIR: { |
507 cycles(&opts->gen, 8); | 491 cycles(&opts->gen, 8); |
508 mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); | 492 mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); |
509 call(code, (uint8_t *)z80_read_byte); | 493 call(code, opts->read_8); |
510 mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); | 494 mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); |
511 call(code, (uint8_t *)z80_write_byte); | 495 call(code, opts->write_8); |
512 add_ir(code, 1, opts->regs[Z80_DE], SZ_W); | 496 add_ir(code, 1, opts->regs[Z80_DE], SZ_W); |
513 add_ir(code, 1, opts->regs[Z80_HL], SZ_W); | 497 add_ir(code, 1, opts->regs[Z80_HL], SZ_W); |
514 | 498 |
515 sub_ir(code, 1, opts->regs[Z80_BC], SZ_W); | 499 sub_ir(code, 1, opts->regs[Z80_BC], SZ_W); |
516 uint8_t * cont = code->cur+1; | 500 uint8_t * cont = code->cur+1; |
527 break; | 511 break; |
528 } | 512 } |
529 case Z80_LDD: { | 513 case Z80_LDD: { |
530 cycles(&opts->gen, 8); | 514 cycles(&opts->gen, 8); |
531 mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); | 515 mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); |
532 call(code, (uint8_t *)z80_read_byte); | 516 call(code, opts->read_8); |
533 mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); | 517 mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); |
534 call(code, (uint8_t *)z80_write_byte); | 518 call(code, opts->write_8); |
535 cycles(&opts->gen, 2); | 519 cycles(&opts->gen, 2); |
536 sub_ir(code, 1, opts->regs[Z80_DE], SZ_W); | 520 sub_ir(code, 1, opts->regs[Z80_DE], SZ_W); |
537 sub_ir(code, 1, opts->regs[Z80_HL], SZ_W); | 521 sub_ir(code, 1, opts->regs[Z80_HL], SZ_W); |
538 sub_ir(code, 1, opts->regs[Z80_BC], SZ_W); | 522 sub_ir(code, 1, opts->regs[Z80_BC], SZ_W); |
539 //TODO: Implement half-carry | 523 //TODO: Implement half-carry |
542 break; | 526 break; |
543 } | 527 } |
544 case Z80_LDDR: { | 528 case Z80_LDDR: { |
545 cycles(&opts->gen, 8); | 529 cycles(&opts->gen, 8); |
546 mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); | 530 mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); |
547 call(code, (uint8_t *)z80_read_byte); | 531 call(code, opts->read_8); |
548 mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); | 532 mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); |
549 call(code, (uint8_t *)z80_write_byte); | 533 call(code, opts->write_8); |
550 sub_ir(code, 1, opts->regs[Z80_DE], SZ_W); | 534 sub_ir(code, 1, opts->regs[Z80_DE], SZ_W); |
551 sub_ir(code, 1, opts->regs[Z80_HL], SZ_W); | 535 sub_ir(code, 1, opts->regs[Z80_HL], SZ_W); |
552 | 536 |
553 sub_ir(code, 1, opts->regs[Z80_BC], SZ_W); | 537 sub_ir(code, 1, opts->regs[Z80_BC], SZ_W); |
554 uint8_t * cont = code->cur+1; | 538 uint8_t * cont = code->cur+1; |
808 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); | 792 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); |
809 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); | 793 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); |
810 } | 794 } |
811 z80_save_reg(inst, opts); | 795 z80_save_reg(inst, opts); |
812 z80_save_ea(code, inst, opts); | 796 z80_save_ea(code, inst, opts); |
813 z80_save_result(code, inst); | 797 z80_save_result(opts, inst); |
814 break; | 798 break; |
815 case Z80_DEC: | 799 case Z80_DEC: |
816 num_cycles = 4; | 800 num_cycles = 4; |
817 if (inst->reg == Z80_IX || inst->reg == Z80_IY) { | 801 if (inst->reg == Z80_IX || inst->reg == Z80_IY) { |
818 num_cycles += 6; | 802 num_cycles += 6; |
834 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); | 818 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); |
835 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); | 819 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); |
836 } | 820 } |
837 z80_save_reg(inst, opts); | 821 z80_save_reg(inst, opts); |
838 z80_save_ea(code, inst, opts); | 822 z80_save_ea(code, inst, opts); |
839 z80_save_result(code, inst); | 823 z80_save_result(opts, inst); |
840 break; | 824 break; |
841 //case Z80_DAA: | 825 //case Z80_DAA: |
842 case Z80_CPL: | 826 case Z80_CPL: |
843 cycles(&opts->gen, 4); | 827 cycles(&opts->gen, 4); |
844 not_r(code, opts->regs[Z80_A], SZ_B); | 828 not_r(code, opts->regs[Z80_A], SZ_B); |
867 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); | 851 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); |
868 //TODO: Implement half-carry flag | 852 //TODO: Implement half-carry flag |
869 break; | 853 break; |
870 case Z80_NOP: | 854 case Z80_NOP: |
871 if (inst->immed == 42) { | 855 if (inst->immed == 42) { |
872 call(code, (uint8_t *)z80_save_context); | 856 call(code, opts->gen.save_context); |
873 mov_rr(code, opts->gen.context_reg, RDI, SZ_Q); | 857 mov_rr(code, opts->gen.context_reg, RDI, SZ_Q); |
874 jmp(code, (uint8_t *)z80_print_regs_exit); | 858 jmp(code, (uint8_t *)z80_print_regs_exit); |
875 } else { | 859 } else { |
876 cycles(&opts->gen, 4 * inst->immed); | 860 cycles(&opts->gen, 4 * inst->immed); |
877 } | 861 } |
878 break; | 862 break; |
879 case Z80_HALT: | 863 case Z80_HALT: { |
880 cycles(&opts->gen, 4); | 864 cycles(&opts->gen, 4); |
881 mov_ir(code, address, opts->gen.scratch1, SZ_W); | 865 mov_ir(code, address, opts->gen.scratch1, SZ_W); |
882 uint8_t * call_inst = code->cur; | 866 uint8_t * call_inst = code->cur; |
883 call(code, (uint8_t *)z80_halt); | 867 mov_rr(code, opts->gen.limit, opts->gen.scratch2, SZ_D); |
868 sub_rr(code, opts->gen.cycles, opts->gen.scratch2, SZ_D); | |
869 and_ir(code, 0xFFFFFFFC, opts->gen.scratch2, SZ_D); | |
870 add_rr(code, opts->gen.scratch2, opts->gen.cycles, SZ_D); | |
871 cmp_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D); | |
872 code_ptr skip_last = code->cur+1; | |
873 jcc(code, CC_B, opts->gen.handle_cycle_limit_int); | |
874 cycles(&opts->gen, 4); | |
875 *skip_last = code->cur - (skip_last+1); | |
876 call(code, opts->gen.handle_cycle_limit_int); | |
884 jmp(code, call_inst); | 877 jmp(code, call_inst); |
885 break; | 878 break; |
879 } | |
886 case Z80_DI: | 880 case Z80_DI: |
887 cycles(&opts->gen, 4); | 881 cycles(&opts->gen, 4); |
888 mov_irdisp(code, 0, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B); | 882 mov_irdisp(code, 0, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B); |
889 mov_irdisp(code, 0, opts->gen.context_reg, offsetof(z80_context, iff2), SZ_B); | 883 mov_irdisp(code, 0, opts->gen.context_reg, offsetof(z80_context, iff2), SZ_B); |
890 mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, sync_cycle), opts->gen.limit, SZ_D); | 884 mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, sync_cycle), opts->gen.limit, SZ_D); |
895 mov_rrdisp(code, opts->gen.cycles, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D); | 889 mov_rrdisp(code, opts->gen.cycles, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D); |
896 mov_irdisp(code, 1, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B); | 890 mov_irdisp(code, 1, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B); |
897 mov_irdisp(code, 1, opts->gen.context_reg, offsetof(z80_context, iff2), SZ_B); | 891 mov_irdisp(code, 1, opts->gen.context_reg, offsetof(z80_context, iff2), SZ_B); |
898 //interrupt enable has a one-instruction latency, minimum instruction duration is 4 cycles | 892 //interrupt enable has a one-instruction latency, minimum instruction duration is 4 cycles |
899 add_irdisp(code, 4, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D); | 893 add_irdisp(code, 4, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D); |
900 call(code, (uint8_t *)z80_do_sync); | 894 call(code, opts->do_sync); |
901 break; | 895 break; |
902 case Z80_IM: | 896 case Z80_IM: |
903 cycles(&opts->gen, 4); | 897 cycles(&opts->gen, 4); |
904 mov_irdisp(code, inst->immed, opts->gen.context_reg, offsetof(z80_context, im), SZ_B); | 898 mov_irdisp(code, inst->immed, opts->gen.context_reg, offsetof(z80_context, im), SZ_B); |
905 break; | 899 break; |
924 cmp_ir(code, 0, dst_op.base, SZ_B); | 918 cmp_ir(code, 0, dst_op.base, SZ_B); |
925 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); | 919 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); |
926 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); | 920 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); |
927 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); | 921 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); |
928 if (inst->addr_mode != Z80_UNUSED) { | 922 if (inst->addr_mode != Z80_UNUSED) { |
929 z80_save_result(code, inst); | 923 z80_save_result(opts, inst); |
930 if (src_op.mode != MODE_UNUSED) { | 924 if (src_op.mode != MODE_UNUSED) { |
931 z80_save_reg(inst, opts); | 925 z80_save_reg(inst, opts); |
932 } | 926 } |
933 } else { | 927 } else { |
934 z80_save_reg(inst, opts); | 928 z80_save_reg(inst, opts); |
956 cmp_ir(code, 0, dst_op.base, SZ_B); | 950 cmp_ir(code, 0, dst_op.base, SZ_B); |
957 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); | 951 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); |
958 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); | 952 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); |
959 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); | 953 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); |
960 if (inst->addr_mode != Z80_UNUSED) { | 954 if (inst->addr_mode != Z80_UNUSED) { |
961 z80_save_result(code, inst); | 955 z80_save_result(opts, inst); |
962 if (src_op.mode != MODE_UNUSED) { | 956 if (src_op.mode != MODE_UNUSED) { |
963 z80_save_reg(inst, opts); | 957 z80_save_reg(inst, opts); |
964 } | 958 } |
965 } else { | 959 } else { |
966 z80_save_reg(inst, opts); | 960 z80_save_reg(inst, opts); |
987 cmp_ir(code, 0, dst_op.base, SZ_B); | 981 cmp_ir(code, 0, dst_op.base, SZ_B); |
988 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); | 982 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); |
989 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); | 983 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); |
990 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); | 984 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); |
991 if (inst->addr_mode != Z80_UNUSED) { | 985 if (inst->addr_mode != Z80_UNUSED) { |
992 z80_save_result(code, inst); | 986 z80_save_result(opts, inst); |
993 if (src_op.mode != MODE_UNUSED) { | 987 if (src_op.mode != MODE_UNUSED) { |
994 z80_save_reg(inst, opts); | 988 z80_save_reg(inst, opts); |
995 } | 989 } |
996 } else { | 990 } else { |
997 z80_save_reg(inst, opts); | 991 z80_save_reg(inst, opts); |
1019 cmp_ir(code, 0, dst_op.base, SZ_B); | 1013 cmp_ir(code, 0, dst_op.base, SZ_B); |
1020 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); | 1014 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); |
1021 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); | 1015 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); |
1022 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); | 1016 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); |
1023 if (inst->addr_mode != Z80_UNUSED) { | 1017 if (inst->addr_mode != Z80_UNUSED) { |
1024 z80_save_result(code, inst); | 1018 z80_save_result(opts, inst); |
1025 if (src_op.mode != MODE_UNUSED) { | 1019 if (src_op.mode != MODE_UNUSED) { |
1026 z80_save_reg(inst, opts); | 1020 z80_save_reg(inst, opts); |
1027 } | 1021 } |
1028 } else { | 1022 } else { |
1029 z80_save_reg(inst, opts); | 1023 z80_save_reg(inst, opts); |
1054 cmp_ir(code, 0, dst_op.base, SZ_B); | 1048 cmp_ir(code, 0, dst_op.base, SZ_B); |
1055 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); | 1049 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); |
1056 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); | 1050 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); |
1057 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); | 1051 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); |
1058 if (inst->addr_mode != Z80_UNUSED) { | 1052 if (inst->addr_mode != Z80_UNUSED) { |
1059 z80_save_result(code, inst); | 1053 z80_save_result(opts, inst); |
1060 if (src_op.mode != MODE_UNUSED) { | 1054 if (src_op.mode != MODE_UNUSED) { |
1061 z80_save_reg(inst, opts); | 1055 z80_save_reg(inst, opts); |
1062 } | 1056 } |
1063 } else { | 1057 } else { |
1064 z80_save_reg(inst, opts); | 1058 z80_save_reg(inst, opts); |
1085 cmp_ir(code, 0, dst_op.base, SZ_B); | 1079 cmp_ir(code, 0, dst_op.base, SZ_B); |
1086 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); | 1080 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); |
1087 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); | 1081 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); |
1088 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); | 1082 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); |
1089 if (inst->addr_mode != Z80_UNUSED) { | 1083 if (inst->addr_mode != Z80_UNUSED) { |
1090 z80_save_result(code, inst); | 1084 z80_save_result(opts, inst); |
1091 if (src_op.mode != MODE_UNUSED) { | 1085 if (src_op.mode != MODE_UNUSED) { |
1092 z80_save_reg(inst, opts); | 1086 z80_save_reg(inst, opts); |
1093 } | 1087 } |
1094 } else { | 1088 } else { |
1095 z80_save_reg(inst, opts); | 1089 z80_save_reg(inst, opts); |
1116 cmp_ir(code, 0, dst_op.base, SZ_B); | 1110 cmp_ir(code, 0, dst_op.base, SZ_B); |
1117 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); | 1111 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); |
1118 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); | 1112 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); |
1119 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); | 1113 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); |
1120 if (inst->addr_mode != Z80_UNUSED) { | 1114 if (inst->addr_mode != Z80_UNUSED) { |
1121 z80_save_result(code, inst); | 1115 z80_save_result(opts, inst); |
1122 if (src_op.mode != MODE_UNUSED) { | 1116 if (src_op.mode != MODE_UNUSED) { |
1123 z80_save_reg(inst, opts); | 1117 z80_save_reg(inst, opts); |
1124 } | 1118 } |
1125 } else { | 1119 } else { |
1126 z80_save_reg(inst, opts); | 1120 z80_save_reg(inst, opts); |
1127 } | 1121 } |
1128 break; | 1122 break; |
1129 case Z80_RLD: | 1123 case Z80_RLD: |
1130 cycles(&opts->gen, 8); | 1124 cycles(&opts->gen, 8); |
1131 mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); | 1125 mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); |
1132 call(code, (uint8_t *)z80_read_byte); | 1126 call(code, opts->read_8); |
1133 //Before: (HL) = 0x12, A = 0x34 | 1127 //Before: (HL) = 0x12, A = 0x34 |
1134 //After: (HL) = 0x24, A = 0x31 | 1128 //After: (HL) = 0x24, A = 0x31 |
1135 mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B); | 1129 mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B); |
1136 shl_ir(code, 4, opts->gen.scratch1, SZ_W); | 1130 shl_ir(code, 4, opts->gen.scratch1, SZ_W); |
1137 and_ir(code, 0xF, opts->gen.scratch2, SZ_W); | 1131 and_ir(code, 0xF, opts->gen.scratch2, SZ_W); |
1149 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); | 1143 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); |
1150 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); | 1144 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); |
1151 | 1145 |
1152 mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W); | 1146 mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W); |
1153 ror_ir(code, 8, opts->gen.scratch1, SZ_W); | 1147 ror_ir(code, 8, opts->gen.scratch1, SZ_W); |
1154 call(code, (uint8_t *)z80_write_byte); | 1148 call(code, opts->write_8); |
1155 break; | 1149 break; |
1156 case Z80_RRD: | 1150 case Z80_RRD: |
1157 cycles(&opts->gen, 8); | 1151 cycles(&opts->gen, 8); |
1158 mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); | 1152 mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); |
1159 call(code, (uint8_t *)z80_read_byte); | 1153 call(code, opts->read_8); |
1160 //Before: (HL) = 0x12, A = 0x34 | 1154 //Before: (HL) = 0x12, A = 0x34 |
1161 //After: (HL) = 0x41, A = 0x32 | 1155 //After: (HL) = 0x41, A = 0x32 |
1162 movzx_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B, SZ_W); | 1156 movzx_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B, SZ_W); |
1163 ror_ir(code, 4, opts->gen.scratch1, SZ_W); | 1157 ror_ir(code, 4, opts->gen.scratch1, SZ_W); |
1164 shl_ir(code, 4, opts->gen.scratch2, SZ_W); | 1158 shl_ir(code, 4, opts->gen.scratch2, SZ_W); |
1179 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); | 1173 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); |
1180 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); | 1174 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); |
1181 | 1175 |
1182 mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W); | 1176 mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W); |
1183 ror_ir(code, 8, opts->gen.scratch1, SZ_W); | 1177 ror_ir(code, 8, opts->gen.scratch1, SZ_W); |
1184 call(code, (uint8_t *)z80_write_byte); | 1178 call(code, opts->write_8); |
1185 break; | 1179 break; |
1186 case Z80_BIT: { | 1180 case Z80_BIT: { |
1187 num_cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16; | 1181 num_cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16; |
1188 cycles(&opts->gen, num_cycles); | 1182 cycles(&opts->gen, num_cycles); |
1189 uint8_t bit; | 1183 uint8_t bit; |
1245 } else { | 1239 } else { |
1246 mov_rr(code, src_op.base, dst_op.base, SZ_B); | 1240 mov_rr(code, src_op.base, dst_op.base, SZ_B); |
1247 } | 1241 } |
1248 } | 1242 } |
1249 if ((inst->addr_mode & 0x1F) != Z80_REG) { | 1243 if ((inst->addr_mode & 0x1F) != Z80_REG) { |
1250 z80_save_result(code, inst); | 1244 z80_save_result(opts, inst); |
1251 if (inst->reg != Z80_USE_IMMED) { | 1245 if (inst->reg != Z80_USE_IMMED) { |
1252 z80_save_reg(inst, opts); | 1246 z80_save_reg(inst, opts); |
1253 } | 1247 } |
1254 } | 1248 } |
1255 break; | 1249 break; |
1287 } else { | 1281 } else { |
1288 mov_rr(code, src_op.base, dst_op.base, SZ_B); | 1282 mov_rr(code, src_op.base, dst_op.base, SZ_B); |
1289 } | 1283 } |
1290 } | 1284 } |
1291 if (inst->addr_mode != Z80_REG) { | 1285 if (inst->addr_mode != Z80_REG) { |
1292 z80_save_result(code, inst); | 1286 z80_save_result(opts, inst); |
1293 if (inst->reg != Z80_USE_IMMED) { | 1287 if (inst->reg != Z80_USE_IMMED) { |
1294 z80_save_reg(inst, opts); | 1288 z80_save_reg(inst, opts); |
1295 } | 1289 } |
1296 } | 1290 } |
1297 break; | 1291 break; |
1316 if (inst->addr_mode == Z80_REG_INDIRECT) { | 1310 if (inst->addr_mode == Z80_REG_INDIRECT) { |
1317 mov_rr(code, opts->regs[inst->ea_reg], opts->gen.scratch1, SZ_W); | 1311 mov_rr(code, opts->regs[inst->ea_reg], opts->gen.scratch1, SZ_W); |
1318 } else { | 1312 } else { |
1319 mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W); | 1313 mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W); |
1320 } | 1314 } |
1321 call(code, (uint8_t *)z80_native_addr); | 1315 call(code, opts->native_addr); |
1322 jmp_r(code, opts->gen.scratch1); | 1316 jmp_r(code, opts->gen.scratch1); |
1323 } | 1317 } |
1324 break; | 1318 break; |
1325 } | 1319 } |
1326 case Z80_JPCC: { | 1320 case Z80_JPCC: { |
1361 call_dst + 256; | 1355 call_dst + 256; |
1362 } | 1356 } |
1363 jmp(code, call_dst); | 1357 jmp(code, call_dst); |
1364 } else { | 1358 } else { |
1365 mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W); | 1359 mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W); |
1366 call(code, (uint8_t *)z80_native_addr); | 1360 call(code, opts->native_addr); |
1367 jmp_r(code, opts->gen.scratch1); | 1361 jmp_r(code, opts->gen.scratch1); |
1368 } | 1362 } |
1369 *no_jump_off = code->cur - (no_jump_off+1); | 1363 *no_jump_off = code->cur - (no_jump_off+1); |
1370 break; | 1364 break; |
1371 } | 1365 } |
1380 call_dst + 256; | 1374 call_dst + 256; |
1381 } | 1375 } |
1382 jmp(code, call_dst); | 1376 jmp(code, call_dst); |
1383 } else { | 1377 } else { |
1384 mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W); | 1378 mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W); |
1385 call(code, (uint8_t *)z80_native_addr); | 1379 call(code, opts->native_addr); |
1386 jmp_r(code, opts->gen.scratch1); | 1380 jmp_r(code, opts->gen.scratch1); |
1387 } | 1381 } |
1388 break; | 1382 break; |
1389 } | 1383 } |
1390 case Z80_JRCC: { | 1384 case Z80_JRCC: { |
1415 call_dst + 256; | 1409 call_dst + 256; |
1416 } | 1410 } |
1417 jmp(code, call_dst); | 1411 jmp(code, call_dst); |
1418 } else { | 1412 } else { |
1419 mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W); | 1413 mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W); |
1420 call(code, (uint8_t *)z80_native_addr); | 1414 call(code, opts->native_addr); |
1421 jmp_r(code, opts->gen.scratch1); | 1415 jmp_r(code, opts->gen.scratch1); |
1422 } | 1416 } |
1423 *no_jump_off = code->cur - (no_jump_off+1); | 1417 *no_jump_off = code->cur - (no_jump_off+1); |
1424 break; | 1418 break; |
1425 } | 1419 } |
1438 call_dst + 256; | 1432 call_dst + 256; |
1439 } | 1433 } |
1440 jmp(code, call_dst); | 1434 jmp(code, call_dst); |
1441 } else { | 1435 } else { |
1442 mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W); | 1436 mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W); |
1443 call(code, (uint8_t *)z80_native_addr); | 1437 call(code, opts->native_addr); |
1444 jmp_r(code, opts->gen.scratch1); | 1438 jmp_r(code, opts->gen.scratch1); |
1445 } | 1439 } |
1446 *no_jump_off = code->cur - (no_jump_off+1); | 1440 *no_jump_off = code->cur - (no_jump_off+1); |
1447 break; | 1441 break; |
1448 case Z80_CALL: { | 1442 case Z80_CALL: { |
1449 cycles(&opts->gen, 11);//T States: 4,3,4 | 1443 cycles(&opts->gen, 11);//T States: 4,3,4 |
1450 sub_ir(code, 2, opts->regs[Z80_SP], SZ_W); | 1444 sub_ir(code, 2, opts->regs[Z80_SP], SZ_W); |
1451 mov_ir(code, address + 3, opts->gen.scratch1, SZ_W); | 1445 mov_ir(code, address + 3, opts->gen.scratch1, SZ_W); |
1452 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); | 1446 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); |
1453 call(code, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3 | 1447 call(code, opts->write_16_highfirst);//T States: 3, 3 |
1454 if (inst->immed < 0x4000) { | 1448 if (inst->immed < 0x4000) { |
1455 code_ptr call_dst = z80_get_native_address(context, inst->immed); | 1449 code_ptr call_dst = z80_get_native_address(context, inst->immed); |
1456 if (!call_dst) { | 1450 if (!call_dst) { |
1457 opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1); | 1451 opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1); |
1458 //fake address to force large displacement | 1452 //fake address to force large displacement |
1459 call_dst + 256; | 1453 call_dst + 256; |
1460 } | 1454 } |
1461 jmp(code, call_dst); | 1455 jmp(code, call_dst); |
1462 } else { | 1456 } else { |
1463 mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W); | 1457 mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W); |
1464 call(code, (uint8_t *)z80_native_addr); | 1458 call(code, opts->native_addr); |
1465 jmp_r(code, opts->gen.scratch1); | 1459 jmp_r(code, opts->gen.scratch1); |
1466 } | 1460 } |
1467 break; | 1461 break; |
1468 } | 1462 } |
1469 case Z80_CALLCC: | 1463 case Z80_CALLCC: |
1496 jcc(code, cond, code->cur+2); | 1490 jcc(code, cond, code->cur+2); |
1497 cycles(&opts->gen, 1);//Last of the above T states takes an extra cycle in the true case | 1491 cycles(&opts->gen, 1);//Last of the above T states takes an extra cycle in the true case |
1498 sub_ir(code, 2, opts->regs[Z80_SP], SZ_W); | 1492 sub_ir(code, 2, opts->regs[Z80_SP], SZ_W); |
1499 mov_ir(code, address + 3, opts->gen.scratch1, SZ_W); | 1493 mov_ir(code, address + 3, opts->gen.scratch1, SZ_W); |
1500 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); | 1494 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); |
1501 call(code, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3 | 1495 call(code, opts->write_16_highfirst);//T States: 3, 3 |
1502 if (inst->immed < 0x4000) { | 1496 if (inst->immed < 0x4000) { |
1503 code_ptr call_dst = z80_get_native_address(context, inst->immed); | 1497 code_ptr call_dst = z80_get_native_address(context, inst->immed); |
1504 if (!call_dst) { | 1498 if (!call_dst) { |
1505 opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1); | 1499 opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1); |
1506 //fake address to force large displacement | 1500 //fake address to force large displacement |
1507 call_dst + 256; | 1501 call_dst + 256; |
1508 } | 1502 } |
1509 jmp(code, call_dst); | 1503 jmp(code, call_dst); |
1510 } else { | 1504 } else { |
1511 mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W); | 1505 mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W); |
1512 call(code, (uint8_t *)z80_native_addr); | 1506 call(code, opts->native_addr); |
1513 jmp_r(code, opts->gen.scratch1); | 1507 jmp_r(code, opts->gen.scratch1); |
1514 } | 1508 } |
1515 *no_call_off = code->cur - (no_call_off+1); | 1509 *no_call_off = code->cur - (no_call_off+1); |
1516 break; | 1510 break; |
1517 case Z80_RET: | 1511 case Z80_RET: |
1518 cycles(&opts->gen, 4);//T States: 4 | 1512 cycles(&opts->gen, 4);//T States: 4 |
1519 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); | 1513 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); |
1520 call(code, (uint8_t *)z80_read_word);//T STates: 3, 3 | 1514 call(code, opts->read_16);//T STates: 3, 3 |
1521 add_ir(code, 2, opts->regs[Z80_SP], SZ_W); | 1515 add_ir(code, 2, opts->regs[Z80_SP], SZ_W); |
1522 call(code, (uint8_t *)z80_native_addr); | 1516 call(code, opts->native_addr); |
1523 jmp_r(code, opts->gen.scratch1); | 1517 jmp_r(code, opts->gen.scratch1); |
1524 break; | 1518 break; |
1525 case Z80_RETCC: { | 1519 case Z80_RETCC: { |
1526 cycles(&opts->gen, 5);//T States: 5 | 1520 cycles(&opts->gen, 5);//T States: 5 |
1527 uint8_t cond = CC_Z; | 1521 uint8_t cond = CC_Z; |
1549 break; | 1543 break; |
1550 } | 1544 } |
1551 uint8_t *no_call_off = code->cur+1; | 1545 uint8_t *no_call_off = code->cur+1; |
1552 jcc(code, cond, code->cur+2); | 1546 jcc(code, cond, code->cur+2); |
1553 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); | 1547 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); |
1554 call(code, (uint8_t *)z80_read_word);//T STates: 3, 3 | 1548 call(code, opts->read_16);//T STates: 3, 3 |
1555 add_ir(code, 2, opts->regs[Z80_SP], SZ_W); | 1549 add_ir(code, 2, opts->regs[Z80_SP], SZ_W); |
1556 call(code, (uint8_t *)z80_native_addr); | 1550 call(code, opts->native_addr); |
1557 jmp_r(code, opts->gen.scratch1); | 1551 jmp_r(code, opts->gen.scratch1); |
1558 *no_call_off = code->cur - (no_call_off+1); | 1552 *no_call_off = code->cur - (no_call_off+1); |
1559 break; | 1553 break; |
1560 } | 1554 } |
1561 case Z80_RETI: | 1555 case Z80_RETI: |
1562 //For some systems, this may need a callback for signalling interrupt routine completion | 1556 //For some systems, this may need a callback for signalling interrupt routine completion |
1563 cycles(&opts->gen, 8);//T States: 4, 4 | 1557 cycles(&opts->gen, 8);//T States: 4, 4 |
1564 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); | 1558 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); |
1565 call(code, (uint8_t *)z80_read_word);//T STates: 3, 3 | 1559 call(code, opts->read_16);//T STates: 3, 3 |
1566 add_ir(code, 2, opts->regs[Z80_SP], SZ_W); | 1560 add_ir(code, 2, opts->regs[Z80_SP], SZ_W); |
1567 call(code, (uint8_t *)z80_native_addr); | 1561 call(code, opts->native_addr); |
1568 jmp_r(code, opts->gen.scratch1); | 1562 jmp_r(code, opts->gen.scratch1); |
1569 break; | 1563 break; |
1570 case Z80_RETN: | 1564 case Z80_RETN: |
1571 cycles(&opts->gen, 8);//T States: 4, 4 | 1565 cycles(&opts->gen, 8);//T States: 4, 4 |
1572 mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, iff2), opts->gen.scratch2, SZ_B); | 1566 mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, iff2), opts->gen.scratch2, SZ_B); |
1573 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); | 1567 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); |
1574 mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B); | 1568 mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B); |
1575 call(code, (uint8_t *)z80_read_word);//T STates: 3, 3 | 1569 call(code, opts->read_16);//T STates: 3, 3 |
1576 add_ir(code, 2, opts->regs[Z80_SP], SZ_W); | 1570 add_ir(code, 2, opts->regs[Z80_SP], SZ_W); |
1577 call(code, (uint8_t *)z80_native_addr); | 1571 call(code, opts->native_addr); |
1578 jmp_r(code, opts->gen.scratch1); | 1572 jmp_r(code, opts->gen.scratch1); |
1579 break; | 1573 break; |
1580 case Z80_RST: { | 1574 case Z80_RST: { |
1581 //RST is basically CALL to an address in page 0 | 1575 //RST is basically CALL to an address in page 0 |
1582 cycles(&opts->gen, 5);//T States: 5 | 1576 cycles(&opts->gen, 5);//T States: 5 |
1583 sub_ir(code, 2, opts->regs[Z80_SP], SZ_W); | 1577 sub_ir(code, 2, opts->regs[Z80_SP], SZ_W); |
1584 mov_ir(code, address + 1, opts->gen.scratch1, SZ_W); | 1578 mov_ir(code, address + 1, opts->gen.scratch1, SZ_W); |
1585 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); | 1579 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); |
1586 call(code, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3 | 1580 call(code, opts->write_16_highfirst);//T States: 3, 3 |
1587 code_ptr call_dst = z80_get_native_address(context, inst->immed); | 1581 code_ptr call_dst = z80_get_native_address(context, inst->immed); |
1588 if (!call_dst) { | 1582 if (!call_dst) { |
1589 opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1); | 1583 opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1); |
1590 //fake address to force large displacement | 1584 //fake address to force large displacement |
1591 call_dst + 256; | 1585 call_dst + 256; |
1598 if (inst->addr_mode == Z80_IMMED_INDIRECT) { | 1592 if (inst->addr_mode == Z80_IMMED_INDIRECT) { |
1599 mov_ir(code, inst->immed, opts->gen.scratch1, SZ_B); | 1593 mov_ir(code, inst->immed, opts->gen.scratch1, SZ_B); |
1600 } else { | 1594 } else { |
1601 mov_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B); | 1595 mov_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B); |
1602 } | 1596 } |
1603 call(code, (uint8_t *)z80_io_read); | 1597 call(code, opts->read_io); |
1604 translate_z80_reg(inst, &dst_op, opts); | 1598 translate_z80_reg(inst, &dst_op, opts); |
1605 mov_rr(code, opts->gen.scratch1, dst_op.base, SZ_B); | 1599 mov_rr(code, opts->gen.scratch1, dst_op.base, SZ_B); |
1606 z80_save_reg(inst, opts); | 1600 z80_save_reg(inst, opts); |
1607 break; | 1601 break; |
1608 /*case Z80_INI: | 1602 /*case Z80_INI: |
1616 } else { | 1610 } else { |
1617 mov_rr(code, opts->regs[Z80_C], opts->gen.scratch2, SZ_B); | 1611 mov_rr(code, opts->regs[Z80_C], opts->gen.scratch2, SZ_B); |
1618 } | 1612 } |
1619 translate_z80_reg(inst, &src_op, opts); | 1613 translate_z80_reg(inst, &src_op, opts); |
1620 mov_rr(code, dst_op.base, opts->gen.scratch1, SZ_B); | 1614 mov_rr(code, dst_op.base, opts->gen.scratch1, SZ_B); |
1621 call(code, (uint8_t *)z80_io_write); | 1615 call(code, opts->write_io); |
1622 z80_save_reg(inst, opts); | 1616 z80_save_reg(inst, opts); |
1623 break; | 1617 break; |
1624 /*case Z80_OUTI: | 1618 /*case Z80_OUTI: |
1625 case Z80_OTIR: | 1619 case Z80_OTIR: |
1626 case Z80_OUTD: | 1620 case Z80_OUTD: |
1735 code_ptr dst = z80_get_native_address(context, inst_start); | 1729 code_ptr dst = z80_get_native_address(context, inst_start); |
1736 code_info code = {dst, dst+16}; | 1730 code_info code = {dst, dst+16}; |
1737 z80_options * opts = context->options; | 1731 z80_options * opts = context->options; |
1738 dprintf("patching code at %p for Z80 instruction at %X due to write to %X\n", code, inst_start, address); | 1732 dprintf("patching code at %p for Z80 instruction at %X due to write to %X\n", code, inst_start, address); |
1739 mov_ir(&code, inst_start, opts->gen.scratch1, SZ_D); | 1733 mov_ir(&code, inst_start, opts->gen.scratch1, SZ_D); |
1740 call(&code, (uint8_t *)z80_retrans_stub); | 1734 call(&code, opts->retrans_stub); |
1741 } | 1735 } |
1742 return context; | 1736 return context; |
1743 } | 1737 } |
1744 | 1738 |
1745 uint8_t * z80_get_native_address_trans(z80_context * context, uint32_t address) | 1739 uint8_t * z80_get_native_address_trans(z80_context * context, uint32_t address) |
1957 for (int i = 0; i <= Z80_A; i++) | 1951 for (int i = 0; i <= Z80_A; i++) |
1958 { | 1952 { |
1959 int reg; | 1953 int reg; |
1960 uint8_t size; | 1954 uint8_t size; |
1961 if (i < Z80_I) { | 1955 if (i < Z80_I) { |
1962 int reg = i /2 + Z80_BC; | 1956 reg = i /2 + Z80_BC; |
1963 size = SZ_W; | 1957 size = SZ_W; |
1958 i++; | |
1964 | 1959 |
1965 } else { | 1960 } else { |
1966 reg = i; | 1961 reg = i; |
1967 size = SZ_B; | 1962 size = SZ_B; |
1968 } | 1963 } |
1975 } | 1970 } |
1976 mov_rrdisp(code, options->gen.limit, options->gen.context_reg, offsetof(z80_context, target_cycle), SZ_D); | 1971 mov_rrdisp(code, options->gen.limit, options->gen.context_reg, offsetof(z80_context, target_cycle), SZ_D); |
1977 mov_rrdisp(code, options->gen.cycles, options->gen.context_reg, offsetof(z80_context, current_cycle), SZ_D); | 1972 mov_rrdisp(code, options->gen.cycles, options->gen.context_reg, offsetof(z80_context, current_cycle), SZ_D); |
1978 mov_rrdisp(code, options->bank_reg, options->gen.context_reg, offsetof(z80_context, bank_reg), SZ_W); | 1973 mov_rrdisp(code, options->bank_reg, options->gen.context_reg, offsetof(z80_context, bank_reg), SZ_W); |
1979 mov_rrdisp(code, options->bank_pointer, options->gen.context_reg, offsetof(z80_context, mem_pointers) + sizeof(uint8_t *) * 1, SZ_PTR); | 1974 mov_rrdisp(code, options->bank_pointer, options->gen.context_reg, offsetof(z80_context, mem_pointers) + sizeof(uint8_t *) * 1, SZ_PTR); |
1975 retn(code); | |
1980 | 1976 |
1981 options->load_context_scratch = code->cur; | 1977 options->load_context_scratch = code->cur; |
1982 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, scratch1), options->gen.scratch1, SZ_W); | 1978 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, scratch1), options->gen.scratch1, SZ_W); |
1983 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, scratch2), options->gen.scratch2, SZ_W); | 1979 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, scratch2), options->gen.scratch2, SZ_W); |
1984 options->gen.load_context = code->cur; | 1980 options->gen.load_context = code->cur; |
2003 } | 1999 } |
2004 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, target_cycle), options->gen.limit, SZ_D); | 2000 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, target_cycle), options->gen.limit, SZ_D); |
2005 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, current_cycle), options->gen.cycles, SZ_D); | 2001 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, current_cycle), options->gen.cycles, SZ_D); |
2006 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, bank_reg), options->bank_reg, SZ_W); | 2002 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, bank_reg), options->bank_reg, SZ_W); |
2007 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, mem_pointers) + sizeof(uint8_t *) * 1, options->bank_pointer, SZ_PTR); | 2003 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, mem_pointers) + sizeof(uint8_t *) * 1, options->bank_pointer, SZ_PTR); |
2004 retn(code); | |
2005 | |
2006 options->native_addr = code->cur; | |
2007 call(code, options->gen.save_context); | |
2008 push_r(code, options->gen.context_reg); | |
2009 mov_rr(code, options->gen.context_reg, RDI, SZ_PTR); | |
2010 movzx_rr(code, options->gen.scratch1, RSI, SZ_W, SZ_D); | |
2011 call(code, (code_ptr)z80_get_native_address_trans); | |
2012 mov_rr(code, RAX, options->gen.scratch1, SZ_PTR); | |
2013 pop_r(code, options->gen.context_reg); | |
2014 call(code, options->gen.load_context); | |
2015 retn(code); | |
2008 | 2016 |
2009 options->gen.handle_cycle_limit = code->cur; | 2017 options->gen.handle_cycle_limit = code->cur; |
2010 cmp_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.cycles, SZ_D); | 2018 cmp_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.cycles, SZ_D); |
2011 code_ptr no_sync = code->cur+1; | 2019 code_ptr no_sync = code->cur+1; |
2012 jcc(code, CC_B, no_sync); | 2020 jcc(code, CC_B, no_sync); |
2063 call(code, options->write_8_noinc); | 2071 call(code, options->write_8_noinc); |
2064 //dispose of return address as we'll be jumping somewhere else | 2072 //dispose of return address as we'll be jumping somewhere else |
2065 pop_r(code, options->gen.scratch2); | 2073 pop_r(code, options->gen.scratch2); |
2066 //TODO: Support interrupt mode 0 and 2 | 2074 //TODO: Support interrupt mode 0 and 2 |
2067 mov_ir(code, 0x38, options->gen.scratch1, SZ_W); | 2075 mov_ir(code, 0x38, options->gen.scratch1, SZ_W); |
2068 call(code, (code_ptr)z80_native_addr); | 2076 call(code, options->native_addr); |
2069 jmp_r(code, options->gen.scratch1); | 2077 jmp_r(code, options->gen.scratch1); |
2078 *skip_int = code->cur - (skip_int+1); | |
2079 cmp_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.cycles, SZ_D); | |
2080 code_ptr skip_sync = code->cur + 1; | |
2081 jcc(code, CC_B, skip_sync); | |
2082 options->do_sync = code->cur; | |
2083 call(code, options->gen.save_context); | |
2084 pop_rind(code, options->gen.context_reg); | |
2085 //restore callee saved registers | |
2086 pop_r(code, R15); | |
2087 pop_r(code, R14); | |
2088 pop_r(code, R13); | |
2089 pop_r(code, R12); | |
2090 pop_r(code, RBP); | |
2091 pop_r(code, RBX); | |
2092 //return to caller of z80_run | |
2093 *skip_sync = code->cur - (skip_sync+1); | |
2094 retn(code); | |
2095 | |
2096 options->read_io = code->cur; | |
2097 check_cycles(&options->gen); | |
2098 cycles(&options->gen, 4); | |
2099 //Genesis has no IO hardware and always returns FF | |
2100 //eventually this should use a second memory map array | |
2101 mov_ir(code, 0xFF, options->gen.scratch1, SZ_B); | |
2102 retn(code); | |
2103 | |
2104 options->write_io = code->cur; | |
2105 check_cycles(&options->gen); | |
2106 cycles(&options->gen, 4); | |
2107 retn(code); | |
2108 | |
2109 options->retrans_stub = code->cur; | |
2110 //pop return address | |
2111 pop_r(code, options->gen.scratch2); | |
2112 call(code, options->gen.save_context); | |
2113 //adjust pointer before move and call instructions that got us here | |
2114 sub_ir(code, 11, options->gen.scratch2, SZ_PTR); | |
2115 mov_rr(code, options->gen.scratch1, RDI, SZ_D); | |
2116 mov_rr(code, options->gen.scratch2, RDX, SZ_PTR); | |
2117 push_r(code, options->gen.context_reg); | |
2118 call(code, (code_ptr)z80_retranslate_inst); | |
2119 pop_r(code, options->gen.context_reg); | |
2120 mov_rr(code, RAX, options->gen.scratch1, SZ_PTR); | |
2121 call(code, options->gen.load_context); | |
2122 jmp_r(code, options->gen.scratch1); | |
2123 | |
2124 options->run = (z80_run_fun)code->cur; | |
2125 //save callee save registers | |
2126 push_r(code, RBX); | |
2127 push_r(code, RBP); | |
2128 push_r(code, R12); | |
2129 push_r(code, R13); | |
2130 push_r(code, R14); | |
2131 push_r(code, R15); | |
2132 mov_rr(code, RDI, options->gen.context_reg, SZ_PTR); | |
2133 cmp_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, extra_pc), SZ_PTR); | |
2134 code_ptr no_extra = code->cur+1; | |
2135 jcc(code, CC_Z, no_extra); | |
2136 push_rdisp(code, options->gen.context_reg, offsetof(z80_context, extra_pc)); | |
2137 mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, extra_pc), SZ_PTR); | |
2138 *no_extra = code->cur - (no_extra + 1); | |
2139 jmp_rind(code, options->gen.context_reg); | |
2070 } | 2140 } |
2071 | 2141 |
2072 void * z80_gen_bank_write(uint32_t start_address, void * voptions) | 2142 void * z80_gen_bank_write(uint32_t start_address, void * voptions) |
2073 { | 2143 { |
2074 z80_options * options = voptions; | 2144 z80_options * options = voptions; |
2084 context->static_code_map->offsets = malloc(sizeof(int32_t) * 0x2000); | 2154 context->static_code_map->offsets = malloc(sizeof(int32_t) * 0x2000); |
2085 memset(context->static_code_map->offsets, 0xFF, sizeof(int32_t) * 0x2000); | 2155 memset(context->static_code_map->offsets, 0xFF, sizeof(int32_t) * 0x2000); |
2086 context->banked_code_map = malloc(sizeof(native_map_slot) * (1 << 9)); | 2156 context->banked_code_map = malloc(sizeof(native_map_slot) * (1 << 9)); |
2087 memset(context->banked_code_map, 0, sizeof(native_map_slot) * (1 << 9)); | 2157 memset(context->banked_code_map, 0, sizeof(native_map_slot) * (1 << 9)); |
2088 context->options = options; | 2158 context->options = options; |
2159 context->run = options->run; | |
2089 } | 2160 } |
2090 | 2161 |
2091 void z80_reset(z80_context * context) | 2162 void z80_reset(z80_context * context) |
2092 { | 2163 { |
2093 context->im = 0; | 2164 context->im = 0; |
2113 check_cycles_int(&opts->gen, address); | 2184 check_cycles_int(&opts->gen, address); |
2114 int check_int_size = code->cur-bp_stub; | 2185 int check_int_size = code->cur-bp_stub; |
2115 code->cur = bp_stub; | 2186 code->cur = bp_stub; |
2116 | 2187 |
2117 //Save context and call breakpoint handler | 2188 //Save context and call breakpoint handler |
2118 call(code, (uint8_t *)z80_save_context); | 2189 call(code, opts->gen.save_context); |
2119 push_r(code, opts->gen.scratch1); | 2190 push_r(code, opts->gen.scratch1); |
2120 mov_rr(code, opts->gen.context_reg, RDI, SZ_Q); | 2191 mov_rr(code, opts->gen.context_reg, RDI, SZ_Q); |
2121 mov_rr(code, opts->gen.scratch1, RSI, SZ_W); | 2192 mov_rr(code, opts->gen.scratch1, RSI, SZ_W); |
2122 call(code, bp_handler); | 2193 call(code, bp_handler); |
2123 mov_rr(code, RAX, opts->gen.context_reg, SZ_Q); | 2194 mov_rr(code, RAX, opts->gen.context_reg, SZ_Q); |
2124 //Restore context | 2195 //Restore context |
2125 call(code, (uint8_t *)z80_load_context); | 2196 call(code, opts->gen.load_context); |
2126 pop_r(code, opts->gen.scratch1); | 2197 pop_r(code, opts->gen.scratch1); |
2127 //do prologue stuff | 2198 //do prologue stuff |
2128 cmp_rr(code, opts->gen.cycles, opts->gen.limit, SZ_D); | 2199 cmp_rr(code, opts->gen.cycles, opts->gen.limit, SZ_D); |
2129 uint8_t * jmp_off = code->cur+1; | 2200 uint8_t * jmp_off = code->cur+1; |
2130 jcc(code, CC_NC, code->cur + 7); | 2201 jcc(code, CC_NC, code->cur + 7); |
2131 pop_r(code, opts->gen.scratch1); | 2202 pop_r(code, opts->gen.scratch1); |
2132 add_ir(code, check_int_size - (code->cur-native), opts->gen.scratch1, SZ_Q); | 2203 add_ir(code, check_int_size - (code->cur-native), opts->gen.scratch1, SZ_Q); |
2133 push_r(code, opts->gen.scratch1); | 2204 push_r(code, opts->gen.scratch1); |
2134 jmp(code, (uint8_t *)z80_handle_cycle_limit_int); | 2205 jmp(code, opts->gen.handle_cycle_limit_int); |
2135 *jmp_off = code->cur - (jmp_off+1); | 2206 *jmp_off = code->cur - (jmp_off+1); |
2136 //jump back to body of translated instruction | 2207 //jump back to body of translated instruction |
2137 pop_r(code, opts->gen.scratch1); | 2208 pop_r(code, opts->gen.scratch1); |
2138 add_ir(code, check_int_size - (code->cur-native), opts->gen.scratch1, SZ_Q); | 2209 add_ir(code, check_int_size - (code->cur-native), opts->gen.scratch1, SZ_Q); |
2139 jmp_r(code, opts->gen.scratch1); | 2210 jmp_r(code, opts->gen.scratch1); |