main
z80_to_x86.c
1/*
2 Copyright 2013 Michael Pavone
3 This file is part of BlastEm.
4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
5*/
6#include "z80inst.h"
7#include "z80_to_x86.h"
8#include "gen_x86.h"
9#include "mem.h"
10#include "util.h"
11#include <stdio.h>
12#include <stdlib.h>
13#include <stddef.h>
14#include <string.h>
15
16#define MODE_UNUSED (MODE_IMMED-1)
17#define MAX_MCYCLE_LENGTH 6
18#define NATIVE_CHUNK_SIZE 1024
19#define NATIVE_MAP_CHUNKS (0x10000 / NATIVE_CHUNK_SIZE)
20
21//#define DO_DEBUG_PRINT
22
23#ifdef DO_DEBUG_PRINT
24#define dprintf printf
25#else
26#define dprintf
27#endif
28
29uint32_t zbreakpoint_patch(z80_context * context, uint16_t address, code_ptr dst);
30void z80_handle_deferred(z80_context * context);
31
32uint8_t z80_size(z80inst * inst)
33{
34 uint8_t reg = (inst->reg & 0x1F);
35 if (reg != Z80_UNUSED && reg != Z80_USE_IMMED) {
36 return reg < Z80_BC ? SZ_B : SZ_W;
37 }
38 //TODO: Handle any necessary special cases
39 return SZ_B;
40}
41
42uint8_t zf_off(uint8_t flag)
43{
44 return offsetof(z80_context, flags) + flag;
45}
46
47uint8_t zaf_off(uint8_t flag)
48{
49 return offsetof(z80_context, alt_flags) + flag;
50}
51
52uint8_t zr_off(uint8_t reg)
53{
54 if (reg > Z80_A) {
55 reg = z80_low_reg(reg);
56 }
57 return offsetof(z80_context, regs) + reg;
58}
59
60uint8_t zar_off(uint8_t reg)
61{
62 if (reg > Z80_A) {
63 reg = z80_low_reg(reg);
64 }
65 return offsetof(z80_context, alt_regs) + reg;
66}
67
68void zreg_to_native(z80_options *opts, uint8_t reg, uint8_t native_reg)
69{
70 if (opts->regs[reg] >= 0) {
71 mov_rr(&opts->gen.code, opts->regs[reg], native_reg, reg > Z80_A ? SZ_W : SZ_B);
72 } else {
73 mov_rdispr(&opts->gen.code, opts->gen.context_reg, zr_off(reg), native_reg, reg > Z80_A ? SZ_W : SZ_B);
74 }
75}
76
77void native_to_zreg(z80_options *opts, uint8_t native_reg, uint8_t reg)
78{
79 if (opts->regs[reg] >= 0) {
80 mov_rr(&opts->gen.code, native_reg, opts->regs[reg], reg > Z80_A ? SZ_W : SZ_B);
81 } else {
82 mov_rrdisp(&opts->gen.code, native_reg, opts->gen.context_reg, zr_off(reg), reg > Z80_A ? SZ_W : SZ_B);
83 }
84}
85
86void translate_z80_reg(z80inst * inst, host_ea * ea, z80_options * opts)
87{
88 code_info *code = &opts->gen.code;
89 if (inst->reg == Z80_USE_IMMED) {
90 ea->mode = MODE_IMMED;
91 ea->disp = inst->immed;
92 } else if ((inst->reg & 0x1F) == Z80_UNUSED) {
93 ea->mode = MODE_UNUSED;
94 } else {
95 ea->mode = MODE_REG_DIRECT;
96 if (inst->reg == Z80_IYH && opts->regs[Z80_IYL] >= 0) {
97 if ((inst->addr_mode & 0x1F) == Z80_REG && inst->ea_reg == Z80_IYL) {
98 mov_rr(code, opts->regs[Z80_IY], opts->gen.scratch1, SZ_W);
99 ror_ir(code, 8, opts->gen.scratch1, SZ_W);
100 ea->base = opts->gen.scratch1;
101 } else {
102 ea->base = opts->regs[Z80_IYL];
103 ror_ir(code, 8, opts->regs[Z80_IY], SZ_W);
104 }
105 } else if(opts->regs[inst->reg] >= 0) {
106 ea->base = opts->regs[inst->reg];
107 if (ea->base >= AH && ea->base <= BH) {
108 if ((inst->addr_mode & 0x1F) == Z80_REG) {
109 uint8_t other_reg = opts->regs[inst->ea_reg];
110 if (other_reg >= R8 || (other_reg >= RSP && other_reg <= RDI)) {
111 //we can't mix an *H reg with a register that requires the REX prefix
112 ea->base = opts->regs[z80_low_reg(inst->reg)];
113 ror_ir(code, 8, ea->base, SZ_W);
114 }
115 } else if((inst->addr_mode & 0x1F) != Z80_UNUSED && (inst->addr_mode & 0x1F) != Z80_IMMED) {
116 //temp regs require REX prefix too
117 ea->base = opts->regs[z80_low_reg(inst->reg)];
118 ror_ir(code, 8, ea->base, SZ_W);
119 }
120 }
121 } else {
122 ea->mode = MODE_REG_DISPLACE8;
123 ea->base = opts->gen.context_reg;
124 ea->disp = zr_off(inst->reg);
125 }
126 }
127}
128
129void z80_save_reg(z80inst * inst, z80_options * opts)
130{
131 code_info *code = &opts->gen.code;
132 if (inst->reg == Z80_USE_IMMED || inst->reg == Z80_UNUSED) {
133 return;
134 }
135 if (inst->reg == Z80_IYH && opts->regs[Z80_IYL] >= 0) {
136 if ((inst->addr_mode & 0x1F) == Z80_REG && inst->ea_reg == Z80_IYL) {
137 ror_ir(code, 8, opts->regs[Z80_IY], SZ_W);
138 mov_rr(code, opts->gen.scratch1, opts->regs[Z80_IYL], SZ_B);
139 ror_ir(code, 8, opts->regs[Z80_IY], SZ_W);
140 } else {
141 ror_ir(code, 8, opts->regs[Z80_IY], SZ_W);
142 }
143 } else if (opts->regs[inst->reg] >= AH && opts->regs[inst->reg] <= BH) {
144 if ((inst->addr_mode & 0x1F) == Z80_REG) {
145 uint8_t other_reg = opts->regs[inst->ea_reg];
146 if (other_reg >= R8 || (other_reg >= RSP && other_reg <= RDI)) {
147 //we can't mix an *H reg with a register that requires the REX prefix
148 ror_ir(code, 8, opts->regs[z80_low_reg(inst->reg)], SZ_W);
149 }
150 } else if((inst->addr_mode & 0x1F) != Z80_UNUSED && (inst->addr_mode & 0x1F) != Z80_IMMED) {
151 //temp regs require REX prefix too
152 ror_ir(code, 8, opts->regs[z80_low_reg(inst->reg)], SZ_W);
153 }
154 }
155}
156
157void translate_z80_ea(z80inst * inst, host_ea * ea, z80_options * opts, uint8_t read, uint8_t modify)
158{
159 code_info *code = &opts->gen.code;
160 uint8_t size, areg;
161 int8_t reg;
162 ea->mode = MODE_REG_DIRECT;
163 areg = read ? opts->gen.scratch1 : opts->gen.scratch2;
164 switch(inst->addr_mode & 0x1F)
165 {
166 case Z80_REG:
167 if (inst->ea_reg == Z80_IYH && opts->regs[Z80_IYL] >= 0) {
168 if (inst->reg == Z80_IYL) {
169 mov_rr(code, opts->regs[Z80_IY], opts->gen.scratch1, SZ_W);
170 ror_ir(code, 8, opts->gen.scratch1, SZ_W);
171 ea->base = opts->gen.scratch1;
172 } else {
173 ea->base = opts->regs[Z80_IYL];
174 ror_ir(code, 8, opts->regs[Z80_IY], SZ_W);
175 }
176 } else if(opts->regs[inst->ea_reg] >= 0) {
177 ea->base = opts->regs[inst->ea_reg];
178 if (ea->base >= AH && ea->base <= BH && inst->reg != Z80_UNUSED && inst->reg != Z80_USE_IMMED) {
179 uint8_t other_reg = opts->regs[inst->reg];
180#ifdef X86_64
181 if (other_reg >= R8 || (other_reg >= RSP && other_reg <= RDI)) {
182 //we can't mix an *H reg with a register that requires the REX prefix
183 ea->base = opts->regs[z80_low_reg(inst->ea_reg)];
184 ror_ir(code, 8, ea->base, SZ_W);
185 }
186#endif
187 }
188 } else {
189 ea->mode = MODE_REG_DISPLACE8;
190 ea->base = opts->gen.context_reg;
191 ea->disp = zr_off(inst->ea_reg);
192 }
193 break;
194 case Z80_REG_INDIRECT:
195 zreg_to_native(opts, inst->ea_reg, areg);
196 size = z80_size(inst);
197 if (read) {
198 if (modify) {
199 //push_r(code, opts->gen.scratch1);
200 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_W);
201 }
202 if (size == SZ_B) {
203 call(code, opts->read_8);
204 } else {
205 call(code, opts->read_16);
206 }
207 }
208 ea->base = opts->gen.scratch1;
209 break;
210 case Z80_IMMED:
211 ea->mode = MODE_IMMED;
212 ea->disp = inst->immed;
213 break;
214 case Z80_IMMED_INDIRECT:
215 mov_ir(code, inst->immed, areg, SZ_W);
216 size = z80_size(inst);
217 if (read) {
218 /*if (modify) {
219 push_r(code, opts->gen.scratch1);
220 }*/
221 if (size == SZ_B) {
222 call(code, opts->read_8);
223 } else {
224 call(code, opts->read_16);
225 }
226 }
227 ea->base = opts->gen.scratch1;
228 break;
229 case Z80_IX_DISPLACE:
230 case Z80_IY_DISPLACE:
231 zreg_to_native(opts, (inst->addr_mode & 0x1F) == Z80_IX_DISPLACE ? Z80_IX : Z80_IY, areg);
232 add_ir(code, inst->ea_reg & 0x80 ? inst->ea_reg - 256 : inst->ea_reg, areg, SZ_W);
233 size = z80_size(inst);
234 if (read) {
235 if (modify) {
236 //push_r(code, opts->gen.scratch1);
237 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_W);
238 }
239 if (size == SZ_B) {
240 call(code, opts->read_8);
241 } else {
242 call(code, opts->read_16);
243 }
244 }
245 ea->base = opts->gen.scratch1;
246 break;
247 case Z80_UNUSED:
248 ea->mode = MODE_UNUSED;
249 break;
250 default:
251 fatal_error("Unrecognized Z80 addressing mode %d\n", inst->addr_mode & 0x1F);
252 }
253}
254
255void z80_save_ea(code_info *code, z80inst * inst, z80_options * opts)
256{
257 if ((inst->addr_mode & 0x1F) == Z80_REG) {
258 if (inst->ea_reg == Z80_IYH && opts->regs[Z80_IYL] >= 0) {
259 if (inst->reg == Z80_IYL) {
260 ror_ir(code, 8, opts->regs[Z80_IY], SZ_W);
261 mov_rr(code, opts->gen.scratch1, opts->regs[Z80_IYL], SZ_B);
262 ror_ir(code, 8, opts->regs[Z80_IY], SZ_W);
263 } else {
264 ror_ir(code, 8, opts->regs[Z80_IY], SZ_W);
265 }
266 } else if (inst->reg != Z80_UNUSED && inst->reg != Z80_USE_IMMED && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) {
267 uint8_t other_reg = opts->regs[inst->reg];
268#ifdef X86_64
269 if (other_reg >= R8 || (other_reg >= RSP && other_reg <= RDI)) {
270 //we can't mix an *H reg with a register that requires the REX prefix
271 ror_ir(code, 8, opts->regs[z80_low_reg(inst->ea_reg)], SZ_W);
272 }
273#endif
274 }
275 }
276}
277
278void z80_save_result(z80_options *opts, z80inst * inst)
279{
280 switch(inst->addr_mode & 0x1f)
281 {
282 case Z80_REG_INDIRECT:
283 case Z80_IMMED_INDIRECT:
284 case Z80_IX_DISPLACE:
285 case Z80_IY_DISPLACE:
286 if (inst->op != Z80_LD) {
287 mov_rdispr(&opts->gen.code, opts->gen.context_reg, offsetof(z80_context, scratch1), opts->gen.scratch2, SZ_W);
288 }
289 if (z80_size(inst) == SZ_B) {
290 call(&opts->gen.code, opts->write_8);
291 } else {
292 call(&opts->gen.code, opts->write_16_lowfirst);
293 }
294 }
295}
296
297enum {
298 DONT_READ=0,
299 READ
300};
301
302enum {
303 DONT_MODIFY=0,
304 MODIFY
305};
306
307void z80_print_regs_exit(z80_context * context)
308{
309 printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\nIX: %X\nIY: %X\nSP: %X\n\nIM: %d, IFF1: %d, IFF2: %d\n",
310 context->regs[Z80_A], context->regs[Z80_B], context->regs[Z80_C],
311 context->regs[Z80_D], context->regs[Z80_E],
312 (context->regs[Z80_H] << 8) | context->regs[Z80_L],
313 (context->regs[Z80_IXH] << 8) | context->regs[Z80_IXL],
314 (context->regs[Z80_IYH] << 8) | context->regs[Z80_IYL],
315 context->sp, context->im, context->iff1, context->iff2);
316 puts("--Alternate Regs--");
317 printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\nIX: %X\nIY: %X\n",
318 context->alt_regs[Z80_A], context->alt_regs[Z80_B], context->alt_regs[Z80_C],
319 context->alt_regs[Z80_D], context->alt_regs[Z80_E],
320 (context->alt_regs[Z80_H] << 8) | context->alt_regs[Z80_L],
321 (context->alt_regs[Z80_IXH] << 8) | context->alt_regs[Z80_IXL],
322 (context->alt_regs[Z80_IYH] << 8) | context->alt_regs[Z80_IYL]);
323 exit(0);
324}
325
326void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, uint8_t interp)
327{
328 uint32_t num_cycles;
329 host_ea src_op, dst_op;
330 uint8_t size;
331 z80_options *opts = context->options;
332 uint8_t * start = opts->gen.code.cur;
333 code_info *code = &opts->gen.code;
334 if (!interp) {
335 check_cycles_int(&opts->gen, address);
336 if (context->breakpoint_flags[address / 8] & (1 << (address % 8))) {
337 zbreakpoint_patch(context, address, start);
338 }
339 num_cycles = 4 * inst->opcode_bytes;
340 add_ir(code, inst->opcode_bytes > 1 ? 2 : 1, opts->regs[Z80_R], SZ_B);
341#ifdef Z80_LOG_ADDRESS
342 log_address(&opts->gen, address, "Z80: %X @ %d\n");
343#endif
344 }
345 switch(inst->op)
346 {
347 case Z80_LD:
348 size = z80_size(inst);
349 switch (inst->addr_mode & 0x1F)
350 {
351 case Z80_REG:
352 case Z80_REG_INDIRECT:
353 if (size != SZ_B) {
354 num_cycles += 2;
355 }
356 if (inst->reg == Z80_I || inst->ea_reg == Z80_I || inst->reg == Z80_R || inst->ea_reg == Z80_R) {
357 num_cycles += 1;
358 } else if (inst->reg == Z80_USE_IMMED) {
359 num_cycles += 3;
360 }
361 break;
362 case Z80_IMMED:
363 num_cycles += size == SZ_B ? 3 : 6;
364 break;
365 case Z80_IMMED_INDIRECT:
366 num_cycles += 6;
367 break;
368 case Z80_IX_DISPLACE:
369 case Z80_IY_DISPLACE:
370 num_cycles += 8; //3 for displacement, 5 for address addition
371 break;
372 }
373 cycles(&opts->gen, num_cycles);
374 if (inst->addr_mode & Z80_DIR) {
375 translate_z80_ea(inst, &dst_op, opts, DONT_READ, MODIFY);
376 translate_z80_reg(inst, &src_op, opts);
377 } else {
378 translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
379 translate_z80_reg(inst, &dst_op, opts);
380 }
381 if (inst->reg == Z80_R) {
382 mov_rr(code, opts->regs[Z80_A], opts->gen.scratch1, SZ_B);
383 mov_rr(code, opts->regs[Z80_A], opts->regs[Z80_R], SZ_B);
384 and_ir(code, 0x80, opts->gen.scratch1, SZ_B);
385 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zr_off(Z80_R), SZ_B);
386 } else if (inst->ea_reg == Z80_R && inst->addr_mode == Z80_REG) {
387 mov_rr(code, opts->regs[Z80_R], opts->regs[Z80_A], SZ_B);
388 and_ir(code, 0x7F, opts->regs[Z80_A], SZ_B);
389 or_rdispr(code, opts->gen.context_reg, zr_off(Z80_R), opts->regs[Z80_A], SZ_B);
390 } else if (src_op.mode == MODE_REG_DIRECT) {
391 if(dst_op.mode == MODE_REG_DISPLACE8) {
392 mov_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, size);
393 } else {
394 mov_rr(code, src_op.base, dst_op.base, size);
395 }
396 } else if(src_op.mode == MODE_IMMED) {
397 if(dst_op.mode == MODE_REG_DISPLACE8) {
398 mov_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, size);
399 } else {
400 mov_ir(code, src_op.disp, dst_op.base, size);
401 }
402 } else {
403 if(dst_op.mode == MODE_REG_DISPLACE8) {
404 mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, size);
405 mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, size);
406 } else {
407 mov_rdispr(code, src_op.base, src_op.disp, dst_op.base, size);
408 }
409 }
410 if ((inst->ea_reg == Z80_I || inst->ea_reg == Z80_R) && inst->addr_mode == Z80_REG) {
411 //ld a, i and ld a, r sets some flags
412 cmp_ir(code, 0, dst_op.base, SZ_B);
413 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
414 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
415 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);;
416 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);;
417 mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, iff2), opts->gen.scratch1, SZ_B);
418 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_PV), SZ_B);
419 }
420 z80_save_reg(inst, opts);
421 z80_save_ea(code, inst, opts);
422 if (inst->addr_mode & Z80_DIR) {
423 z80_save_result(opts, inst);
424 }
425 break;
426 case Z80_PUSH:
427 cycles(&opts->gen, num_cycles + 1);
428 sub_ir(code, 2, opts->regs[Z80_SP], SZ_W);
429 if (inst->reg == Z80_AF) {
430 zreg_to_native(opts, Z80_A, opts->gen.scratch1);
431 shl_ir(code, 8, opts->gen.scratch1, SZ_W);
432 mov_rdispr(code, opts->gen.context_reg, zf_off(ZF_XY), opts->gen.scratch1, SZ_B);
433 and_ir(code, 0x28, opts->gen.scratch1, SZ_B);
434 or_rdispr(code, opts->gen.context_reg, zf_off(ZF_C), opts->gen.scratch1, SZ_B);
435 ror_ir(code, 1, opts->gen.scratch1, SZ_B);
436 or_rdispr(code, opts->gen.context_reg, zf_off(ZF_N), opts->gen.scratch1, SZ_B);
437 ror_ir(code, 1, opts->gen.scratch1, SZ_B);
438 or_rdispr(code, opts->gen.context_reg, zf_off(ZF_PV), opts->gen.scratch1, SZ_B);
439 ror_ir(code, 2, opts->gen.scratch1, SZ_B);
440 or_rdispr(code, opts->gen.context_reg, zf_off(ZF_H), opts->gen.scratch1, SZ_B);
441 ror_ir(code, 2, opts->gen.scratch1, SZ_B);
442 or_rdispr(code, opts->gen.context_reg, zf_off(ZF_Z), opts->gen.scratch1, SZ_B);
443 ror_ir(code, 1, opts->gen.scratch1, SZ_B);
444 or_rdispr(code, opts->gen.context_reg, zf_off(ZF_S), opts->gen.scratch1, SZ_B);
445 ror_ir(code, 1, opts->gen.scratch1, SZ_B);
446 } else {
447 zreg_to_native(opts, inst->reg, opts->gen.scratch1);
448 }
449 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
450 call(code, opts->write_16_highfirst);
451 //no call to save_z80_reg needed since there's no chance we'll use the only
452 //the upper half of a register pair
453 break;
454 case Z80_POP:
455 cycles(&opts->gen, num_cycles);
456 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
457 call(code, opts->read_16);
458 add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
459 if (inst->reg == Z80_AF) {
460
461 bt_ir(code, 0, opts->gen.scratch1, SZ_W);
462 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
463 bt_ir(code, 1, opts->gen.scratch1, SZ_W);
464 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_N));
465 bt_ir(code, 2, opts->gen.scratch1, SZ_W);
466 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_PV));
467 bt_ir(code, 4, opts->gen.scratch1, SZ_W);
468 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
469 bt_ir(code, 6, opts->gen.scratch1, SZ_W);
470 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_Z));
471 bt_ir(code, 7, opts->gen.scratch1, SZ_W);
472 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_S));
473 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
474 shr_ir(code, 8, opts->gen.scratch1, SZ_W);
475 native_to_zreg(opts, opts->gen.scratch1, Z80_A);
476 } else {
477 native_to_zreg(opts, opts->gen.scratch1, inst->reg);
478 }
479 //no call to save_z80_reg needed since there's no chance we'll use the only
480 //the upper half of a register pair
481 break;
482 case Z80_EX:
483 cycles(&opts->gen, num_cycles);
484 if (inst->addr_mode == Z80_REG) {
485 if(inst->reg == Z80_AF) {
486 zreg_to_native(opts, Z80_A, opts->gen.scratch1);
487 mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_A), opts->gen.scratch2, SZ_B);
488 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_A), SZ_B);
489 native_to_zreg(opts, opts->gen.scratch2, Z80_A);
490
491 //Flags are currently word aligned, so we can move
492 //them efficiently a word at a time
493 for (int f = ZF_C; f < ZF_NUM; f+=2) {
494 mov_rdispr(code, opts->gen.context_reg, zf_off(f), opts->gen.scratch1, SZ_W);
495 mov_rdispr(code, opts->gen.context_reg, zaf_off(f), opts->gen.scratch2, SZ_W);
496 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zaf_off(f), SZ_W);
497 mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(f), SZ_W);
498 }
499 } else {
500 if (opts->regs[Z80_DE] >= 0 && opts->regs[Z80_HL] >= 0) {
501 xchg_rr(code, opts->regs[Z80_DE], opts->regs[Z80_HL], SZ_W);
502 } else {
503 zreg_to_native(opts, Z80_DE, opts->gen.scratch1);
504 zreg_to_native(opts, Z80_HL, opts->gen.scratch2);
505 native_to_zreg(opts, opts->gen.scratch1, Z80_HL);
506 native_to_zreg(opts, opts->gen.scratch2, Z80_DE);
507 }
508 }
509 } else {
510 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
511 call(code, opts->read_8);
512 if (opts->regs[inst->reg] >= 0) {
513 xchg_rr(code, opts->regs[inst->reg], opts->gen.scratch1, SZ_B);
514 } else {
515 zreg_to_native(opts, inst->reg, opts->gen.scratch2);
516 xchg_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
517 native_to_zreg(opts, opts->gen.scratch2, inst->reg);
518 }
519 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
520 call(code, opts->write_8);
521 cycles(&opts->gen, 1);
522 uint8_t high_reg = z80_high_reg(inst->reg);
523 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
524 add_ir(code, 1, opts->gen.scratch1, SZ_W);
525 call(code, opts->read_8);
526 if (opts->regs[inst->reg] >= 0) {
527 //even though some of the upper halves can be used directly
528 //the limitations on mixing *H regs with the REX prefix
529 //prevent us from taking advantage of it
530 uint8_t use_reg = opts->regs[inst->reg];
531 ror_ir(code, 8, use_reg, SZ_W);
532 xchg_rr(code, use_reg, opts->gen.scratch1, SZ_B);
533 //restore reg to normal rotation
534 ror_ir(code, 8, use_reg, SZ_W);
535 } else {
536 zreg_to_native(opts, high_reg, opts->gen.scratch2);
537 xchg_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
538 native_to_zreg(opts, opts->gen.scratch2, high_reg);
539 }
540 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
541 add_ir(code, 1, opts->gen.scratch2, SZ_W);
542 call(code, opts->write_8);
543 cycles(&opts->gen, 2);
544 }
545 break;
546 case Z80_EXX:
547 cycles(&opts->gen, num_cycles);
548 zreg_to_native(opts, Z80_BC, opts->gen.scratch1);
549 mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_BC), opts->gen.scratch2, SZ_W);
550 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_BC), SZ_W);
551 native_to_zreg(opts, opts->gen.scratch2, Z80_BC);
552
553 zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
554 mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_HL), opts->gen.scratch2, SZ_W);
555 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_HL), SZ_W);
556 native_to_zreg(opts, opts->gen.scratch2, Z80_HL);
557
558 zreg_to_native(opts, Z80_DE, opts->gen.scratch1);
559 mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_DE), opts->gen.scratch2, SZ_W);
560 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_DE), SZ_W);
561 native_to_zreg(opts, opts->gen.scratch2, Z80_DE);
562 break;
563 case Z80_LDI: {
564 cycles(&opts->gen, num_cycles);
565 zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
566 call(code, opts->read_8);
567 zreg_to_native(opts, Z80_DE, opts->gen.scratch2);
568 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
569 call(code, opts->write_8);
570 mov_rdispr(code, opts->gen.context_reg, zf_off(ZF_XY), opts->gen.scratch1, SZ_B);
571 add_rr(code, opts->regs[Z80_A], opts->gen.scratch1, SZ_B);
572 mov_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
573 and_ir(code, 0x8, opts->gen.scratch1, SZ_B);
574 shl_ir(code, 4, opts->gen.scratch2, SZ_B);
575 or_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
576 mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
577 cycles(&opts->gen, 2);
578 if (opts->regs[Z80_DE] >= 0) {
579 add_ir(code, 1, opts->regs[Z80_DE], SZ_W);
580 } else {
581 add_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_DE), SZ_W);
582 }
583 if (opts->regs[Z80_HL] >= 0) {
584 add_ir(code, 1, opts->regs[Z80_HL], SZ_W);
585 } else {
586 add_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_W);
587 }
588 if (opts->regs[Z80_BC] >= 0) {
589 sub_ir(code, 1, opts->regs[Z80_BC], SZ_W);
590 } else {
591 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_BC), SZ_W);
592 }
593 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
594 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
595 setcc_rdisp(code, CC_NZ, opts->gen.context_reg, zf_off(ZF_PV));
596 break;
597 }
598 case Z80_LDIR: {
599 cycles(&opts->gen, num_cycles);
600 zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
601 call(code, opts->read_8);
602 zreg_to_native(opts, Z80_DE, opts->gen.scratch2);
603 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
604 call(code, opts->write_8);
605 mov_rdispr(code, opts->gen.context_reg, zf_off(ZF_XY), opts->gen.scratch1, SZ_B);
606 add_rr(code, opts->regs[Z80_A], opts->gen.scratch1, SZ_B);
607 mov_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
608 and_ir(code, 0x8, opts->gen.scratch1, SZ_B);
609 shl_ir(code, 4, opts->gen.scratch2, SZ_B);
610 or_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
611 mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
612 if (opts->regs[Z80_DE] >= 0) {
613 add_ir(code, 1, opts->regs[Z80_DE], SZ_W);
614 } else {
615 add_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_DE), SZ_W);
616 }
617 if (opts->regs[Z80_HL] >= 0) {
618 add_ir(code, 1, opts->regs[Z80_HL], SZ_W);
619 } else {
620 add_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_W);
621 }
622 if (opts->regs[Z80_BC] >= 0) {
623 sub_ir(code, 1, opts->regs[Z80_BC], SZ_W);
624 } else {
625 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_BC), SZ_W);
626 }
627 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
628 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
629 uint8_t * cont = code->cur+1;
630 jcc(code, CC_Z, code->cur+2);
631 cycles(&opts->gen, 7);
632 mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_PV), SZ_B);
633 jmp(code, start);
634 *cont = code->cur - (cont + 1);
635 cycles(&opts->gen, 2);
636 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B);
637 break;
638 }
639 case Z80_LDD: {
640 cycles(&opts->gen, num_cycles);
641 zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
642 call(code, opts->read_8);
643 zreg_to_native(opts, Z80_DE, opts->gen.scratch2);
644 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
645 call(code, opts->write_8);
646 mov_rdispr(code, opts->gen.context_reg, zf_off(ZF_XY), opts->gen.scratch1, SZ_B);
647 add_rr(code, opts->regs[Z80_A], opts->gen.scratch1, SZ_B);
648 mov_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
649 and_ir(code, 0x8, opts->gen.scratch1, SZ_B);
650 shl_ir(code, 4, opts->gen.scratch2, SZ_B);
651 or_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
652 mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
653 cycles(&opts->gen, 2);
654 if (opts->regs[Z80_DE] >= 0) {
655 sub_ir(code, 1, opts->regs[Z80_DE], SZ_W);
656 } else {
657 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_DE), SZ_W);
658 }
659 if (opts->regs[Z80_HL] >= 0) {
660 sub_ir(code, 1, opts->regs[Z80_HL], SZ_W);
661 } else {
662 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_W);
663 }
664 if (opts->regs[Z80_BC] >= 0) {
665 sub_ir(code, 1, opts->regs[Z80_BC], SZ_W);
666 } else {
667 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_BC), SZ_W);
668 }
669 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
670 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
671 setcc_rdisp(code, CC_NZ, opts->gen.context_reg, zf_off(ZF_PV));
672 break;
673 }
674 case Z80_LDDR: {
675 cycles(&opts->gen, num_cycles);
676 zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
677 call(code, opts->read_8);
678 zreg_to_native(opts, Z80_DE, opts->gen.scratch2);
679 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
680 call(code, opts->write_8);
681 mov_rdispr(code, opts->gen.context_reg, zf_off(ZF_XY), opts->gen.scratch1, SZ_B);
682 add_rr(code, opts->regs[Z80_A], opts->gen.scratch1, SZ_B);
683 mov_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
684 and_ir(code, 0x8, opts->gen.scratch1, SZ_B);
685 shl_ir(code, 4, opts->gen.scratch2, SZ_B);
686 or_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
687 mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
688 if (opts->regs[Z80_DE] >= 0) {
689 sub_ir(code, 1, opts->regs[Z80_DE], SZ_W);
690 } else {
691 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_DE), SZ_W);
692 }
693 if (opts->regs[Z80_HL] >= 0) {
694 sub_ir(code, 1, opts->regs[Z80_HL], SZ_W);
695 } else {
696 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_W);
697 }
698 if (opts->regs[Z80_BC] >= 0) {
699 sub_ir(code, 1, opts->regs[Z80_BC], SZ_W);
700 } else {
701 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_BC), SZ_W);
702 }
703 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
704 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
705 uint8_t * cont = code->cur+1;
706 jcc(code, CC_Z, code->cur+2);
707 cycles(&opts->gen, 7);
708 mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_PV), SZ_B);
709 jmp(code, start);
710 *cont = code->cur - (cont + 1);
711 cycles(&opts->gen, 2);
712 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B);
713 break;
714 }
715 case Z80_CPI:
716 cycles(&opts->gen, num_cycles);//T-States 4,4
717 zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
718 call(code, opts->read_8);//T-States 3
719 mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
720 sub_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
721 mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
722 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
723 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
724 xor_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
725 xor_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
726 bt_ir(code, 4, opts->gen.scratch2, SZ_B);
727 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
728 cycles(&opts->gen, 5);//T-States 5
729 if (opts->regs[Z80_HL] >= 0) {
730 add_ir(code, 1, opts->regs[Z80_HL], SZ_W);
731 } else {
732 add_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_W);
733 }
734 if (opts->regs[Z80_BC] >= 0) {
735 sub_ir(code, 1, opts->regs[Z80_BC], SZ_W);
736 } else {
737 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_BC), SZ_W);
738 }
739 setcc_rdisp(code, CC_NZ, opts->gen.context_reg, zf_off(ZF_PV));
740 mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
741 sub_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
742 sub_rdispr(code, opts->gen.context_reg, zf_off(ZF_H), opts->gen.scratch2, SZ_B);
743 mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
744 shl_ir(code, 4, opts->gen.scratch2, SZ_B);
745 and_irdisp(code, 0x8, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
746 and_ir(code, 0x20, opts->gen.scratch2, SZ_B);
747 or_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
748 break;
749 case Z80_CPIR: {
750 cycles(&opts->gen, num_cycles);//T-States 4,4
751 zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
752 call(code, opts->read_8);//T-States 3
753 mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
754 sub_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
755 mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
756 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
757 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
758 xor_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
759 xor_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
760 bt_ir(code, 4, opts->gen.scratch2, SZ_B);
761 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
762 cycles(&opts->gen, 5);//T-States 5
763 if (opts->regs[Z80_HL] >= 0) {
764 add_ir(code, 1, opts->regs[Z80_HL], SZ_W);
765 } else {
766 add_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_W);
767 }
768 mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
769 sub_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
770 sub_rdispr(code, opts->gen.context_reg, zf_off(ZF_H), opts->gen.scratch2, SZ_B);
771 mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
772 shl_ir(code, 4, opts->gen.scratch2, SZ_B);
773 and_irdisp(code, 0x8, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
774 and_ir(code, 0x20, opts->gen.scratch2, SZ_B);
775 or_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
776 if (opts->regs[Z80_BC] >= 0) {
777 sub_ir(code, 1, opts->regs[Z80_BC], SZ_W);
778 } else {
779 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_BC), SZ_W);
780 }
781 setcc_rdisp(code, CC_NZ, opts->gen.context_reg, zf_off(ZF_PV));
782 uint8_t * cont = code->cur+1;
783 jcc(code, CC_Z, code->cur+2);
784 cmp_rr(code, opts->gen.scratch1, opts->regs[Z80_A], SZ_B);
785 uint8_t * cont2 = code->cur+1;
786 jcc(code, CC_Z, code->cur+2);
787 //repeat case
788 cycles(&opts->gen, 5);//T-States 5
789 jmp(code, start);
790 *cont = code->cur - (cont + 1);
791 *cont2 = code->cur - (cont2 + 1);
792 break;
793 }
794 case Z80_CPD:
795 cycles(&opts->gen, num_cycles);//T-States 4,4
796 zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
797 call(code, opts->read_8);//T-States 3
798 mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
799 sub_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
800 mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
801 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
802 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
803 xor_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
804 xor_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
805 bt_ir(code, 4, opts->gen.scratch2, SZ_B);
806 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
807 cycles(&opts->gen, 5);//T-States 5
808 if (opts->regs[Z80_HL] >= 0) {
809 sub_ir(code, 1, opts->regs[Z80_HL], SZ_W);
810 } else {
811 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_W);
812 }
813 if (opts->regs[Z80_BC] >= 0) {
814 sub_ir(code, 1, opts->regs[Z80_BC], SZ_W);
815 } else {
816 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_BC), SZ_W);
817 }
818 setcc_rdisp(code, CC_NZ, opts->gen.context_reg, zf_off(ZF_PV));
819 mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
820 sub_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
821 sub_rdispr(code, opts->gen.context_reg, zf_off(ZF_H), opts->gen.scratch2, SZ_B);
822 mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
823 shl_ir(code, 4, opts->gen.scratch2, SZ_B);
824 and_irdisp(code, 0x8, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
825 and_ir(code, 0x20, opts->gen.scratch2, SZ_B);
826 or_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
827 break;
828 case Z80_CPDR: {
829 cycles(&opts->gen, num_cycles);//T-States 4,4
830 zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
831 call(code, opts->read_8);//T-States 3
832 mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
833 sub_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
834 mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
835 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
836 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
837 xor_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
838 xor_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
839 bt_ir(code, 4, opts->gen.scratch2, SZ_B);
840 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
841 cycles(&opts->gen, 5);//T-States 5
842 if (opts->regs[Z80_HL] >= 0) {
843 sub_ir(code, 1, opts->regs[Z80_HL], SZ_W);
844 } else {
845 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_W);
846 }
847 mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
848 sub_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
849 sub_rdispr(code, opts->gen.context_reg, zf_off(ZF_H), opts->gen.scratch2, SZ_B);
850 mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
851 shl_ir(code, 4, opts->gen.scratch2, SZ_B);
852 and_irdisp(code, 0x8, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
853 and_ir(code, 0x20, opts->gen.scratch2, SZ_B);
854 or_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
855 if (opts->regs[Z80_BC] >= 0) {
856 sub_ir(code, 1, opts->regs[Z80_BC], SZ_W);
857 } else {
858 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_BC), SZ_W);
859 }
860 setcc_rdisp(code, CC_NZ, opts->gen.context_reg, zf_off(ZF_PV));
861 uint8_t * cont = code->cur+1;
862 jcc(code, CC_Z, code->cur+2);
863 cmp_rr(code, opts->gen.scratch1, opts->regs[Z80_A], SZ_B);
864 uint8_t * cont2 = code->cur+1;
865 jcc(code, CC_Z, code->cur+2);
866 //repeat case
867 cycles(&opts->gen, 5);//T-States 5
868 jmp(code, start);
869 *cont = code->cur - (cont + 1);
870 *cont2 = code->cur - (cont2 + 1);
871 break;
872 }
873 case Z80_ADD:
874 if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
875 num_cycles += 8;
876 } else if(inst->addr_mode == Z80_IMMED) {
877 num_cycles += 3;
878 } else if(z80_size(inst) == SZ_W) {
879 num_cycles += 7;
880 }
881 cycles(&opts->gen, num_cycles);
882 translate_z80_reg(inst, &dst_op, opts);
883 translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
884 if (dst_op.mode == MODE_REG_DIRECT) {
885 mov_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
886 } else {
887 mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, z80_size(inst));
888 }
889 if (src_op.mode == MODE_REG_DIRECT) {
890 xor_rr(code, src_op.base, opts->gen.scratch2, z80_size(inst));
891 } else if (src_op.mode == MODE_IMMED) {
892 xor_ir(code, src_op.disp, opts->gen.scratch2, z80_size(inst));
893 } else {
894 xor_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, z80_size(inst));
895 }
896 if (dst_op.mode == MODE_REG_DIRECT) {
897 if (src_op.mode == MODE_REG_DIRECT) {
898 add_rr(code, src_op.base, dst_op.base, z80_size(inst));
899 } else if (src_op.mode == MODE_IMMED) {
900 add_ir(code, src_op.disp, dst_op.base, z80_size(inst));
901 } else {
902 add_rdispr(code, src_op.base, src_op.disp, dst_op.base, z80_size(inst));
903 }
904 if (z80_size(inst) == SZ_B) {
905 mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
906 }
907 } else {
908 if (src_op.mode == MODE_REG_DIRECT) {
909 add_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, z80_size(inst));
910 } else if (src_op.mode == MODE_IMMED) {
911 add_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, z80_size(inst));
912 } else {
913 mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, z80_size(inst));
914 add_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, z80_size(inst));
915 }
916 mov_rdispr(code, dst_op.base, dst_op.disp + (z80_size(inst) == SZ_B ? 0 : 1), opts->gen.scratch1, SZ_B);
917 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
918 }
919 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
920 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
921 if (z80_size(inst) == SZ_B) {
922 setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
923 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
924 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
925 }
926 if (dst_op.mode == MODE_REG_DIRECT) {
927 xor_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
928 } else {
929 xor_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, z80_size(inst));
930 }
931 bt_ir(code, z80_size(inst) == SZ_B ? 4 : 12, opts->gen.scratch2, z80_size(inst));
932 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
933 if (z80_size(inst) == SZ_W & dst_op.mode == MODE_REG_DIRECT) {
934 mov_rr(code, dst_op.base, opts->gen.scratch2, SZ_W);
935 shr_ir(code, 8, opts->gen.scratch2, SZ_W);
936 mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
937 }
938 z80_save_reg(inst, opts);
939 z80_save_ea(code, inst, opts);
940 break;
941 case Z80_ADC:
942 if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
943 num_cycles += 8;
944 } else if(inst->addr_mode == Z80_IMMED) {
945 num_cycles += 3;
946 } else if(z80_size(inst) == SZ_W) {
947 num_cycles += 7;
948 }
949 cycles(&opts->gen, num_cycles);
950 translate_z80_reg(inst, &dst_op, opts);
951 translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
952 if (dst_op.mode == MODE_REG_DIRECT) {
953 mov_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
954 } else {
955 mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, z80_size(inst));
956 }
957 if (src_op.mode == MODE_REG_DIRECT) {
958 xor_rr(code, src_op.base, opts->gen.scratch2, z80_size(inst));
959 } else if (src_op.mode == MODE_IMMED) {
960 xor_ir(code, src_op.disp, opts->gen.scratch2, z80_size(inst));
961 } else {
962 xor_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, z80_size(inst));
963 }
964 bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
965 if (dst_op.mode == MODE_REG_DIRECT) {
966 if (src_op.mode == MODE_REG_DIRECT) {
967 adc_rr(code, src_op.base, dst_op.base, z80_size(inst));
968 } else if (src_op.mode == MODE_IMMED) {
969 adc_ir(code, src_op.disp, dst_op.base, z80_size(inst));
970 } else {
971 adc_rdispr(code, src_op.base, src_op.disp, dst_op.base, z80_size(inst));
972 }
973 if (z80_size(inst) == SZ_B) {
974 mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
975 }
976 } else {
977 if (src_op.mode == MODE_REG_DIRECT) {
978 adc_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, z80_size(inst));
979 } else if (src_op.mode == MODE_IMMED) {
980 adc_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, z80_size(inst));
981 } else {
982 mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, z80_size(inst));
983 adc_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, z80_size(inst));
984 }
985 mov_rdispr(code, dst_op.base, dst_op.disp + z80_size(inst) == SZ_B ? 0 : 8, opts->gen.scratch1, SZ_B);
986 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
987 }
988 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
989 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
990 setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
991 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
992 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
993 if (dst_op.mode == MODE_REG_DIRECT) {
994 xor_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
995 } else {
996 xor_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, z80_size(inst));
997 }
998 bt_ir(code, z80_size(inst) == SZ_B ? 4 : 12, opts->gen.scratch2, z80_size(inst));
999 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
1000 if (z80_size(inst) == SZ_W & dst_op.mode == MODE_REG_DIRECT) {
1001 mov_rr(code, dst_op.base, opts->gen.scratch2, SZ_W);
1002 shr_ir(code, 8, opts->gen.scratch2, SZ_W);
1003 mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1004 }
1005 z80_save_reg(inst, opts);
1006 z80_save_ea(code, inst, opts);
1007 break;
1008 case Z80_SUB:
1009 if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1010 num_cycles += 8;
1011 } else if(inst->addr_mode == Z80_IMMED) {
1012 num_cycles += 3;
1013 }
1014 cycles(&opts->gen, num_cycles);
1015 translate_z80_reg(inst, &dst_op, opts);
1016 translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
1017 if (dst_op.mode == MODE_REG_DIRECT) {
1018 mov_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
1019 } else {
1020 mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, z80_size(inst));
1021 }
1022 if (src_op.mode == MODE_REG_DIRECT) {
1023 xor_rr(code, src_op.base, opts->gen.scratch2, z80_size(inst));
1024 } else if (src_op.mode == MODE_IMMED) {
1025 xor_ir(code, src_op.disp, opts->gen.scratch2, z80_size(inst));
1026 } else {
1027 xor_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, z80_size(inst));
1028 }
1029 if (dst_op.mode == MODE_REG_DIRECT) {
1030 if (src_op.mode == MODE_REG_DIRECT) {
1031 sub_rr(code, src_op.base, dst_op.base, z80_size(inst));
1032 } else if (src_op.mode == MODE_IMMED) {
1033 sub_ir(code, src_op.disp, dst_op.base, z80_size(inst));
1034 } else {
1035 sub_rdispr(code, src_op.base, src_op.disp, dst_op.base, z80_size(inst));
1036 }
1037 if (z80_size(inst) == SZ_B) {
1038 mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1039 }
1040 } else {
1041 if (src_op.mode == MODE_REG_DIRECT) {
1042 sub_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, z80_size(inst));
1043 } else if (src_op.mode == MODE_IMMED) {
1044 sub_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, z80_size(inst));
1045 } else {
1046 mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, z80_size(inst));
1047 sub_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, z80_size(inst));
1048 }
1049 mov_rdispr(code, dst_op.base, dst_op.disp + z80_size(inst) == SZ_B ? 0 : 8, opts->gen.scratch1, SZ_B);
1050 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1051 }
1052 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
1053 mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1054 setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
1055 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1056 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1057 if (dst_op.mode == MODE_REG_DIRECT) {
1058 xor_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
1059 } else {
1060 xor_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, z80_size(inst));
1061 }
1062 bt_ir(code, z80_size(inst) == SZ_B ? 4 : 12, opts->gen.scratch2, z80_size(inst));
1063 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
1064 if (z80_size(inst) == SZ_W & dst_op.mode == MODE_REG_DIRECT) {
1065 mov_rr(code, dst_op.base, opts->gen.scratch2, SZ_W);
1066 shr_ir(code, 8, opts->gen.scratch2, SZ_W);
1067 mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1068 }
1069 z80_save_reg(inst, opts);
1070 z80_save_ea(code, inst, opts);
1071 break;
1072 case Z80_SBC:
1073 if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1074 num_cycles += 8;
1075 } else if(inst->addr_mode == Z80_IMMED) {
1076 num_cycles += 3;
1077 } else if(z80_size(inst) == SZ_W) {
1078 num_cycles += 7;
1079 }
1080 cycles(&opts->gen, num_cycles);
1081 translate_z80_reg(inst, &dst_op, opts);
1082 translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
1083 if (dst_op.mode == MODE_REG_DIRECT) {
1084 mov_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
1085 } else {
1086 mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, z80_size(inst));
1087 }
1088 if (src_op.mode == MODE_REG_DIRECT) {
1089 xor_rr(code, src_op.base, opts->gen.scratch2, z80_size(inst));
1090 } else if (src_op.mode == MODE_IMMED) {
1091 xor_ir(code, src_op.disp, opts->gen.scratch2, z80_size(inst));
1092 } else {
1093 xor_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, z80_size(inst));
1094 }
1095 bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
1096 if (dst_op.mode == MODE_REG_DIRECT) {
1097 if (src_op.mode == MODE_REG_DIRECT) {
1098 sbb_rr(code, src_op.base, dst_op.base, z80_size(inst));
1099 } else if (src_op.mode == MODE_IMMED) {
1100 sbb_ir(code, src_op.disp, dst_op.base, z80_size(inst));
1101 } else {
1102 sbb_rdispr(code, src_op.base, src_op.disp, dst_op.base, z80_size(inst));
1103 }
1104 if (z80_size(inst) == SZ_B) {
1105 mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1106 }
1107 } else {
1108 if (src_op.mode == MODE_REG_DIRECT) {
1109 sbb_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, z80_size(inst));
1110 } else if (src_op.mode == MODE_IMMED) {
1111 sbb_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, z80_size(inst));
1112 } else {
1113 mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, z80_size(inst));
1114 sbb_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, z80_size(inst));
1115 }
1116 mov_rdispr(code, dst_op.base, dst_op.disp + z80_size(inst) == SZ_B ? 0 : 8, opts->gen.scratch1, SZ_B);
1117 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1118 }
1119 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
1120 mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1121 setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
1122 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1123 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1124 if (dst_op.mode == MODE_REG_DIRECT) {
1125 xor_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
1126 } else {
1127 xor_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, z80_size(inst));
1128 }
1129 bt_ir(code, z80_size(inst) == SZ_B ? 4 : 12, opts->gen.scratch2, z80_size(inst));
1130 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
1131 if (z80_size(inst) == SZ_W & dst_op.mode == MODE_REG_DIRECT) {
1132 mov_rr(code, dst_op.base, opts->gen.scratch2, SZ_W);
1133 shr_ir(code, 8, opts->gen.scratch2, SZ_W);
1134 mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1135 }
1136 z80_save_reg(inst, opts);
1137 z80_save_ea(code, inst, opts);
1138 break;
1139 case Z80_AND:
1140 if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1141 num_cycles += 8;
1142 } else if(inst->addr_mode == Z80_IMMED) {
1143 num_cycles += 3;
1144 } else if(z80_size(inst) == SZ_W) {
1145 num_cycles += 4;
1146 }
1147 cycles(&opts->gen, num_cycles);
1148 translate_z80_reg(inst, &dst_op, opts);
1149 translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
1150 if (src_op.mode == MODE_REG_DIRECT) {
1151 and_rr(code, src_op.base, dst_op.base, z80_size(inst));
1152 } else if (src_op.mode == MODE_IMMED) {
1153 and_ir(code, src_op.disp, dst_op.base, z80_size(inst));
1154 } else {
1155 and_rdispr(code, src_op.base, src_op.disp, dst_op.base, z80_size(inst));
1156 }
1157 mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1158 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1159 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
1160 mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1161 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1162 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1163 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1164 z80_save_reg(inst, opts);
1165 z80_save_ea(code, inst, opts);
1166 break;
1167 case Z80_OR:
1168 if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1169 num_cycles += 8;
1170 } else if(inst->addr_mode == Z80_IMMED) {
1171 num_cycles += 3;
1172 } else if(z80_size(inst) == SZ_W) {
1173 num_cycles += 4;
1174 }
1175 cycles(&opts->gen, num_cycles);
1176 translate_z80_reg(inst, &dst_op, opts);
1177 translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
1178 if (src_op.mode == MODE_REG_DIRECT) {
1179 or_rr(code, src_op.base, dst_op.base, z80_size(inst));
1180 } else if (src_op.mode == MODE_IMMED) {
1181 or_ir(code, src_op.disp, dst_op.base, z80_size(inst));
1182 } else {
1183 or_rdispr(code, src_op.base, src_op.disp, dst_op.base, z80_size(inst));
1184 }
1185 mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1186 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1187 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
1188 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1189 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1190 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1191 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1192 z80_save_reg(inst, opts);
1193 z80_save_ea(code, inst, opts);
1194 break;
1195 case Z80_XOR:
1196 if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1197 num_cycles += 8;
1198 } else if(inst->addr_mode == Z80_IMMED) {
1199 num_cycles += 3;
1200 } else if(z80_size(inst) == SZ_W) {
1201 num_cycles += 4;
1202 }
1203 cycles(&opts->gen, num_cycles);
1204 translate_z80_reg(inst, &dst_op, opts);
1205 translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
1206 if (src_op.mode == MODE_REG_DIRECT) {
1207 xor_rr(code, src_op.base, dst_op.base, z80_size(inst));
1208 } else if (src_op.mode == MODE_IMMED) {
1209 xor_ir(code, src_op.disp, dst_op.base, z80_size(inst));
1210 } else {
1211 xor_rdispr(code, src_op.base, src_op.disp, dst_op.base, z80_size(inst));
1212 }
1213 mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1214 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1215 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
1216 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1217 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1218 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1219 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1220 z80_save_reg(inst, opts);
1221 z80_save_ea(code, inst, opts);
1222 break;
1223 case Z80_CP:
1224 if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1225 num_cycles += 8;
1226 } else if(inst->addr_mode == Z80_IMMED) {
1227 num_cycles += 3;
1228 }
1229 cycles(&opts->gen, num_cycles);
1230 translate_z80_reg(inst, &dst_op, opts);
1231 translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
1232 mov_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
1233 if (src_op.mode == MODE_REG_DIRECT) {
1234 sub_rr(code, src_op.base, opts->gen.scratch2, z80_size(inst));
1235 mov_rrdisp(code, src_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1236 } else if (src_op.mode == MODE_IMMED) {
1237 sub_ir(code, src_op.disp, opts->gen.scratch2, z80_size(inst));
1238 mov_irdisp(code, src_op.disp, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1239 } else {
1240 sub_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, z80_size(inst));
1241 mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_B);
1242 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1243 }
1244 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
1245 mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1246 setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
1247 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1248 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1249 xor_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
1250 if (src_op.mode == MODE_REG_DIRECT) {
1251 xor_rr(code, src_op.base, opts->gen.scratch2, z80_size(inst));
1252 } else if (src_op.mode == MODE_IMMED) {
1253 xor_ir(code, src_op.disp, opts->gen.scratch2, z80_size(inst));
1254 } else {
1255 xor_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, z80_size(inst));
1256 }
1257 bt_ir(code, 4, opts->gen.scratch2, SZ_B);
1258 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
1259 z80_save_reg(inst, opts);
1260 z80_save_ea(code, inst, opts);
1261 break;
1262 case Z80_INC:
1263 case Z80_DEC:
1264 if(z80_size(inst) == SZ_W) {
1265 num_cycles += 2;
1266 } else if (inst->addr_mode == Z80_REG_INDIRECT) {
1267 num_cycles += 1;
1268 } else if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1269 num_cycles += 9;
1270 }
1271 cycles(&opts->gen, num_cycles);
1272 translate_z80_reg(inst, &dst_op, opts);
1273 if (dst_op.mode == MODE_UNUSED) {
1274 translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
1275 }
1276 if (z80_size(inst) == SZ_B) {
1277 if (dst_op.mode == MODE_REG_DIRECT) {
1278 if (dst_op.base >= AH && dst_op.base <= BH) {
1279 mov_rr(code, dst_op.base - AH, opts->gen.scratch2, SZ_W);
1280 } else {
1281 mov_rr(code, dst_op.base, opts->gen.scratch2, SZ_B);
1282 }
1283 } else {
1284 mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, SZ_B);
1285 }
1286 }
1287 if (inst->op == Z80_INC) {
1288 if (dst_op.mode == MODE_REG_DIRECT) {
1289 add_ir(code, 1, dst_op.base, z80_size(inst));
1290 } else {
1291 add_irdisp(code, 1, dst_op.base, dst_op.disp, z80_size(inst));
1292 }
1293 } else {
1294 if (dst_op.mode == MODE_REG_DIRECT) {
1295 sub_ir(code, 1, dst_op.base, z80_size(inst));
1296 } else {
1297 sub_irdisp(code, 1, dst_op.base, dst_op.disp, z80_size(inst));
1298 }
1299 }
1300 if (z80_size(inst) == SZ_B) {
1301 mov_irdisp(code, inst->op == Z80_DEC, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1302 setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
1303 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1304 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1305 int bit = 4;
1306 if (dst_op.mode == MODE_REG_DIRECT) {
1307 mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1308 if (dst_op.base >= AH && dst_op.base <= BH) {
1309 bit = 12;
1310 xor_rr(code, dst_op.base - AH, opts->gen.scratch2, SZ_W);
1311 } else {
1312 xor_rr(code, dst_op.base, opts->gen.scratch2, SZ_B);
1313 }
1314 } else {
1315 mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, SZ_B);
1316 xor_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, SZ_B);
1317 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1318 }
1319 bt_ir(code, bit, opts->gen.scratch2, SZ_W);
1320 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
1321 }
1322 z80_save_reg(inst, opts);
1323 z80_save_ea(code, inst, opts);
1324 z80_save_result(opts, inst);
1325 break;
1326 case Z80_DAA: {
1327 cycles(&opts->gen, num_cycles);
1328 xor_rr(code, opts->gen.scratch2, opts->gen.scratch2, SZ_B);
1329 zreg_to_native(opts, Z80_A, opts->gen.scratch1);
1330 and_ir(code, 0xF, opts->gen.scratch1, SZ_B);
1331 cmp_ir(code, 0xA, opts->gen.scratch1, SZ_B);
1332 mov_ir(code, 0xA0, opts->gen.scratch1, SZ_B);
1333 code_ptr corf_low_range = code->cur + 1;
1334 jcc(code, CC_NC, code->cur+2);
1335 cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1336 code_ptr corf_low = code->cur + 1;
1337 jcc(code, CC_NZ, code->cur+2);
1338 code_ptr no_corf_low = code->cur + 1;
1339 jmp(code, code->cur + 2);
1340
1341 *corf_low_range = code->cur - (corf_low_range + 1);
1342 mov_ir(code, 0x90, opts->gen.scratch1, SZ_B);
1343 *corf_low = code->cur - (corf_low + 1);
1344 mov_ir(code, 0x06, opts->gen.scratch2, SZ_B);
1345
1346 *no_corf_low = code->cur - (no_corf_low + 1);
1347 cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
1348 code_ptr corf_high = code->cur+1;
1349 jcc(code, CC_NZ, code->cur+2);
1350 cmp_rr(code, opts->gen.scratch1, opts->regs[Z80_A], SZ_B);
1351 code_ptr no_corf_high = code->cur+1;
1352 jcc(code, CC_C, code->cur+2);
1353 *corf_high = code->cur - (corf_high + 1);
1354 or_ir(code, 0x60, opts->gen.scratch2, SZ_B);
1355 mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
1356 *no_corf_high = code->cur - (no_corf_high + 1);
1357
1358 mov_rr(code, opts->regs[Z80_A], opts->gen.scratch1, SZ_B);
1359 xor_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_B);
1360
1361 cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1362 code_ptr not_sub = code->cur+1;
1363 jcc(code, CC_Z, code->cur+2);
1364 neg_r(code, opts->gen.scratch2, SZ_B);
1365 *not_sub = code->cur - (not_sub + 1);
1366
1367 add_rr(code, opts->gen.scratch2, opts->regs[Z80_A], SZ_B);
1368 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1369 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1370 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1371 xor_rr(code, opts->regs[Z80_A], opts->gen.scratch1, SZ_B);
1372 bt_ir(code, 4, opts->gen.scratch1, SZ_B);
1373 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
1374 mov_rrdisp(code, opts->regs[Z80_A], opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1375 break;
1376 }
1377 case Z80_CPL:
1378 cycles(&opts->gen, num_cycles);
1379 not_r(code, opts->regs[Z80_A], SZ_B);
1380 mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1381 mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1382 mov_rrdisp(code, opts->regs[Z80_A], opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1383 break;
1384 case Z80_NEG:
1385 cycles(&opts->gen, num_cycles);
1386 mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
1387 neg_r(code, opts->regs[Z80_A], SZ_B);
1388 mov_rrdisp(code, opts->regs[Z80_A], opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1389 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1390 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1391 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
1392 setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
1393 mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1394 xor_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
1395 bt_ir(code, 4, opts->gen.scratch2, SZ_B);
1396 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
1397 break;
1398 case Z80_CCF:
1399 cycles(&opts->gen, num_cycles);
1400 mov_rdispr(code, opts->gen.context_reg, zf_off(ZF_C), opts->gen.scratch1, SZ_B);
1401 xor_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
1402 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1403 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1404 mov_rrdisp(code, opts->regs[Z80_A], opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1405 break;
1406 case Z80_SCF:
1407 cycles(&opts->gen, num_cycles);
1408 mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
1409 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1410 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1411 mov_rrdisp(code, opts->regs[Z80_A], opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1412 break;
1413 case Z80_NOP:
1414 cycles(&opts->gen, num_cycles);
1415 break;
1416 case Z80_HALT: {
1417 code_ptr loop_top = code->cur;
1418 //this isn't terribly efficient, but it's good enough for now
1419 cycles(&opts->gen, num_cycles);
1420 check_cycles_int(&opts->gen, address+1);
1421 jmp(code, loop_top);
1422 break;
1423 }
1424 case Z80_DI:
1425 cycles(&opts->gen, num_cycles);
1426 mov_irdisp(code, 0, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B);
1427 mov_irdisp(code, 0, opts->gen.context_reg, offsetof(z80_context, iff2), SZ_B);
1428 //turn cycles remaining into current cycle
1429 neg_r(code, opts->gen.cycles, SZ_D);
1430 add_rdispr(code, opts->gen.context_reg, offsetof(z80_context, target_cycle), opts->gen.cycles, SZ_D);
1431 //set interrupt cycle to never and fetch the new target cycle from sync_cycle
1432 mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, sync_cycle), opts->gen.scratch1, SZ_D);
1433 mov_irdisp(code, 0xFFFFFFFF, opts->gen.context_reg, offsetof(z80_context, int_cycle), SZ_D);
1434 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, target_cycle), SZ_D);
1435 //turn current cycle back into cycles remaining
1436 neg_r(code, opts->gen.cycles, SZ_D);
1437 add_rr(code, opts->gen.scratch1, opts->gen.cycles, SZ_D);
1438 break;
1439 case Z80_EI:
1440 cycles(&opts->gen, num_cycles);
1441 neg_r(code, opts->gen.cycles, SZ_D);
1442 add_rdispr(code, opts->gen.context_reg, offsetof(z80_context, target_cycle), opts->gen.cycles, SZ_D);
1443 mov_rrdisp(code, opts->gen.cycles, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D);
1444 neg_r(code, opts->gen.cycles, SZ_D);
1445 add_rdispr(code, opts->gen.context_reg, offsetof(z80_context, target_cycle), opts->gen.cycles, SZ_D);
1446 mov_irdisp(code, 1, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B);
1447 mov_irdisp(code, 1, opts->gen.context_reg, offsetof(z80_context, iff2), SZ_B);
1448 //interrupt enable has a one-instruction latency, minimum instruction duration is 4 cycles
1449 add_irdisp(code, 4*opts->gen.clock_divider, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D);
1450 call(code, opts->do_sync);
1451 break;
1452 case Z80_IM:
1453 cycles(&opts->gen, num_cycles);
1454 mov_irdisp(code, inst->immed, opts->gen.context_reg, offsetof(z80_context, im), SZ_B);
1455 break;
1456 case Z80_RLC:
1457 if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1458 num_cycles += 8;
1459 }
1460 cycles(&opts->gen, num_cycles);
1461 if (inst->addr_mode != Z80_UNUSED) {
1462 translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
1463 translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register
1464 cycles(&opts->gen, 1);
1465 } else {
1466 src_op.mode = MODE_UNUSED;
1467 translate_z80_reg(inst, &dst_op, opts);
1468 }
1469 if (dst_op.mode == MODE_REG_DIRECT) {
1470 rol_ir(code, 1, dst_op.base, SZ_B);
1471 mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1472 } else {
1473 rol_irdisp(code, 1, dst_op.base, dst_op.disp, SZ_B);
1474 mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, SZ_B);
1475 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1476 }
1477 if (src_op.mode == MODE_REG_DIRECT) {
1478 mov_rr(code, dst_op.base, src_op.base, SZ_B);
1479 } else if(src_op.mode == MODE_REG_DISPLACE8) {
1480 mov_rrdisp(code, dst_op.base, src_op.base, src_op.disp, SZ_B);
1481 }
1482 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
1483 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1484 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1485 if (inst->immed) {
1486 //rlca does not set these flags
1487 if (dst_op.mode == MODE_REG_DIRECT) {
1488 cmp_ir(code, 0, dst_op.base, SZ_B);
1489 } else {
1490 cmp_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B);
1491 }
1492 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1493 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1494 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1495 }
1496 if (inst->addr_mode != Z80_UNUSED) {
1497 z80_save_result(opts, inst);
1498 if (src_op.mode != MODE_UNUSED) {
1499 z80_save_reg(inst, opts);
1500 }
1501 } else {
1502 z80_save_reg(inst, opts);
1503 }
1504 break;
1505 case Z80_RL:
1506 if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1507 num_cycles += 8;
1508 }
1509 cycles(&opts->gen, num_cycles);
1510 if (inst->addr_mode != Z80_UNUSED) {
1511 translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
1512 translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register
1513 cycles(&opts->gen, 1);
1514 } else {
1515 src_op.mode = MODE_UNUSED;
1516 translate_z80_reg(inst, &dst_op, opts);
1517 }
1518 bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
1519 if (dst_op.mode == MODE_REG_DIRECT) {
1520 rcl_ir(code, 1, dst_op.base, SZ_B);
1521 mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1522 } else {
1523 rcl_irdisp(code, 1, dst_op.base, dst_op.disp, SZ_B);
1524 mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, SZ_B);
1525 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1526 }
1527 if (src_op.mode == MODE_REG_DIRECT) {
1528 mov_rr(code, dst_op.base, src_op.base, SZ_B);
1529 } else if(src_op.mode == MODE_REG_DISPLACE8) {
1530 mov_rrdisp(code, dst_op.base, src_op.base, src_op.disp, SZ_B);
1531 }
1532 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
1533 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1534 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1535 if (inst->immed) {
1536 //rla does not set these flags
1537 if (dst_op.mode == MODE_REG_DIRECT) {
1538 cmp_ir(code, 0, dst_op.base, SZ_B);
1539 } else {
1540 cmp_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B);
1541 }
1542 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1543 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1544 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1545 }
1546 if (inst->addr_mode != Z80_UNUSED) {
1547 z80_save_result(opts, inst);
1548 if (src_op.mode != MODE_UNUSED) {
1549 z80_save_reg(inst, opts);
1550 }
1551 } else {
1552 z80_save_reg(inst, opts);
1553 }
1554 break;
1555 case Z80_RRC:
1556 if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1557 num_cycles += 8;
1558 }
1559 cycles(&opts->gen, num_cycles);
1560 if (inst->addr_mode != Z80_UNUSED) {
1561 translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
1562 translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register
1563 cycles(&opts->gen, 1);
1564 } else {
1565 src_op.mode = MODE_UNUSED;
1566 translate_z80_reg(inst, &dst_op, opts);
1567 }
1568 if (dst_op.mode == MODE_REG_DIRECT) {
1569 ror_ir(code, 1, dst_op.base, SZ_B);
1570 mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1571 } else {
1572 ror_irdisp(code, 1, dst_op.base, dst_op.disp, SZ_B);
1573 mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, SZ_B);
1574 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1575 }
1576 if (src_op.mode == MODE_REG_DIRECT) {
1577 mov_rr(code, dst_op.base, src_op.base, SZ_B);
1578 } else if(src_op.mode == MODE_REG_DISPLACE8) {
1579 mov_rrdisp(code, dst_op.base, src_op.base, src_op.disp, SZ_B);
1580 }
1581 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
1582 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1583 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1584 if (inst->immed) {
1585 //rrca does not set these flags
1586 if (dst_op.mode == MODE_REG_DIRECT) {
1587 cmp_ir(code, 0, dst_op.base, SZ_B);
1588 } else {
1589 cmp_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B);
1590 }
1591 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1592 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1593 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1594 }
1595 if (inst->addr_mode != Z80_UNUSED) {
1596 z80_save_result(opts, inst);
1597 if (src_op.mode != MODE_UNUSED) {
1598 z80_save_reg(inst, opts);
1599 }
1600 } else {
1601 z80_save_reg(inst, opts);
1602 }
1603 break;
1604 case Z80_RR:
1605 if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1606 num_cycles += 8;
1607 }
1608 cycles(&opts->gen, num_cycles);
1609 if (inst->addr_mode != Z80_UNUSED) {
1610 translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
1611 translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register
1612 cycles(&opts->gen, 1);
1613 } else {
1614 src_op.mode = MODE_UNUSED;
1615 translate_z80_reg(inst, &dst_op, opts);
1616 }
1617 bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
1618 if (dst_op.mode == MODE_REG_DIRECT) {
1619 rcr_ir(code, 1, dst_op.base, SZ_B);
1620 mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1621 } else {
1622 rcr_irdisp(code, 1, dst_op.base, dst_op.disp, SZ_B);
1623 mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, SZ_B);
1624 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1625 }
1626 if (src_op.mode == MODE_REG_DIRECT) {
1627 mov_rr(code, dst_op.base, src_op.base, SZ_B);
1628 } else if(src_op.mode == MODE_REG_DISPLACE8) {
1629 mov_rrdisp(code, dst_op.base, src_op.base, src_op.disp, SZ_B);
1630 }
1631 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
1632 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1633 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1634 if (inst->immed) {
1635 //rra does not set these flags
1636 if (dst_op.mode == MODE_REG_DIRECT) {
1637 cmp_ir(code, 0, dst_op.base, SZ_B);
1638 } else {
1639 cmp_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B);
1640 }
1641 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1642 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1643 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1644 }
1645 if (inst->addr_mode != Z80_UNUSED) {
1646 z80_save_result(opts, inst);
1647 if (src_op.mode != MODE_UNUSED) {
1648 z80_save_reg(inst, opts);
1649 }
1650 } else {
1651 z80_save_reg(inst, opts);
1652 }
1653 break;
1654 case Z80_SLA:
1655 case Z80_SLL:
1656 if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1657 num_cycles += 8;
1658 }
1659 cycles(&opts->gen, num_cycles);
1660 if (inst->addr_mode != Z80_UNUSED) {
1661 translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
1662 translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register
1663 cycles(&opts->gen, 1);
1664 } else {
1665 src_op.mode = MODE_UNUSED;
1666 translate_z80_reg(inst, &dst_op, opts);
1667 }
1668 if (dst_op.mode == MODE_REG_DIRECT) {
1669 shl_ir(code, 1, dst_op.base, SZ_B);
1670 } else {
1671 shl_irdisp(code, 1, dst_op.base, dst_op.disp, SZ_B);
1672 }
1673 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
1674 if (inst->op == Z80_SLL) {
1675 if (dst_op.mode == MODE_REG_DIRECT) {
1676 or_ir(code, 1, dst_op.base, SZ_B);
1677 } else {
1678 or_irdisp(code, 1, dst_op.base, dst_op.disp, SZ_B);
1679 }
1680 }
1681 if (src_op.mode == MODE_REG_DIRECT) {
1682 mov_rr(code, dst_op.base, src_op.base, SZ_B);
1683 } else if(src_op.mode == MODE_REG_DISPLACE8) {
1684 mov_rrdisp(code, dst_op.base, src_op.base, src_op.disp, SZ_B);
1685 }
1686 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1687 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1688 if (dst_op.mode == MODE_REG_DIRECT) {
1689 mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1690 cmp_ir(code, 0, dst_op.base, SZ_B);
1691 } else {
1692 mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, SZ_B);
1693 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1694 cmp_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B);
1695 }
1696 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1697 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1698 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1699 if (inst->addr_mode != Z80_UNUSED) {
1700 z80_save_result(opts, inst);
1701 if (src_op.mode != MODE_UNUSED) {
1702 z80_save_reg(inst, opts);
1703 }
1704 } else {
1705 z80_save_reg(inst, opts);
1706 }
1707 break;
1708 case Z80_SRA:
1709 if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1710 num_cycles += 8;
1711 }
1712 cycles(&opts->gen, num_cycles);
1713 if (inst->addr_mode != Z80_UNUSED) {
1714 translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
1715 translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register
1716 cycles(&opts->gen, 1);
1717 } else {
1718 src_op.mode = MODE_UNUSED;
1719 translate_z80_reg(inst, &dst_op, opts);
1720 }
1721 if (dst_op.mode == MODE_REG_DIRECT) {
1722 sar_ir(code, 1, dst_op.base, SZ_B);
1723 } else {
1724 sar_irdisp(code, 1, dst_op.base, dst_op.disp, SZ_B);
1725 }
1726 if (src_op.mode == MODE_REG_DIRECT) {
1727 mov_rr(code, dst_op.base, src_op.base, SZ_B);
1728 } else if(src_op.mode == MODE_REG_DISPLACE8) {
1729 mov_rrdisp(code, dst_op.base, src_op.base, src_op.disp, SZ_B);
1730 }
1731 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
1732 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1733 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1734 if (dst_op.mode == MODE_REG_DIRECT) {
1735 mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1736 cmp_ir(code, 0, dst_op.base, SZ_B);
1737 } else {
1738 mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, SZ_B);
1739 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1740 cmp_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B);
1741 }
1742 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1743 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1744 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1745 if (inst->addr_mode != Z80_UNUSED) {
1746 z80_save_result(opts, inst);
1747 if (src_op.mode != MODE_UNUSED) {
1748 z80_save_reg(inst, opts);
1749 }
1750 } else {
1751 z80_save_reg(inst, opts);
1752 }
1753 break;
1754 case Z80_SRL:
1755 if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1756 num_cycles += 8;
1757 }
1758 cycles(&opts->gen, num_cycles);
1759 if (inst->addr_mode != Z80_UNUSED) {
1760 translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
1761 translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register
1762 cycles(&opts->gen, 1);
1763 } else {
1764 src_op.mode = MODE_UNUSED;
1765 translate_z80_reg(inst, &dst_op, opts);
1766 }
1767 if (dst_op.mode == MODE_REG_DIRECT) {
1768 shr_ir(code, 1, dst_op.base, SZ_B);
1769 } else {
1770 shr_irdisp(code, 1, dst_op.base, dst_op.disp, SZ_B);
1771 }
1772 if (src_op.mode == MODE_REG_DIRECT) {
1773 mov_rr(code, dst_op.base, src_op.base, SZ_B);
1774 } else if(src_op.mode == MODE_REG_DISPLACE8) {
1775 mov_rrdisp(code, dst_op.base, src_op.base, src_op.disp, SZ_B);
1776 }
1777 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
1778 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1779 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1780 if (dst_op.mode == MODE_REG_DIRECT) {
1781 mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1782 cmp_ir(code, 0, dst_op.base, SZ_B);
1783 } else {
1784 mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, SZ_B);
1785 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1786 cmp_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B);
1787 }
1788 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1789 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1790 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1791 if (inst->addr_mode != Z80_UNUSED) {
1792 z80_save_result(opts, inst);
1793 if (src_op.mode != MODE_UNUSED) {
1794 z80_save_reg(inst, opts);
1795 }
1796 } else {
1797 z80_save_reg(inst, opts);
1798 }
1799 break;
1800 case Z80_RLD:
1801 cycles(&opts->gen, num_cycles);
1802 zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
1803 call(code, opts->read_8);
1804 //Before: (HL) = 0x12, A = 0x34
1805 //After: (HL) = 0x24, A = 0x31
1806 zreg_to_native(opts, Z80_A, opts->gen.scratch2);
1807 shl_ir(code, 4, opts->gen.scratch1, SZ_W);
1808 and_ir(code, 0xF, opts->gen.scratch2, SZ_W);
1809 and_ir(code, 0xFFF, opts->gen.scratch1, SZ_W);
1810 and_ir(code, 0xF0, opts->regs[Z80_A], SZ_B);
1811 or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_W);
1812 //opts->gen.scratch1 = 0x0124
1813 ror_ir(code, 8, opts->gen.scratch1, SZ_W);
1814 cycles(&opts->gen, 4);
1815 or_rr(code, opts->gen.scratch1, opts->regs[Z80_A], SZ_B);
1816 //set flags
1817 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1818 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1819 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1820 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1821 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1822 mov_rrdisp(code, opts->regs[Z80_A], opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1823
1824 zreg_to_native(opts, Z80_HL, opts->gen.scratch2);
1825 ror_ir(code, 8, opts->gen.scratch1, SZ_W);
1826 call(code, opts->write_8);
1827 break;
1828 case Z80_RRD:
1829 cycles(&opts->gen, num_cycles);
1830 zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
1831 call(code, opts->read_8);
1832 //Before: (HL) = 0x12, A = 0x34
1833 //After: (HL) = 0x41, A = 0x32
1834 zreg_to_native(opts, Z80_A, opts->gen.scratch2);
1835 ror_ir(code, 4, opts->gen.scratch1, SZ_W);
1836 shl_ir(code, 4, opts->gen.scratch2, SZ_W);
1837 and_ir(code, 0xF00F, opts->gen.scratch1, SZ_W);
1838 and_ir(code, 0xF0, opts->regs[Z80_A], SZ_B);
1839 and_ir(code, 0xF0, opts->gen.scratch2, SZ_W);
1840 //opts->gen.scratch1 = 0x2001
1841 //opts->gen.scratch2 = 0x0040
1842 or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_W);
1843 //opts->gen.scratch1 = 0x2041
1844 ror_ir(code, 8, opts->gen.scratch1, SZ_W);
1845 cycles(&opts->gen, 4);
1846 shr_ir(code, 4, opts->gen.scratch1, SZ_B);
1847 or_rr(code, opts->gen.scratch1, opts->regs[Z80_A], SZ_B);
1848 //set flags
1849 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1850 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1851 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1852 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1853 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1854 mov_rrdisp(code, opts->regs[Z80_A], opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1855
1856 zreg_to_native(opts, Z80_HL, opts->gen.scratch2);
1857 ror_ir(code, 8, opts->gen.scratch1, SZ_W);
1858 call(code, opts->write_8);
1859 break;
1860 case Z80_BIT: {
1861 if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1862 num_cycles += 4;
1863 }
1864 cycles(&opts->gen, num_cycles);
1865 uint8_t bit;
1866 if ((inst->addr_mode & 0x1F) == Z80_REG && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) {
1867 src_op.base = opts->regs[z80_word_reg(inst->ea_reg)];
1868 src_op.mode = MODE_REG_DIRECT;
1869 size = SZ_W;
1870 bit = inst->immed + 8;
1871 } else {
1872 size = SZ_B;
1873 bit = inst->immed;
1874 translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
1875 }
1876 if (inst->addr_mode != Z80_REG) {
1877 //Reads normally take 3 cycles, but the read at the end of a bit instruction takes 4
1878 cycles(&opts->gen, 1);
1879 }
1880 if (src_op.mode == MODE_REG_DIRECT) {
1881 bt_ir(code, bit, src_op.base, size);
1882 } else {
1883 bt_irdisp(code, bit, src_op.base, src_op.disp, size);
1884 }
1885 setcc_rdisp(code, CC_NC, opts->gen.context_reg, zf_off(ZF_Z));
1886 setcc_rdisp(code, CC_NC, opts->gen.context_reg, zf_off(ZF_PV));
1887 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1888 mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1889 if (inst->immed == 7) {
1890 if (src_op.mode == MODE_REG_DIRECT) {
1891 cmp_ir(code, 0, src_op.base, size);
1892 } else {
1893 cmp_irdisp(code, 0, src_op.base, src_op.disp, size);
1894 }
1895 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1896 } else {
1897 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B);
1898 }
1899
1900 if ((inst->addr_mode & 0x1F) == Z80_REG) {
1901 if (src_op.mode == MODE_REG_DIRECT) {
1902 if (size == SZ_W) {
1903 mov_rr(code, src_op.base, opts->gen.scratch1, SZ_W);
1904 shr_ir(code, 8, opts->gen.scratch1, SZ_W);
1905 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1906 } else {
1907 mov_rrdisp(code, src_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1908 }
1909 } else {
1910 mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_B);
1911 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1912 }
1913 } else if((inst->addr_mode & 0x1F) != Z80_REG_INDIRECT) {
1914 zreg_to_native(opts, (inst->addr_mode & 0x1F) == Z80_IX_DISPLACE ? Z80_IX : Z80_IY, opts->gen.scratch2);
1915 add_ir(code, inst->ea_reg & 0x80 ? inst->ea_reg - 256 : inst->ea_reg, opts->gen.scratch2, SZ_W);
1916 shr_ir(code, 8, opts->gen.scratch2, SZ_W);
1917 mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1918 }
1919 break;
1920 }
1921 case Z80_SET: {
1922 if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1923 num_cycles += 4;
1924 }
1925 cycles(&opts->gen, num_cycles);
1926 uint8_t bit;
1927 if ((inst->addr_mode & 0x1F) == Z80_REG && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) {
1928 src_op.base = opts->regs[z80_word_reg(inst->ea_reg)];
1929 src_op.mode = MODE_REG_DIRECT;
1930 size = SZ_W;
1931 bit = inst->immed + 8;
1932 } else {
1933 size = SZ_B;
1934 bit = inst->immed;
1935 translate_z80_ea(inst, &src_op, opts, READ, MODIFY);
1936 }
1937 if (inst->reg != Z80_USE_IMMED) {
1938 translate_z80_reg(inst, &dst_op, opts);
1939 }
1940 if (inst->addr_mode != Z80_REG) {
1941 //Reads normally take 3 cycles, but the read in the middle of a set instruction takes 4
1942 cycles(&opts->gen, 1);
1943 }
1944 if (src_op.mode == MODE_REG_DIRECT) {
1945 bts_ir(code, bit, src_op.base, size);
1946 } else {
1947 bts_irdisp(code, bit, src_op.base, src_op.disp, size);
1948 }
1949 if (inst->reg != Z80_USE_IMMED) {
1950 if (size == SZ_W) {
1951#ifdef X86_64
1952 if (dst_op.base >= R8) {
1953 ror_ir(code, 8, src_op.base, SZ_W);
1954 mov_rr(code, opts->regs[z80_low_reg(inst->ea_reg)], dst_op.base, SZ_B);
1955 ror_ir(code, 8, src_op.base, SZ_W);
1956 } else {
1957#endif
1958 if (dst_op.mode == MODE_REG_DIRECT) {
1959 zreg_to_native(opts, inst->ea_reg, dst_op.base);
1960 } else {
1961 zreg_to_native(opts, inst->ea_reg, opts->gen.scratch1);
1962 mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_B);
1963 }
1964#ifdef X86_64
1965 }
1966#endif
1967 } else {
1968 if (dst_op.mode == MODE_REG_DIRECT) {
1969 if (src_op.mode == MODE_REG_DIRECT) {
1970 mov_rr(code, src_op.base, dst_op.base, SZ_B);
1971 } else {
1972 mov_rdispr(code, src_op.base, src_op.disp, dst_op.base, SZ_B);
1973 }
1974 } else if (src_op.mode == MODE_REG_DIRECT) {
1975 mov_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, SZ_B);
1976 } else {
1977 mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_B);
1978 mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_B);
1979 }
1980 }
1981 }
1982 if ((inst->addr_mode & 0x1F) != Z80_REG) {
1983 z80_save_result(opts, inst);
1984 if (inst->reg != Z80_USE_IMMED) {
1985 z80_save_reg(inst, opts);
1986 }
1987 }
1988 break;
1989 }
1990 case Z80_RES: {
1991 if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1992 num_cycles += 4;
1993 }
1994 cycles(&opts->gen, num_cycles);
1995 uint8_t bit;
1996 if ((inst->addr_mode & 0x1F) == Z80_REG && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) {
1997 src_op.base = opts->regs[z80_word_reg(inst->ea_reg)];
1998 src_op.mode = MODE_REG_DIRECT;
1999 size = SZ_W;
2000 bit = inst->immed + 8;
2001 } else {
2002 size = SZ_B;
2003 bit = inst->immed;
2004 translate_z80_ea(inst, &src_op, opts, READ, MODIFY);
2005 }
2006 if (inst->reg != Z80_USE_IMMED) {
2007 translate_z80_reg(inst, &dst_op, opts);
2008 }
2009 if (inst->addr_mode != Z80_REG) {
2010 //Reads normally take 3 cycles, but the read in the middle of a set instruction takes 4
2011 cycles(&opts->gen, 1);
2012 }
2013 if (src_op.mode == MODE_REG_DIRECT) {
2014 btr_ir(code, bit, src_op.base, size);
2015 } else {
2016 btr_irdisp(code, bit, src_op.base, src_op.disp, size);
2017 }
2018 if (inst->reg != Z80_USE_IMMED) {
2019 if (size == SZ_W) {
2020#ifdef X86_64
2021 if (dst_op.base >= R8) {
2022 ror_ir(code, 8, src_op.base, SZ_W);
2023 mov_rr(code, opts->regs[z80_low_reg(inst->ea_reg)], dst_op.base, SZ_B);
2024 ror_ir(code, 8, src_op.base, SZ_W);
2025 } else {
2026#endif
2027 if (dst_op.mode == MODE_REG_DIRECT) {
2028 zreg_to_native(opts, inst->ea_reg, dst_op.base);
2029 } else {
2030 zreg_to_native(opts, inst->ea_reg, opts->gen.scratch1);
2031 mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_B);
2032 }
2033#ifdef X86_64
2034 }
2035#endif
2036 } else {
2037 if (dst_op.mode == MODE_REG_DIRECT) {
2038 if (src_op.mode == MODE_REG_DIRECT) {
2039 mov_rr(code, src_op.base, dst_op.base, SZ_B);
2040 } else {
2041 mov_rdispr(code, src_op.base, src_op.disp, dst_op.base, SZ_B);
2042 }
2043 } else if (src_op.mode == MODE_REG_DIRECT) {
2044 mov_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, SZ_B);
2045 } else {
2046 mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_B);
2047 mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_B);
2048 }
2049 }
2050 }
2051 if (inst->addr_mode != Z80_REG) {
2052 z80_save_result(opts, inst);
2053 if (inst->reg != Z80_USE_IMMED) {
2054 z80_save_reg(inst, opts);
2055 }
2056 }
2057 break;
2058 }
2059 case Z80_JP: {
2060 if (inst->addr_mode != Z80_REG_INDIRECT) {
2061 num_cycles += 6;
2062 }
2063 cycles(&opts->gen, num_cycles);
2064 if (inst->addr_mode != Z80_REG_INDIRECT) {
2065 code_ptr call_dst = z80_get_native_address(context, inst->immed);
2066 if (!call_dst) {
2067 opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1);
2068 //fake address to force large displacement
2069 call_dst = code->cur + 256;
2070 }
2071 jmp(code, call_dst);
2072 } else {
2073 if (inst->addr_mode == Z80_REG_INDIRECT) {
2074 zreg_to_native(opts, inst->ea_reg, opts->gen.scratch1);
2075 } else {
2076 mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W);
2077 }
2078 call(code, opts->native_addr);
2079 jmp_r(code, opts->gen.scratch1);
2080 }
2081 break;
2082 }
2083 case Z80_JPCC: {
2084 cycles(&opts->gen, num_cycles + 6);//T States: 4,3,3
2085 uint8_t cond = CC_Z;
2086 switch (inst->reg)
2087 {
2088 case Z80_CC_NZ:
2089 cond = CC_NZ;
2090 case Z80_CC_Z:
2091 cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B);
2092 break;
2093 case Z80_CC_NC:
2094 cond = CC_NZ;
2095 case Z80_CC_C:
2096 cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
2097 break;
2098 case Z80_CC_PO:
2099 cond = CC_NZ;
2100 case Z80_CC_PE:
2101 cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B);
2102 break;
2103 case Z80_CC_P:
2104 cond = CC_NZ;
2105 case Z80_CC_M:
2106 cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B);
2107 break;
2108 }
2109 uint8_t *no_jump_off = code->cur+1;
2110 jcc(code, cond, code->cur+2);
2111 uint16_t dest_addr = inst->immed;
2112 code_ptr call_dst = z80_get_native_address(context, dest_addr);
2113 if (!call_dst) {
2114 opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1);
2115 //fake address to force large displacement
2116 call_dst = code->cur + 256;
2117 }
2118 jmp(code, call_dst);
2119 *no_jump_off = code->cur - (no_jump_off+1);
2120 break;
2121 }
2122 case Z80_JR: {
2123 cycles(&opts->gen, num_cycles + 8);//T States: 4,3,5
2124 uint16_t dest_addr = address + inst->immed + 2;
2125 code_ptr call_dst = z80_get_native_address(context, dest_addr);
2126 if (!call_dst) {
2127 opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1);
2128 //fake address to force large displacement
2129 call_dst = code->cur + 256;
2130 }
2131 jmp(code, call_dst);
2132 break;
2133 }
2134 case Z80_JRCC: {
2135 cycles(&opts->gen, num_cycles + 3);//T States: 4,3
2136 uint8_t cond = CC_Z;
2137 switch (inst->reg)
2138 {
2139 case Z80_CC_NZ:
2140 cond = CC_NZ;
2141 case Z80_CC_Z:
2142 cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B);
2143 break;
2144 case Z80_CC_NC:
2145 cond = CC_NZ;
2146 case Z80_CC_C:
2147 cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
2148 break;
2149 }
2150 uint8_t *no_jump_off = code->cur+1;
2151 jcc(code, cond, code->cur+2);
2152 cycles(&opts->gen, 5);//T States: 5
2153 uint16_t dest_addr = address + inst->immed + 2;
2154 code_ptr call_dst = z80_get_native_address(context, dest_addr);
2155 if (!call_dst) {
2156 opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1);
2157 //fake address to force large displacement
2158 call_dst = code->cur + 256;
2159 }
2160 jmp(code, call_dst);
2161 *no_jump_off = code->cur - (no_jump_off+1);
2162 break;
2163 }
2164 case Z80_DJNZ: {
2165 cycles(&opts->gen, num_cycles + 4);//T States: 5,3
2166 if (opts->regs[Z80_B] >= 0) {
2167 sub_ir(code, 1, opts->regs[Z80_B], SZ_B);
2168 } else {
2169 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2170 }
2171 uint8_t *no_jump_off = code->cur+1;
2172 jcc(code, CC_Z, code->cur+2);
2173 cycles(&opts->gen, 5);//T States: 5
2174 uint16_t dest_addr = address + inst->immed + 2;
2175 code_ptr call_dst = z80_get_native_address(context, dest_addr);
2176 if (!call_dst) {
2177 opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1);
2178 //fake address to force large displacement
2179 call_dst = code->cur + 256;
2180 }
2181 jmp(code, call_dst);
2182 *no_jump_off = code->cur - (no_jump_off+1);
2183 break;
2184 }
2185 case Z80_CALL: {
2186 cycles(&opts->gen, num_cycles + 7);//T States: 4,3,4
2187 sub_ir(code, 2, opts->regs[Z80_SP], SZ_W);
2188 mov_ir(code, address + 3, opts->gen.scratch1, SZ_W);
2189 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
2190 call(code, opts->write_16_highfirst);//T States: 3, 3
2191 code_ptr call_dst = z80_get_native_address(context, inst->immed);
2192 if (!call_dst) {
2193 opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1);
2194 //fake address to force large displacement
2195 call_dst = code->cur + 256;
2196 }
2197 jmp(code, call_dst);
2198 break;
2199 }
2200 case Z80_CALLCC: {
2201 cycles(&opts->gen, num_cycles + 6);//T States: 4,3,3 (false case)
2202 uint8_t cond = CC_Z;
2203 switch (inst->reg)
2204 {
2205 case Z80_CC_NZ:
2206 cond = CC_NZ;
2207 case Z80_CC_Z:
2208 cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B);
2209 break;
2210 case Z80_CC_NC:
2211 cond = CC_NZ;
2212 case Z80_CC_C:
2213 cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
2214 break;
2215 case Z80_CC_PO:
2216 cond = CC_NZ;
2217 case Z80_CC_PE:
2218 cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B);
2219 break;
2220 case Z80_CC_P:
2221 cond = CC_NZ;
2222 case Z80_CC_M:
2223 cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B);
2224 break;
2225 }
2226 uint8_t *no_call_off = code->cur+1;
2227 jcc(code, cond, code->cur+2);
2228 cycles(&opts->gen, 1);//Last of the above T states takes an extra cycle in the true case
2229 sub_ir(code, 2, opts->regs[Z80_SP], SZ_W);
2230 mov_ir(code, address + 3, opts->gen.scratch1, SZ_W);
2231 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
2232 call(code, opts->write_16_highfirst);//T States: 3, 3
2233 code_ptr call_dst = z80_get_native_address(context, inst->immed);
2234 if (!call_dst) {
2235 opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1);
2236 //fake address to force large displacement
2237 call_dst = code->cur + 256;
2238 }
2239 jmp(code, call_dst);
2240 *no_call_off = code->cur - (no_call_off+1);
2241 break;
2242 }
2243 case Z80_RET:
2244 cycles(&opts->gen, num_cycles);//T States: 4
2245 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
2246 call(code, opts->read_16);//T STates: 3, 3
2247 add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
2248 call(code, opts->native_addr);
2249 jmp_r(code, opts->gen.scratch1);
2250 break;
2251 case Z80_RETCC: {
2252 cycles(&opts->gen, num_cycles + 1);//T States: 5
2253 uint8_t cond = CC_Z;
2254 switch (inst->reg)
2255 {
2256 case Z80_CC_NZ:
2257 cond = CC_NZ;
2258 case Z80_CC_Z:
2259 cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B);
2260 break;
2261 case Z80_CC_NC:
2262 cond = CC_NZ;
2263 case Z80_CC_C:
2264 cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
2265 break;
2266 case Z80_CC_PO:
2267 cond = CC_NZ;
2268 case Z80_CC_PE:
2269 cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B);
2270 break;
2271 case Z80_CC_P:
2272 cond = CC_NZ;
2273 case Z80_CC_M:
2274 cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B);
2275 break;
2276 }
2277 uint8_t *no_call_off = code->cur+1;
2278 jcc(code, cond, code->cur+2);
2279 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
2280 call(code, opts->read_16);//T STates: 3, 3
2281 add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
2282 call(code, opts->native_addr);
2283 jmp_r(code, opts->gen.scratch1);
2284 *no_call_off = code->cur - (no_call_off+1);
2285 break;
2286 }
2287 case Z80_RETI:
2288 //For some systems, this may need a callback for signalling interrupt routine completion
2289 cycles(&opts->gen, num_cycles);//T States: 4, 4
2290 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
2291 call(code, opts->read_16);//T STates: 3, 3
2292 add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
2293 call(code, opts->native_addr);
2294 jmp_r(code, opts->gen.scratch1);
2295 break;
2296 case Z80_RETN:
2297 cycles(&opts->gen, num_cycles);//T States: 4, 4
2298 mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, iff2), opts->gen.scratch2, SZ_B);
2299 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
2300 mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B);
2301 call(code, opts->read_16);//T STates: 3, 3
2302 add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
2303 call(code, opts->native_addr);
2304 jmp_r(code, opts->gen.scratch1);
2305 break;
2306 case Z80_RST: {
2307 //RST is basically CALL to an address in page 0
2308 cycles(&opts->gen, num_cycles + 1);//T States: 5
2309 sub_ir(code, 2, opts->regs[Z80_SP], SZ_W);
2310 mov_ir(code, address + 1, opts->gen.scratch1, SZ_W);
2311 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
2312 call(code, opts->write_16_highfirst);//T States: 3, 3
2313 code_ptr call_dst = z80_get_native_address(context, inst->immed);
2314 if (!call_dst) {
2315 opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1);
2316 //fake address to force large displacement
2317 call_dst = code->cur + 256;
2318 }
2319 jmp(code, call_dst);
2320 break;
2321 }
2322 case Z80_IN:
2323 if (inst->addr_mode == Z80_IMMED_INDIRECT) {
2324 num_cycles += 3;
2325 }
2326 cycles(&opts->gen, num_cycles);//T States: 4 3/4
2327 if (inst->addr_mode == Z80_IMMED_INDIRECT) {
2328 mov_ir(code, inst->immed, opts->gen.scratch1, SZ_B);
2329 } else {
2330 zreg_to_native(opts, Z80_C, opts->gen.scratch2);
2331 }
2332 call(code, opts->read_io);
2333 if (inst->addr_mode != Z80_IMMED_INDIRECT) {
2334 or_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_B);
2335 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
2336 mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
2337 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
2338 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
2339 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
2340 }
2341 if (inst->reg != Z80_UNUSED) {
2342 translate_z80_reg(inst, &dst_op, opts);
2343 if (dst_op.mode == MODE_REG_DIRECT) {
2344 mov_rr(code, opts->gen.scratch1, dst_op.base, SZ_B);
2345 } else {
2346 mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_B);
2347 }
2348 }
2349 z80_save_reg(inst, opts);
2350 break;
2351 case Z80_INI:
2352 cycles(&opts->gen, num_cycles + 1);//T States: 4, 5
2353 //read from IO (C)
2354 zreg_to_native(opts, Z80_BC, opts->gen.scratch1);
2355 call(code, opts->read_io);//T states 3
2356
2357 //undocumented N flag behavior
2358 //flag set on bit 7 of value written
2359 bt_ir(code, 7, opts->gen.scratch1, SZ_B);
2360 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_N));
2361 //save value to be written for flag calculation, as the write func does not
2362 //guarantee that it's preserved across the call
2363 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_B);
2364
2365 //write to (HL)
2366 zreg_to_native(opts, Z80_HL, opts->gen.scratch2);
2367 call(code, opts->write_8);//T states 4
2368 cycles(&opts->gen, 1);
2369
2370 //increment HL
2371 if (opts->regs[Z80_HL] >= 0) {
2372 add_ir(code, 1, opts->regs[Z80_HL], SZ_W);
2373 } else {
2374 add_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_B);
2375 }
2376 mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, scratch1), opts->gen.scratch1, SZ_B);
2377 if (opts->regs[Z80_C] >= 0) {
2378 add_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
2379 } else {
2380 add_rdispr(code, opts->gen.context_reg, zr_off(Z80_C), opts->gen.scratch1, SZ_B);
2381 }
2382 add_ir(code, 1, opts->gen.scratch1, SZ_B);
2383 //undocumented C and H flag behavior
2384 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
2385 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
2386 //decrement B
2387 if (opts->regs[Z80_B] >= 0) {
2388 sub_ir(code, 1, opts->regs[Z80_B], SZ_B);
2389 mov_rrdisp(code, opts->regs[Z80_B], opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
2390 } else {
2391 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2392 }
2393 //undocumented Z and S flag behavior, set based on decrement of B
2394 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
2395 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
2396 //crazy undocumented P/V flag behavior
2397 and_ir(code, 7, opts->gen.scratch1, SZ_B);
2398 if (opts->regs[Z80_B] >= 0) {
2399 //deal with silly x86-64 restrictions on *H registers
2400 ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2401 xor_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
2402 ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2403 } else {
2404 xor_rdispr(code, opts->gen.context_reg, zr_off(Z80_B), opts->gen.scratch1, SZ_B);
2405 }
2406 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
2407 break;
2408 case Z80_INIR: {
2409 cycles(&opts->gen, num_cycles + 1);//T States: 4, 5
2410 //read from IO (C)
2411 zreg_to_native(opts, Z80_BC, opts->gen.scratch1);
2412 call(code, opts->read_io);//T states 3
2413
2414 //undocumented N flag behavior
2415 //flag set on bit 7 of value written
2416 bt_ir(code, 7, opts->gen.scratch1, SZ_B);
2417 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_N));
2418 //save value to be written for flag calculation, as the write func does not
2419 //guarantee that it's preserved across the call
2420 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_B);
2421
2422 //write to (HL)
2423 zreg_to_native(opts, Z80_HL, opts->gen.scratch2);
2424 call(code, opts->write_8);//T states 4
2425 cycles(&opts->gen, 1);
2426
2427 //increment HL
2428 if (opts->regs[Z80_HL] >= 0) {
2429 add_ir(code, 1, opts->regs[Z80_HL], SZ_W);
2430 } else {
2431 add_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_B);
2432 }
2433 mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, scratch1), opts->gen.scratch1, SZ_B);
2434 if (opts->regs[Z80_C] >= 0) {
2435 add_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
2436 } else {
2437 add_rdispr(code, opts->gen.context_reg, zr_off(Z80_C), opts->gen.scratch1, SZ_B);
2438 }
2439 add_ir(code, 1, opts->gen.scratch1, SZ_B);
2440 //undocumented C and H flag behavior
2441 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
2442 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
2443 //decrement B
2444 if (opts->regs[Z80_B] >= 0) {
2445 sub_ir(code, 1, opts->regs[Z80_B], SZ_B);
2446 mov_rrdisp(code, opts->regs[Z80_B], opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
2447 } else {
2448 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2449 }
2450 //undocumented Z and S flag behavior, set based on decrement of B
2451 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
2452 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
2453 //crazy undocumented P/V flag behavior
2454 and_ir(code, 7, opts->gen.scratch1, SZ_B);
2455 if (opts->regs[Z80_B] >= 0) {
2456 //deal with silly x86-64 restrictions on *H registers
2457 ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2458 xor_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
2459 ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2460 } else {
2461 xor_rdispr(code, opts->gen.context_reg, zr_off(Z80_B), opts->gen.scratch1, SZ_B);
2462 }
2463 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
2464 if (opts->regs[Z80_B] >= 0) {
2465 cmp_ir(code, 0, opts->regs[Z80_B], SZ_B);
2466 } else {
2467 cmp_irdisp(code, 0, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2468 }
2469 code_ptr done = code->cur+1;
2470 jcc(code, CC_Z, code->cur+2);
2471 cycles(&opts->gen, 5);
2472 jmp(code, start);
2473 *done = code->cur - (done + 1);
2474 break;
2475 }
2476 case Z80_IND:
2477 cycles(&opts->gen, num_cycles + 1);//T States: 4, 5
2478 //read from IO (C)
2479 zreg_to_native(opts, Z80_BC, opts->gen.scratch1);
2480 call(code, opts->read_io);//T states 3
2481
2482 //undocumented N flag behavior
2483 //flag set on bit 7 of value written
2484 bt_ir(code, 7, opts->gen.scratch1, SZ_B);
2485 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_N));
2486 //save value to be written for flag calculation, as the write func does not
2487 //guarantee that it's preserved across the call
2488 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_B);
2489
2490 //write to (HL)
2491 zreg_to_native(opts, Z80_HL, opts->gen.scratch2);
2492 call(code, opts->write_8);//T states 4
2493 cycles(&opts->gen, 1);
2494
2495 //decrement HL
2496 if (opts->regs[Z80_HL] >= 0) {
2497 sub_ir(code, 1, opts->regs[Z80_HL], SZ_W);
2498 } else {
2499 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_B);
2500 }
2501 mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, scratch1), opts->gen.scratch1, SZ_B);
2502 if (opts->regs[Z80_C] >= 0) {
2503 add_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
2504 } else {
2505 add_rdispr(code, opts->gen.context_reg, zr_off(Z80_C), opts->gen.scratch1, SZ_B);
2506 }
2507 add_ir(code, 1, opts->gen.scratch1, SZ_B);
2508 //undocumented C and H flag behavior
2509 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
2510 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
2511 //decrement B
2512 if (opts->regs[Z80_B] >= 0) {
2513 sub_ir(code, 1, opts->regs[Z80_B], SZ_B);
2514 mov_rrdisp(code, opts->regs[Z80_B], opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
2515 } else {
2516 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2517 }
2518 //undocumented Z and S flag behavior, set based on decrement of B
2519 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
2520 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
2521 //crazy undocumented P/V flag behavior
2522 and_ir(code, 7, opts->gen.scratch1, SZ_B);
2523 if (opts->regs[Z80_B] >= 0) {
2524 //deal with silly x86-64 restrictions on *H registers
2525 ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2526 xor_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
2527 ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2528 } else {
2529 xor_rdispr(code, opts->gen.context_reg, zr_off(Z80_B), opts->gen.scratch1, SZ_B);
2530 }
2531 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
2532 break;
2533 case Z80_INDR: {
2534 cycles(&opts->gen, num_cycles + 1);//T States: 4, 5
2535 //read from IO (C)
2536 zreg_to_native(opts, Z80_BC, opts->gen.scratch1);
2537 call(code, opts->read_io);//T states 3
2538
2539 //undocumented N flag behavior
2540 //flag set on bit 7 of value written
2541 bt_ir(code, 7, opts->gen.scratch1, SZ_B);
2542 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_N));
2543 //save value to be written for flag calculation, as the write func does not
2544 //guarantee that it's preserved across the call
2545 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_B);
2546
2547 //write to (HL)
2548 zreg_to_native(opts, Z80_HL, opts->gen.scratch2);
2549 call(code, opts->write_8);//T states 4
2550 cycles(&opts->gen, 1);
2551
2552 //decrement HL
2553 if (opts->regs[Z80_HL] >= 0) {
2554 sub_ir(code, 1, opts->regs[Z80_HL], SZ_W);
2555 } else {
2556 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_B);
2557 }
2558 mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, scratch1), opts->gen.scratch1, SZ_B);
2559 if (opts->regs[Z80_C] >= 0) {
2560 add_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
2561 } else {
2562 add_rdispr(code, opts->gen.context_reg, zr_off(Z80_C), opts->gen.scratch1, SZ_B);
2563 }
2564 add_ir(code, 1, opts->gen.scratch1, SZ_B);
2565 //undocumented C and H flag behavior
2566 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
2567 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
2568 //decrement B
2569 if (opts->regs[Z80_B] >= 0) {
2570 sub_ir(code, 1, opts->regs[Z80_B], SZ_B);
2571 mov_rrdisp(code, opts->regs[Z80_B], opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
2572 } else {
2573 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2574 }
2575 //undocumented Z and S flag behavior, set based on decrement of B
2576 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
2577 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
2578 //crazy undocumented P/V flag behavior
2579 and_ir(code, 7, opts->gen.scratch1, SZ_B);
2580 if (opts->regs[Z80_B] >= 0) {
2581 //deal with silly x86-64 restrictions on *H registers
2582 ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2583 xor_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
2584 ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2585 } else {
2586 xor_rdispr(code, opts->gen.context_reg, zr_off(Z80_B), opts->gen.scratch1, SZ_B);
2587 }
2588 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
2589 if (opts->regs[Z80_B] >= 0) {
2590 cmp_ir(code, 0, opts->regs[Z80_B], SZ_B);
2591 } else {
2592 cmp_irdisp(code, 0, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2593 }
2594 code_ptr done = code->cur+1;
2595 jcc(code, CC_Z, code->cur+2);
2596 cycles(&opts->gen, 5);
2597 jmp(code, start);
2598 *done = code->cur - (done + 1);
2599 break;
2600 }
2601 case Z80_OUT:
2602 if (inst->addr_mode == Z80_IMMED_INDIRECT) {
2603 num_cycles += 3;
2604 }
2605 cycles(&opts->gen, num_cycles);//T States: 4 3/4
2606 if ((inst->addr_mode & 0x1F) == Z80_IMMED_INDIRECT) {
2607 mov_ir(code, inst->immed, opts->gen.scratch2, SZ_B);
2608 } else {
2609 zreg_to_native(opts, Z80_C, opts->gen.scratch2);
2610 }
2611 translate_z80_reg(inst, &src_op, opts);
2612 if (src_op.mode == MODE_REG_DIRECT) {
2613 mov_rr(code, src_op.base, opts->gen.scratch1, SZ_B);
2614 } else if (src_op.mode == MODE_IMMED) {
2615 mov_ir(code, src_op.disp, opts->gen.scratch1, SZ_B);
2616 } else {
2617 mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_B);
2618 }
2619 call(code, opts->write_io);
2620 z80_save_reg(inst, opts);
2621 break;
2622 case Z80_OUTI:
2623 cycles(&opts->gen, num_cycles + 1);//T States: 4, 5
2624 //read from (HL)
2625 zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
2626 call(code, opts->read_8);//T states 3
2627 //undocumented N flag behavior
2628 //flag set on bit 7 of value written
2629 bt_ir(code, 7, opts->gen.scratch1, SZ_B);
2630 setcc_rdisp(code, CC_NC, opts->gen.context_reg, zf_off(ZF_N));
2631 //write to IO (C)
2632 zreg_to_native(opts, Z80_C, opts->gen.scratch2);
2633 call(code, opts->write_io);//T states 4
2634 //increment HL
2635 if (opts->regs[Z80_HL] >= 0) {
2636 add_ir(code, 1, opts->regs[Z80_HL], SZ_W);
2637 add_rr(code, opts->regs[Z80_L], opts->gen.scratch1, SZ_B);
2638 } else {
2639 add_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_B);
2640 add_rdispr(code, opts->gen.context_reg, zr_off(Z80_L), opts->gen.scratch1, SZ_B);
2641 }
2642 //undocumented C and H flag behavior
2643 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
2644 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
2645 //decrement B
2646 if (opts->regs[Z80_B] >= 0) {
2647 sub_ir(code, 1, opts->regs[Z80_B], SZ_B);
2648 } else {
2649 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2650 }
2651 //undocumented Z and S flag behavior, set based on decrement of B
2652 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
2653 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
2654 //crazy undocumented P/V flag behavior
2655 and_ir(code, 7, opts->gen.scratch1, SZ_B);
2656 if (opts->regs[Z80_B] >= 0) {
2657 //deal with silly x86-64 restrictions on *H registers
2658 ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2659 xor_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
2660 ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2661 } else {
2662 xor_rdispr(code, opts->gen.context_reg, zr_off(Z80_B), opts->gen.scratch1, SZ_B);
2663 }
2664 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
2665 break;
2666 case Z80_OTIR: {
2667 cycles(&opts->gen, num_cycles + 1);//T States: 4, 5
2668 //read from (HL)
2669 zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
2670 call(code, opts->read_8);//T states 3
2671 //undocumented N flag behavior
2672 //flag set on bit 7 of value written
2673 bt_ir(code, 7, opts->gen.scratch1, SZ_B);
2674 setcc_rdisp(code, CC_NC, opts->gen.context_reg, zf_off(ZF_N));
2675 //write to IO (C)
2676 zreg_to_native(opts, Z80_C, opts->gen.scratch2);
2677 call(code, opts->write_io);//T states 4
2678 //increment HL
2679 if (opts->regs[Z80_HL] >= 0) {
2680 add_ir(code, 1, opts->regs[Z80_HL], SZ_W);
2681 add_rr(code, opts->regs[Z80_L], opts->gen.scratch1, SZ_B);
2682 } else {
2683 add_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_B);
2684 add_rdispr(code, opts->gen.context_reg, zr_off(Z80_L), opts->gen.scratch1, SZ_B);
2685 }
2686 //undocumented C and H flag behavior
2687 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
2688 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
2689 //decrement B
2690 if (opts->regs[Z80_B] >= 0) {
2691 sub_ir(code, 1, opts->regs[Z80_B], SZ_B);
2692 } else {
2693 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2694 }
2695 //undocumented Z and S flag behavior, set based on decrement of B
2696 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
2697 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
2698 //crazy undocumented P/V flag behavior
2699 and_ir(code, 7, opts->gen.scratch1, SZ_B);
2700 if (opts->regs[Z80_B] >= 0) {
2701 //deal with silly x86-64 restrictions on *H registers
2702 ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2703 xor_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
2704 ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2705 } else {
2706 xor_rdispr(code, opts->gen.context_reg, zr_off(Z80_B), opts->gen.scratch1, SZ_B);
2707 }
2708 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
2709 if (opts->regs[Z80_B] >= 0) {
2710 cmp_ir(code, 0, opts->regs[Z80_B], SZ_B);
2711 } else {
2712 cmp_irdisp(code, 0, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2713 }
2714 code_ptr done = code->cur+1;
2715 jcc(code, CC_Z, code->cur+2);
2716 cycles(&opts->gen, 5);
2717 jmp(code, start);
2718 *done = code->cur - (done + 1);
2719 break;
2720 }
2721 case Z80_OUTD:
2722 cycles(&opts->gen, num_cycles + 1);//T States: 4, 5
2723 //read from (HL)
2724 zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
2725 call(code, opts->read_8);//T states 3
2726 //undocumented N flag behavior
2727 //flag set on bit 7 of value written
2728 bt_ir(code, 7, opts->gen.scratch1, SZ_B);
2729 setcc_rdisp(code, CC_NC, opts->gen.context_reg, zf_off(ZF_N));
2730 //write to IO (C)
2731 zreg_to_native(opts, Z80_C, opts->gen.scratch2);
2732 call(code, opts->write_io);//T states 4
2733 //decrement HL
2734 if (opts->regs[Z80_HL] >= 0) {
2735 sub_ir(code, 1, opts->regs[Z80_HL], SZ_W);
2736 add_rr(code, opts->regs[Z80_L], opts->gen.scratch1, SZ_B);
2737 } else {
2738 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_B);
2739 add_rdispr(code, opts->gen.context_reg, zr_off(Z80_L), opts->gen.scratch1, SZ_B);
2740 }
2741 //undocumented C and H flag behavior
2742 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
2743 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
2744 //decrement B
2745 if (opts->regs[Z80_B] >= 0) {
2746 sub_ir(code, 1, opts->regs[Z80_B], SZ_B);
2747 } else {
2748 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2749 }
2750 //undocumented Z and S flag behavior, set based on decrement of B
2751 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
2752 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
2753 //crazy undocumented P/V flag behavior
2754 and_ir(code, 7, opts->gen.scratch1, SZ_B);
2755 if (opts->regs[Z80_B] >= 0) {
2756 //deal with silly x86-64 restrictions on *H registers
2757 ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2758 xor_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
2759 ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2760 } else {
2761 xor_rdispr(code, opts->gen.context_reg, zr_off(Z80_B), opts->gen.scratch1, SZ_B);
2762 }
2763 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
2764 break;
2765 case Z80_OTDR: {
2766 cycles(&opts->gen, num_cycles + 1);//T States: 4, 5
2767 //read from (HL)
2768 zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
2769 call(code, opts->read_8);//T states 3
2770 //undocumented N flag behavior
2771 //flag set on bit 7 of value written
2772 bt_ir(code, 7, opts->gen.scratch1, SZ_B);
2773 setcc_rdisp(code, CC_NC, opts->gen.context_reg, zf_off(ZF_N));
2774 //write to IO (C)
2775 zreg_to_native(opts, Z80_C, opts->gen.scratch2);
2776 call(code, opts->write_io);//T states 4
2777 //increment HL
2778 if (opts->regs[Z80_HL] >= 0) {
2779 sub_ir(code, 1, opts->regs[Z80_HL], SZ_W);
2780 add_rr(code, opts->regs[Z80_L], opts->gen.scratch1, SZ_B);
2781 } else {
2782 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_B);
2783 add_rdispr(code, opts->gen.context_reg, zr_off(Z80_L), opts->gen.scratch1, SZ_B);
2784 }
2785 //undocumented C and H flag behavior
2786 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
2787 setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
2788 //decrement B
2789 if (opts->regs[Z80_B] >= 0) {
2790 sub_ir(code, 1, opts->regs[Z80_B], SZ_B);
2791 } else {
2792 sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2793 }
2794 //undocumented Z and S flag behavior, set based on decrement of B
2795 setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
2796 setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
2797 //crazy undocumented P/V flag behavior
2798 and_ir(code, 7, opts->gen.scratch1, SZ_B);
2799 if (opts->regs[Z80_B] >= 0) {
2800 //deal with silly x86-64 restrictions on *H registers
2801 ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2802 xor_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
2803 ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2804 } else {
2805 xor_rdispr(code, opts->gen.context_reg, zr_off(Z80_B), opts->gen.scratch1, SZ_B);
2806 }
2807 setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
2808 if (opts->regs[Z80_B] >= 0) {
2809 cmp_ir(code, 0, opts->regs[Z80_B], SZ_B);
2810 } else {
2811 cmp_irdisp(code, 0, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2812 }
2813 code_ptr done = code->cur+1;
2814 jcc(code, CC_Z, code->cur+2);
2815 cycles(&opts->gen, 5);
2816 jmp(code, start);
2817 *done = code->cur - (done + 1);
2818 break;
2819 }
2820 default: {
2821 char disbuf[80];
2822 z80_disasm(inst, disbuf, address);
2823 FILE * f = fopen("zram.bin", "wb");
2824 fwrite(context->mem_pointers[0], 1, 8 * 1024, f);
2825 fclose(f);
2826 fatal_error("unimplemented Z80 instruction: %s at %X\nZ80 RAM has been saved to zram.bin for debugging", disbuf, address);
2827 }
2828 }
2829}
2830
2831uint8_t * z80_interp_handler(uint8_t opcode, z80_context * context)
2832{
2833 if (!context->interp_code[opcode]) {
2834 if (opcode == 0xCB || (opcode >= 0xDD && (opcode & 0xF) == 0xD)) {
2835 fatal_error("Encountered prefix byte %X at address %X. Z80 interpeter doesn't support those yet.", opcode, context->pc);
2836 }
2837 uint8_t codebuf[8];
2838 memset(codebuf, 0, sizeof(codebuf));
2839 codebuf[0] = opcode;
2840 z80inst inst;
2841 uint8_t * after = z80_decode(codebuf, &inst);
2842 if (after - codebuf > 1) {
2843 fatal_error("Encountered multi-byte Z80 instruction at %X. Z80 interpeter doesn't support those yet.", context->pc);
2844 }
2845
2846 z80_options * opts = context->options;
2847 code_info *code = &opts->gen.code;
2848 check_alloc_code(code, ZMAX_NATIVE_SIZE);
2849 context->interp_code[opcode] = code->cur;
2850 translate_z80inst(&inst, context, 0, 1);
2851 mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, pc), opts->gen.scratch1, SZ_W);
2852 add_ir(code, after - codebuf, opts->gen.scratch1, SZ_W);
2853 call(code, opts->native_addr);
2854 jmp_r(code, opts->gen.scratch1);
2855 z80_handle_deferred(context);
2856 }
2857 return context->interp_code[opcode];
2858}
2859
2860code_info z80_make_interp_stub(z80_context * context, uint16_t address)
2861{
2862 z80_options *opts = context->options;
2863 code_info * code = &opts->gen.code;
2864 check_alloc_code(code, 32);
2865 code_info stub = {code->cur, NULL};
2866 //TODO: make this play well with the breakpoint code
2867 mov_ir(code, address, opts->gen.scratch1, SZ_W);
2868 call(code, opts->read_8);
2869 //opcode fetch M-cycles have one extra T-state
2870 cycles(&opts->gen, 1);
2871 //TODO: increment R
2872 check_cycles_int(&opts->gen, address);
2873 call(code, opts->gen.save_context);
2874 mov_irdisp(code, address, opts->gen.context_reg, offsetof(z80_context, pc), SZ_W);
2875 push_r(code, opts->gen.context_reg);
2876 call_args(code, (code_ptr)z80_interp_handler, 2, opts->gen.scratch1, opts->gen.context_reg);
2877 mov_rr(code, RAX, opts->gen.scratch1, SZ_PTR);
2878 pop_r(code, opts->gen.context_reg);
2879 call(code, opts->gen.load_context);
2880 jmp_r(code, opts->gen.scratch1);
2881 stub.last = code->cur;
2882 return stub;
2883}
2884
2885
2886uint8_t * z80_get_native_address(z80_context * context, uint32_t address)
2887{
2888 z80_options *opts = context->options;
2889 native_map_slot * native_code_map = opts->gen.native_code_map;
2890
2891 memmap_chunk const *mem_chunk = find_map_chunk(address, &opts->gen, 0, NULL);
2892 if (mem_chunk) {
2893 //calculate the lowest alias for this address
2894 address = mem_chunk->start + ((address - mem_chunk->start) & mem_chunk->mask);
2895 }
2896 uint32_t chunk = address / NATIVE_CHUNK_SIZE;
2897 if (!native_code_map[chunk].base) {
2898 return NULL;
2899 }
2900 uint32_t offset = address % NATIVE_CHUNK_SIZE;
2901 if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET || native_code_map[chunk].offsets[offset] == EXTENSION_WORD) {
2902 return NULL;
2903 }
2904 return native_code_map[chunk].base + native_code_map[chunk].offsets[offset];
2905}
2906
2907uint8_t z80_get_native_inst_size(z80_options * opts, uint32_t address)
2908{
2909 uint32_t meta_off;
2910 memmap_chunk const *chunk = find_map_chunk(address, &opts->gen, MMAP_CODE, &meta_off);
2911 if (chunk) {
2912 meta_off += (address - chunk->start) & chunk->mask;
2913 }
2914 uint32_t slot = meta_off/1024;
2915 return opts->gen.ram_inst_sizes[slot][meta_off%1024];
2916}
2917
2918void z80_map_native_address(z80_context * context, uint32_t address, uint8_t * native_address, uint8_t size, uint8_t native_size)
2919{
2920 z80_options * opts = context->options;
2921 uint32_t meta_off;
2922 memmap_chunk const *mem_chunk = find_map_chunk(address, &opts->gen, MMAP_CODE, &meta_off);
2923 if (mem_chunk) {
2924 if (mem_chunk->flags & MMAP_CODE) {
2925 uint32_t masked = (address & mem_chunk->mask);
2926 uint32_t final_off = masked + meta_off;
2927 uint32_t ram_flags_off = final_off >> (opts->gen.ram_flags_shift + 3);
2928 context->ram_code_flags[ram_flags_off] |= 1 << ((final_off >> opts->gen.ram_flags_shift) & 7);
2929
2930 uint32_t slot = final_off / 1024;
2931 if (!opts->gen.ram_inst_sizes[slot]) {
2932 opts->gen.ram_inst_sizes[slot] = malloc(sizeof(uint8_t) * 1024);
2933 }
2934 opts->gen.ram_inst_sizes[slot][final_off % 1024] = native_size;
2935
2936 //TODO: Deal with case in which end of instruction is in a different memory chunk
2937 masked = (address + size - 1) & mem_chunk->mask;
2938 final_off = masked + meta_off;
2939 ram_flags_off = final_off >> (opts->gen.ram_flags_shift + 3);
2940 context->ram_code_flags[ram_flags_off] |= 1 << ((final_off >> opts->gen.ram_flags_shift) & 7);
2941 }
2942 //calculate the lowest alias for this address
2943 address = mem_chunk->start + ((address - mem_chunk->start) & mem_chunk->mask);
2944 } else {
2945 address &= opts->gen.address_mask;
2946 }
2947
2948 native_map_slot *map = opts->gen.native_code_map + address / NATIVE_CHUNK_SIZE;
2949 if (!map->base) {
2950 map->base = native_address;
2951 map->offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE);
2952 memset(map->offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE);
2953 }
2954 map->offsets[address % NATIVE_CHUNK_SIZE] = native_address - map->base;
2955 for(--size, address++; size; --size, address++) {
2956 address &= opts->gen.address_mask;
2957 map = opts->gen.native_code_map + address / NATIVE_CHUNK_SIZE;
2958 if (!map->base) {
2959 map->base = native_address;
2960 map->offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE);
2961 memset(map->offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE);
2962 }
2963
2964 if (map->offsets[address % NATIVE_CHUNK_SIZE] == INVALID_OFFSET) {
2965 //TODO: better handling of potentially overlapping instructions
2966 map->offsets[address % NATIVE_CHUNK_SIZE] = EXTENSION_WORD;
2967 }
2968 }
2969}
2970
2971#define INVALID_INSTRUCTION_START 0xFEEDFEED
2972
2973uint32_t z80_get_instruction_start(z80_context *context, uint32_t address)
2974{
2975 z80_options *opts = context->options;
2976 native_map_slot * native_code_map = opts->gen.native_code_map;
2977 memmap_chunk const *mem_chunk = find_map_chunk(address, &opts->gen, 0, NULL);
2978 if (mem_chunk) {
2979 //calculate the lowest alias for this address
2980 address = mem_chunk->start + ((address - mem_chunk->start) & mem_chunk->mask);
2981 }
2982
2983 uint32_t chunk = address / NATIVE_CHUNK_SIZE;
2984 if (!native_code_map[chunk].base) {
2985 return INVALID_INSTRUCTION_START;
2986 }
2987 uint32_t offset = address % NATIVE_CHUNK_SIZE;
2988 if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET) {
2989 return INVALID_INSTRUCTION_START;
2990 }
2991 while (native_code_map[chunk].offsets[offset] == EXTENSION_WORD)
2992 {
2993 --address;
2994 chunk = address / NATIVE_CHUNK_SIZE;
2995 offset = address % NATIVE_CHUNK_SIZE;
2996 }
2997 return address;
2998}
2999
3000//Technically unbounded due to redundant prefixes, but this is the max useful size
3001#define Z80_MAX_INST_SIZE 4
3002
3003z80_context * z80_handle_code_write(uint32_t address, z80_context * context)
3004{
3005 uint32_t inst_start = z80_get_instruction_start(context, address);
3006 while (inst_start != INVALID_INSTRUCTION_START && (address - inst_start) < Z80_MAX_INST_SIZE) {
3007 code_ptr dst = z80_get_native_address(context, inst_start);
3008 code_info code = {dst, dst+32, 0};
3009 z80_options * opts = context->options;
3010 dprintf("patching code at %p for Z80 instruction at %X due to write to %X\n", code.cur, inst_start, address);
3011 mov_ir(&code, inst_start, opts->gen.scratch1, SZ_D);
3012 call(&code, opts->retrans_stub);
3013 inst_start = z80_get_instruction_start(context, inst_start - 1);
3014 }
3015 return context;
3016}
3017
3018void z80_invalidate_code_range(z80_context *context, uint32_t start, uint32_t end)
3019{
3020 z80_options *opts = context->options;
3021 native_map_slot * native_code_map = opts->gen.native_code_map;
3022 memmap_chunk const *mem_chunk = find_map_chunk(start, &opts->gen, 0, NULL);
3023 if (mem_chunk) {
3024 //calculate the lowest alias for this address
3025 start = mem_chunk->start + ((start - mem_chunk->start) & mem_chunk->mask);
3026 }
3027 mem_chunk = find_map_chunk(end, &opts->gen, 0, NULL);
3028 if (mem_chunk) {
3029 //calculate the lowest alias for this address
3030 end = mem_chunk->start + ((end - mem_chunk->start) & mem_chunk->mask);
3031 }
3032 uint32_t start_chunk = start / NATIVE_CHUNK_SIZE, end_chunk = end / NATIVE_CHUNK_SIZE;
3033 for (uint32_t chunk = start_chunk; chunk <= end_chunk; chunk++)
3034 {
3035 if (native_code_map[chunk].base) {
3036 uint32_t start_offset = chunk == start_chunk ? start % NATIVE_CHUNK_SIZE : 0;
3037 uint32_t end_offset = chunk == end_chunk ? end % NATIVE_CHUNK_SIZE : NATIVE_CHUNK_SIZE;
3038 for (uint32_t offset = start_offset; offset < end_offset; offset++)
3039 {
3040 if (native_code_map[chunk].offsets[offset] != INVALID_OFFSET && native_code_map[chunk].offsets[offset] != EXTENSION_WORD) {
3041 code_info code;
3042 code.cur = native_code_map[chunk].base + native_code_map[chunk].offsets[offset];
3043 code.last = code.cur + 32;
3044 code.stack_off = 0;
3045 mov_ir(&code, chunk * NATIVE_CHUNK_SIZE + offset, opts->gen.scratch1, SZ_D);
3046 call(&code, opts->retrans_stub);
3047 }
3048 }
3049 }
3050 }
3051}
3052
3053uint8_t * z80_get_native_address_trans(z80_context * context, uint32_t address)
3054{
3055 uint8_t * addr = z80_get_native_address(context, address);
3056 if (!addr) {
3057 translate_z80_stream(context, address);
3058 addr = z80_get_native_address(context, address);
3059 if (!addr) {
3060 printf("Failed to translate %X to native code\n", address);
3061 }
3062 }
3063 return addr;
3064}
3065
3066void z80_handle_deferred(z80_context * context)
3067{
3068 z80_options * opts = context->options;
3069 process_deferred(&opts->gen.deferred, context, (native_addr_func)z80_get_native_address);
3070 if (opts->gen.deferred) {
3071 translate_z80_stream(context, opts->gen.deferred->address);
3072 }
3073}
3074
3075extern void * z80_retranslate_inst(uint32_t address, z80_context * context, uint8_t * orig_start) asm("z80_retranslate_inst");
3076void * z80_retranslate_inst(uint32_t address, z80_context * context, uint8_t * orig_start)
3077{
3078 char disbuf[80];
3079 z80_options * opts = context->options;
3080 uint8_t orig_size = z80_get_native_inst_size(opts, address);
3081 code_info *code = &opts->gen.code;
3082 uint8_t *after, *inst = get_native_pointer(address, (void **)context->mem_pointers, &opts->gen);
3083 z80inst instbuf;
3084 dprintf("Retranslating code at Z80 address %X, native address %p\n", address, orig_start);
3085 after = z80_decode(inst, &instbuf);
3086 #ifdef DO_DEBUG_PRINT
3087 z80_disasm(&instbuf, disbuf, address);
3088 if (instbuf.op == Z80_NOP) {
3089 printf("%X\t%s(%d)\n", address, disbuf, instbuf.immed);
3090 } else {
3091 printf("%X\t%s\n", address, disbuf);
3092 }
3093 #endif
3094 if (orig_size != ZMAX_NATIVE_SIZE) {
3095 check_alloc_code(code, ZMAX_NATIVE_SIZE);
3096 code_ptr start = code->cur;
3097 deferred_addr * orig_deferred = opts->gen.deferred;
3098 translate_z80inst(&instbuf, context, address, 0);
3099 /*
3100 if ((native_end - dst) <= orig_size) {
3101 uint8_t * native_next = z80_get_native_address(context, address + after-inst);
3102 if (native_next && ((native_next == orig_start + orig_size) || (orig_size - (native_end - dst)) > 5)) {
3103 remove_deferred_until(&opts->gen.deferred, orig_deferred);
3104 native_end = translate_z80inst(&instbuf, orig_start, context, address, 0);
3105 if (native_next == orig_start + orig_size && (native_next-native_end) < 2) {
3106 while (native_end < orig_start + orig_size) {
3107 *(native_end++) = 0x90; //NOP
3108 }
3109 } else {
3110 jmp(native_end, native_next);
3111 }
3112 z80_handle_deferred(context);
3113 return orig_start;
3114 }
3115 }*/
3116 z80_map_native_address(context, address, start, after-inst, ZMAX_NATIVE_SIZE);
3117 code_info tmp_code = {orig_start, orig_start + 16};
3118 jmp(&tmp_code, start);
3119 tmp_code = *code;
3120 code->cur = start + ZMAX_NATIVE_SIZE;
3121 if (!z80_is_terminal(&instbuf)) {
3122 jmp(&tmp_code, z80_get_native_address_trans(context, address + after-inst));
3123 }
3124 z80_handle_deferred(context);
3125 return start;
3126 } else {
3127 code_info tmp_code = *code;
3128 code->cur = orig_start;
3129 code->last = orig_start + ZMAX_NATIVE_SIZE;
3130 translate_z80inst(&instbuf, context, address, 0);
3131 code_info tmp2 = *code;
3132 *code = tmp_code;
3133 if (!z80_is_terminal(&instbuf)) {
3134
3135 jmp(&tmp2, z80_get_native_address_trans(context, address + after-inst));
3136 }
3137 z80_handle_deferred(context);
3138 return orig_start;
3139 }
3140}
3141
3142void translate_z80_stream(z80_context * context, uint32_t address)
3143{
3144 char disbuf[80];
3145 if (z80_get_native_address(context, address)) {
3146 return;
3147 }
3148 z80_options * opts = context->options;
3149 uint32_t start_address = address;
3150
3151 do
3152 {
3153 z80inst inst;
3154 dprintf("translating Z80 code at address %X\n", address);
3155 do {
3156 uint8_t * existing = z80_get_native_address(context, address);
3157 if (existing) {
3158 jmp(&opts->gen.code, existing);
3159 break;
3160 }
3161 uint8_t * encoded, *next;
3162 encoded = get_native_pointer(address, (void **)context->mem_pointers, &opts->gen);
3163 if (!encoded) {
3164 code_info stub = z80_make_interp_stub(context, address);
3165 z80_map_native_address(context, address, stub.cur, 1, stub.last - stub.cur);
3166 break;
3167 }
3168 //make sure prologue is in a contiguous chunk of code
3169 check_code_prologue(&opts->gen.code);
3170 next = z80_decode(encoded, &inst);
3171 #ifdef DO_DEBUG_PRINT
3172 z80_disasm(&inst, disbuf, address);
3173 if (inst.op == Z80_NOP) {
3174 printf("%X\t%s(%d)\n", address, disbuf, inst.immed);
3175 } else {
3176 printf("%X\t%s\n", address, disbuf);
3177 }
3178 #endif
3179 code_ptr start = opts->gen.code.cur;
3180 translate_z80inst(&inst, context, address, 0);
3181 z80_map_native_address(context, address, start, next-encoded, opts->gen.code.cur - start);
3182 address += next-encoded;
3183 address &= 0xFFFF;
3184 } while (!z80_is_terminal(&inst));
3185 process_deferred(&opts->gen.deferred, context, (native_addr_func)z80_get_native_address);
3186 if (opts->gen.deferred) {
3187 address = opts->gen.deferred->address;
3188 dprintf("defferred address: %X\n", address);
3189 }
3190 } while (opts->gen.deferred);
3191}
3192
3193void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t num_chunks, memmap_chunk const * io_chunks, uint32_t num_io_chunks, uint32_t clock_divider, uint32_t io_address_mask)
3194{
3195 memset(options, 0, sizeof(*options));
3196
3197 options->gen.memmap = chunks;
3198 options->gen.memmap_chunks = num_chunks;
3199 options->gen.address_size = SZ_W;
3200 options->gen.address_mask = 0xFFFF;
3201 options->gen.max_address = 0x10000;
3202 options->gen.bus_cycles = 3;
3203 options->gen.clock_divider = clock_divider;
3204 options->gen.mem_ptr_off = offsetof(z80_context, mem_pointers);
3205 options->gen.ram_flags_off = offsetof(z80_context, ram_code_flags);
3206 options->gen.ram_flags_shift = 7;
3207
3208 options->flags = 0;
3209#ifdef X86_64
3210 options->regs[Z80_B] = BH;
3211 options->regs[Z80_C] = RBX;
3212 options->regs[Z80_D] = CH;
3213 options->regs[Z80_E] = RCX;
3214 options->regs[Z80_H] = AH;
3215 options->regs[Z80_L] = RAX;
3216 options->regs[Z80_IXH] = DH;
3217 options->regs[Z80_IXL] = RDX;
3218 options->regs[Z80_IYH] = -1;
3219 options->regs[Z80_IYL] = R8;
3220 options->regs[Z80_I] = -1;
3221 options->regs[Z80_R] = RDI;
3222 options->regs[Z80_A] = R10;
3223 options->regs[Z80_BC] = RBX;
3224 options->regs[Z80_DE] = RCX;
3225 options->regs[Z80_HL] = RAX;
3226 options->regs[Z80_SP] = R9;
3227 options->regs[Z80_AF] = -1;
3228 options->regs[Z80_IX] = RDX;
3229 options->regs[Z80_IY] = R8;
3230
3231 options->gen.scratch1 = R13;
3232 options->gen.scratch2 = R14;
3233#else
3234 memset(options->regs, -1, sizeof(options->regs));
3235 options->regs[Z80_A] = RAX;
3236 options->regs[Z80_R] = AH;
3237 options->regs[Z80_H] = BH;
3238 options->regs[Z80_L] = RBX;
3239 options->regs[Z80_HL] = RBX;
3240
3241 options->regs[Z80_SP] = RDI;
3242
3243 options->gen.scratch1 = RCX;
3244 options->gen.scratch2 = RDX;
3245#endif
3246
3247 options->gen.context_reg = RSI;
3248 options->gen.cycles = RBP;
3249 options->gen.limit = -1;
3250
3251 options->gen.native_code_map = malloc(sizeof(native_map_slot) * NATIVE_MAP_CHUNKS);
3252 memset(options->gen.native_code_map, 0, sizeof(native_map_slot) * NATIVE_MAP_CHUNKS);
3253 options->gen.deferred = NULL;
3254 uint32_t inst_size_size = sizeof(uint8_t *) * ram_size(&options->gen) / 1024;
3255 options->gen.ram_inst_sizes = malloc(inst_size_size);
3256 memset(options->gen.ram_inst_sizes, 0, inst_size_size);
3257
3258 code_info *code = &options->gen.code;
3259 init_code_info(code);
3260
3261 options->save_context_scratch = code->cur;
3262 mov_rrdisp(code, options->gen.scratch1, options->gen.context_reg, offsetof(z80_context, scratch1), SZ_W);
3263 mov_rrdisp(code, options->gen.scratch2, options->gen.context_reg, offsetof(z80_context, scratch2), SZ_W);
3264
3265 options->gen.save_context = code->cur;
3266 for (int i = 0; i <= Z80_A; i++)
3267 {
3268 int reg;
3269 uint8_t size;
3270 if (i < Z80_I) {
3271 reg = i /2 + Z80_BC + (i > Z80_H ? 2 : 0);
3272 size = SZ_W;
3273 } else {
3274 reg = i;
3275 size = SZ_B;
3276 }
3277 if (reg == Z80_R) {
3278 and_ir(code, 0x7F, options->regs[Z80_R], SZ_B);
3279 or_rrdisp(code, options->regs[Z80_R], options->gen.context_reg, zr_off(Z80_R), SZ_B);
3280 } else if (options->regs[reg] >= 0) {
3281 mov_rrdisp(code, options->regs[reg], options->gen.context_reg, zr_off(reg), size);
3282 }
3283 if (size == SZ_W) {
3284 i++;
3285 }
3286 }
3287 if (options->regs[Z80_SP] >= 0) {
3288 mov_rrdisp(code, options->regs[Z80_SP], options->gen.context_reg, offsetof(z80_context, sp), SZ_W);
3289 }
3290 neg_r(code, options->gen.cycles, SZ_D);
3291 add_rdispr(code, options->gen.context_reg, offsetof(z80_context, target_cycle), options->gen.cycles, SZ_D);
3292 mov_rrdisp(code, options->gen.cycles, options->gen.context_reg, offsetof(z80_context, current_cycle), SZ_D);
3293 retn(code);
3294
3295 options->load_context_scratch = code->cur;
3296 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, scratch1), options->gen.scratch1, SZ_W);
3297 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, scratch2), options->gen.scratch2, SZ_W);
3298 options->gen.load_context = code->cur;
3299 for (int i = 0; i <= Z80_A; i++)
3300 {
3301 int reg;
3302 uint8_t size;
3303 if (i < Z80_I) {
3304 reg = i /2 + Z80_BC + (i > Z80_H ? 2 : 0);
3305 size = SZ_W;
3306 } else {
3307 reg = i;
3308 size = SZ_B;
3309 }
3310 if (options->regs[reg] >= 0) {
3311 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, regs) + i, options->regs[reg], size);
3312 if (reg == Z80_R) {
3313 and_irdisp(code, 0x80, options->gen.context_reg, zr_off(reg), SZ_B);
3314 }
3315 }
3316 if (size == SZ_W) {
3317 i++;
3318 }
3319 }
3320 if (options->regs[Z80_SP] >= 0) {
3321 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, sp), options->regs[Z80_SP], SZ_W);
3322 }
3323 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, target_cycle), options->gen.cycles, SZ_D);
3324 sub_rdispr(code, options->gen.context_reg, offsetof(z80_context, current_cycle), options->gen.cycles, SZ_D);
3325 retn(code);
3326
3327 options->native_addr = code->cur;
3328 call(code, options->gen.save_context);
3329 push_r(code, options->gen.context_reg);
3330 movzx_rr(code, options->gen.scratch1, options->gen.scratch1, SZ_W, SZ_D);
3331 call_args(code, (code_ptr)z80_get_native_address_trans, 2, options->gen.context_reg, options->gen.scratch1);
3332 mov_rr(code, RAX, options->gen.scratch1, SZ_PTR);
3333 pop_r(code, options->gen.context_reg);
3334 call(code, options->gen.load_context);
3335 retn(code);
3336
3337 uint32_t tmp_stack_off;
3338
3339 options->gen.handle_cycle_limit = code->cur;
3340 //calculate call/stack adjust size
3341 sub_ir(code, 16-sizeof(void *), RSP, SZ_PTR);
3342 call_noalign(code, options->gen.handle_cycle_limit);
3343 uint32_t call_adjust_size = code->cur - options->gen.handle_cycle_limit;
3344 code->cur = options->gen.handle_cycle_limit;
3345
3346 neg_r(code, options->gen.cycles, SZ_D);
3347 add_rdispr(code, options->gen.context_reg, offsetof(z80_context, target_cycle), options->gen.cycles, SZ_D);
3348 cmp_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.cycles, SZ_D);
3349 code_ptr no_sync = code->cur+1;
3350 jcc(code, CC_B, no_sync);
3351 neg_r(code, options->gen.cycles, SZ_D);
3352 add_rdispr(code, options->gen.context_reg, offsetof(z80_context, target_cycle), options->gen.cycles, SZ_D);
3353 mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, pc), SZ_W);
3354 call(code, options->save_context_scratch);
3355 tmp_stack_off = code->stack_off;
3356 pop_r(code, RAX); //return address in read/write func
3357 add_ir(code, 16-sizeof(void *), RSP, SZ_PTR);
3358 pop_r(code, RBX); //return address in translated code
3359 add_ir(code, 16-sizeof(void *), RSP, SZ_PTR);
3360 sub_ir(code, call_adjust_size, RAX, SZ_PTR); //adjust return address to point to the call + stack adjust that got us here
3361 mov_rrdisp(code, RBX, options->gen.context_reg, offsetof(z80_context, extra_pc), SZ_PTR);
3362 mov_rrind(code, RAX, options->gen.context_reg, SZ_PTR);
3363 restore_callee_save_regs(code);
3364 //return to caller of z80_run
3365 retn(code);
3366
3367 *no_sync = code->cur - (no_sync + 1);
3368 neg_r(code, options->gen.cycles, SZ_D);
3369 add_rdispr(code, options->gen.context_reg, offsetof(z80_context, target_cycle), options->gen.cycles, SZ_D);
3370 retn(code);
3371 code->stack_off = tmp_stack_off;
3372
3373 options->gen.handle_code_write = (code_ptr)z80_handle_code_write;
3374
3375 options->read_8 = gen_mem_fun(&options->gen, chunks, num_chunks, READ_8, &options->read_8_noinc);
3376 options->write_8 = gen_mem_fun(&options->gen, chunks, num_chunks, WRITE_8, &options->write_8_noinc);
3377
3378 code_ptr skip_int = code->cur;
3379 //calculate adjust size
3380 add_ir(code, 16-sizeof(void *), RSP, SZ_PTR);
3381 uint32_t adjust_size = code->cur - skip_int;
3382 code->cur = skip_int;
3383
3384 cmp_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.cycles, SZ_D);
3385 code_ptr skip_sync = code->cur + 1;
3386 jcc(code, CC_B, skip_sync);
3387 neg_r(code, options->gen.cycles, SZ_D);
3388 add_rdispr(code, options->gen.context_reg, offsetof(z80_context, target_cycle), options->gen.cycles, SZ_D);
3389 //save PC
3390 mov_rrdisp(code, options->gen.scratch1, options->gen.context_reg, offsetof(z80_context, pc), SZ_D);
3391 options->do_sync = code->cur;
3392 call(code, options->gen.save_context);
3393 tmp_stack_off = code->stack_off;
3394 //pop return address off the stack and save for resume later
3395 //pop_rind(code, options->gen.context_reg);
3396 pop_r(code, RAX);
3397 add_ir(code, adjust_size, RAX, SZ_PTR);
3398 add_ir(code, 16-sizeof(void *), RSP, SZ_PTR);
3399 mov_rrind(code, RAX, options->gen.context_reg, SZ_PTR);
3400
3401 //restore callee saved registers
3402 restore_callee_save_regs(code);
3403 //return to caller of z80_run
3404 retn(code);
3405 *skip_sync = code->cur - (skip_sync+1);
3406 neg_r(code, options->gen.cycles, SZ_D);
3407 add_rdispr(code, options->gen.context_reg, offsetof(z80_context, target_cycle), options->gen.cycles, SZ_D);
3408 retn(code);
3409 code->stack_off = tmp_stack_off;
3410
3411 options->gen.handle_cycle_limit_int = code->cur;
3412 neg_r(code, options->gen.cycles, SZ_D);
3413 add_rdispr(code, options->gen.context_reg, offsetof(z80_context, target_cycle), options->gen.cycles, SZ_D);
3414 cmp_rdispr(code, options->gen.context_reg, offsetof(z80_context, int_cycle), options->gen.cycles, SZ_D);
3415 jcc(code, CC_B, skip_int);
3416 //set limit to the cycle limit
3417 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.scratch2, SZ_D);
3418 mov_rrdisp(code, options->gen.scratch2, options->gen.context_reg, offsetof(z80_context, target_cycle), SZ_D);
3419 neg_r(code, options->gen.cycles, SZ_D);
3420 add_rr(code, options->gen.scratch2, options->gen.cycles, SZ_D);
3421 //disable interrupts
3422 cmp_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, int_is_nmi), SZ_B);
3423 code_ptr is_nmi = code->cur + 1;
3424 jcc(code, CC_NZ, is_nmi);
3425 mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff1), SZ_B);
3426 mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff2), SZ_B);
3427 cycles(&options->gen, 6); //interupt ack cycle
3428 code_ptr after_int_disable = code->cur + 1;
3429 jmp(code, after_int_disable);
3430 *is_nmi = code->cur - (is_nmi + 1);
3431 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, iff1), options->gen.scratch2, SZ_B);
3432 mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff1), SZ_B);
3433 mov_rrdisp(code, options->gen.scratch2, options->gen.context_reg, offsetof(z80_context, iff2), SZ_B);
3434 cycles(&options->gen, 5); //NMI processing cycles
3435 *after_int_disable = code->cur - (after_int_disable + 1);
3436 //save return address (in scratch1) to Z80 stack
3437 sub_ir(code, 2, options->regs[Z80_SP], SZ_W);
3438 mov_rr(code, options->regs[Z80_SP], options->gen.scratch2, SZ_W);
3439 //we need to do check_cycles and cycles outside of the write_8 call
3440 //so that the stack has the correct depth if we need to return to C
3441 //for a synchronization
3442 check_cycles(&options->gen);
3443 cycles(&options->gen, 3);
3444 //save word to write before call to write_8_noinc
3445 push_r(code, options->gen.scratch1);
3446 call(code, options->write_8_noinc);
3447 //restore word to write
3448 pop_r(code, options->gen.scratch1);
3449 //write high byte to SP+1
3450 mov_rr(code, options->regs[Z80_SP], options->gen.scratch2, SZ_W);
3451 add_ir(code, 1, options->gen.scratch2, SZ_W);
3452 shr_ir(code, 8, options->gen.scratch1, SZ_W);
3453 check_cycles(&options->gen);
3454 cycles(&options->gen, 3);
3455 call(code, options->write_8_noinc);
3456 //dispose of return address as we'll be jumping somewhere else
3457 add_ir(code, 16, RSP, SZ_PTR);
3458 cmp_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, int_is_nmi), SZ_B);
3459 is_nmi = code->cur + 1;
3460 jcc(code, CC_NZ, is_nmi);
3461 //TODO: Support interrupt mode 0, not needed for Genesis sit it seems to read $FF during intack
3462 //which is conveniently rst $38, i.e. the same thing that im 1 does
3463 //check interrupt mode
3464 cmp_irdisp(code, 2, options->gen.context_reg, offsetof(z80_context, im), SZ_B);
3465 code_ptr im2 = code->cur + 1;
3466 jcc(code, CC_Z, im2);
3467 mov_ir(code, 0x38, options->gen.scratch1, SZ_W);
3468 cycles(&options->gen, 1); //total time for mode 0/1 is 13 t-states
3469 code_ptr after_int_dest = code->cur + 1;
3470 jmp(code, after_int_dest);
3471 *im2 = code->cur - (im2 + 1);
3472 //read vector address from I << 8 | vector
3473 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, regs) + Z80_I, options->gen.scratch1, SZ_B);
3474 shl_ir(code, 8, options->gen.scratch1, SZ_W);
3475 movzx_rdispr(code, options->gen.context_reg, offsetof(z80_context, im2_vector), options->gen.scratch2, SZ_B, SZ_W);
3476 or_rr(code, options->gen.scratch2, options->gen.scratch1, SZ_W);
3477 push_r(code, options->gen.scratch1);
3478 cycles(&options->gen, 3);
3479 call(code, options->read_8_noinc);
3480 pop_r(code, options->gen.scratch2);
3481 push_r(code, options->gen.scratch1);
3482 mov_rr(code, options->gen.scratch2, options->gen.scratch1, SZ_W);
3483 add_ir(code, 1, options->gen.scratch1, SZ_W);
3484 cycles(&options->gen, 3);
3485 call(code, options->read_8_noinc);
3486 pop_r(code, options->gen.scratch2);
3487 shl_ir(code, 8, options->gen.scratch1, SZ_W);
3488 movzx_rr(code, options->gen.scratch2, options->gen.scratch2, SZ_B, SZ_W);
3489 or_rr(code, options->gen.scratch2, options->gen.scratch1, SZ_W);
3490 code_ptr after_int_dest2 = code->cur + 1;
3491 jmp(code, after_int_dest2);
3492 *is_nmi = code->cur - (is_nmi + 1);
3493 mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, int_is_nmi), SZ_B);
3494 mov_irdisp(code, CYCLE_NEVER, options->gen.context_reg, offsetof(z80_context, nmi_start), SZ_D);
3495 mov_ir(code, 0x66, options->gen.scratch1, SZ_W);
3496 *after_int_dest = code->cur - (after_int_dest + 1);
3497 *after_int_dest2 = code->cur - (after_int_dest2 + 1);
3498 call(code, options->native_addr);
3499 mov_rrind(code, options->gen.scratch1, options->gen.context_reg, SZ_PTR);
3500 tmp_stack_off = code->stack_off;
3501 restore_callee_save_regs(code);
3502 //return to caller of z80_run to sync
3503 retn(code);
3504 code->stack_off = tmp_stack_off;
3505
3506 //HACK
3507 options->gen.address_size = SZ_D;
3508 options->gen.address_mask = io_address_mask;
3509 options->gen.bus_cycles = 4;
3510 options->read_io = gen_mem_fun(&options->gen, io_chunks, num_io_chunks, READ_8, NULL);
3511 options->write_io = gen_mem_fun(&options->gen, io_chunks, num_io_chunks, WRITE_8, NULL);
3512 options->gen.address_size = SZ_W;
3513 options->gen.address_mask = 0xFFFF;
3514 options->gen.bus_cycles = 3;
3515
3516 options->read_16 = code->cur;
3517 cycles(&options->gen, 3);
3518 check_cycles(&options->gen);
3519 //TODO: figure out how to handle the extra wait state for word reads to bank area
3520 //may also need special handling to avoid too much stack depth when access is blocked
3521 push_r(code, options->gen.scratch1);
3522 call(code, options->read_8_noinc);
3523 mov_rr(code, options->gen.scratch1, options->gen.scratch2, SZ_B);
3524#ifndef X86_64
3525 //scratch 2 is a caller save register in 32-bit builds and may be clobbered by something called from the read8 fun
3526 mov_rrdisp(code, options->gen.scratch1, options->gen.context_reg, offsetof(z80_context, scratch2), SZ_B);
3527#endif
3528 pop_r(code, options->gen.scratch1);
3529 add_ir(code, 1, options->gen.scratch1, SZ_W);
3530 cycles(&options->gen, 3);
3531 check_cycles(&options->gen);
3532 call(code, options->read_8_noinc);
3533 shl_ir(code, 8, options->gen.scratch1, SZ_W);
3534#ifdef X86_64
3535 mov_rr(code, options->gen.scratch2, options->gen.scratch1, SZ_B);
3536#else
3537 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, scratch2), options->gen.scratch1, SZ_B);
3538#endif
3539 retn(code);
3540
3541 options->write_16_highfirst = code->cur;
3542 cycles(&options->gen, 3);
3543 check_cycles(&options->gen);
3544 push_r(code, options->gen.scratch2);
3545 push_r(code, options->gen.scratch1);
3546 add_ir(code, 1, options->gen.scratch2, SZ_W);
3547 shr_ir(code, 8, options->gen.scratch1, SZ_W);
3548 call(code, options->write_8_noinc);
3549 pop_r(code, options->gen.scratch1);
3550 pop_r(code, options->gen.scratch2);
3551 cycles(&options->gen, 3);
3552 check_cycles(&options->gen);
3553 //TODO: Check if we can get away with TCO here
3554 call(code, options->write_8_noinc);
3555 retn(code);
3556
3557 options->write_16_lowfirst = code->cur;
3558 cycles(&options->gen, 3);
3559 check_cycles(&options->gen);
3560 push_r(code, options->gen.scratch2);
3561 push_r(code, options->gen.scratch1);
3562 call(code, options->write_8_noinc);
3563 pop_r(code, options->gen.scratch1);
3564 pop_r(code, options->gen.scratch2);
3565 add_ir(code, 1, options->gen.scratch2, SZ_W);
3566 shr_ir(code, 8, options->gen.scratch1, SZ_W);
3567 cycles(&options->gen, 3);
3568 check_cycles(&options->gen);
3569 //TODO: Check if we can get away with TCO here
3570 call(code, options->write_8_noinc);
3571 retn(code);
3572
3573 options->retrans_stub = code->cur;
3574 tmp_stack_off = code->stack_off;
3575 //calculate size of patch
3576 mov_ir(code, 0x7FFF, options->gen.scratch1, SZ_D);
3577 code->stack_off += sizeof(void *);
3578 if (code->stack_off & 0xF) {
3579 sub_ir(code, 16 - (code->stack_off & 0xF), RSP, SZ_PTR);
3580 }
3581 call_noalign(code, options->retrans_stub);
3582 uint32_t patch_size = code->cur - options->retrans_stub;
3583 code->cur = options->retrans_stub;
3584 code->stack_off = tmp_stack_off;
3585
3586 //pop return address
3587 pop_r(code, options->gen.scratch2);
3588 add_ir(code, 16-sizeof(void*), RSP, SZ_PTR);
3589 code->stack_off = tmp_stack_off;
3590 call(code, options->gen.save_context);
3591 //adjust pointer before move and call instructions that got us here
3592 sub_ir(code, patch_size, options->gen.scratch2, SZ_PTR);
3593 push_r(code, options->gen.context_reg);
3594 call_args(code, (code_ptr)z80_retranslate_inst, 3, options->gen.scratch1, options->gen.context_reg, options->gen.scratch2);
3595 pop_r(code, options->gen.context_reg);
3596 mov_rr(code, RAX, options->gen.scratch1, SZ_PTR);
3597 call(code, options->gen.load_context);
3598 jmp_r(code, options->gen.scratch1);
3599
3600 options->run = (z80_ctx_fun)code->cur;
3601 tmp_stack_off = code->stack_off;
3602 save_callee_save_regs(code);
3603#ifdef X86_64
3604 mov_rr(code, RDI, options->gen.context_reg, SZ_PTR);
3605#else
3606 mov_rdispr(code, RSP, 5 * sizeof(int32_t), options->gen.context_reg, SZ_PTR);
3607#endif
3608 call(code, options->load_context_scratch);
3609 cmp_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, extra_pc), SZ_PTR);
3610 code_ptr no_extra = code->cur+1;
3611 jcc(code, CC_Z, no_extra);
3612 sub_ir(code, 16-sizeof(void *), RSP, SZ_PTR);
3613 push_rdisp(code, options->gen.context_reg, offsetof(z80_context, extra_pc));
3614 mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, extra_pc), SZ_PTR);
3615 *no_extra = code->cur - (no_extra + 1);
3616 jmp_rind(code, options->gen.context_reg);
3617 code->stack_off = tmp_stack_off;
3618}
3619
3620z80_context *init_z80_context(z80_options * options)
3621{
3622 size_t ctx_size = sizeof(z80_context) + ram_size(&options->gen) / (1 << options->gen.ram_flags_shift) / 8;
3623 z80_context *context = calloc(1, ctx_size);
3624 context->options = options;
3625 context->int_cycle = CYCLE_NEVER;
3626 context->int_pulse_start = CYCLE_NEVER;
3627 context->int_pulse_end = CYCLE_NEVER;
3628 context->nmi_start = CYCLE_NEVER;
3629
3630 return context;
3631}
3632
3633static void check_nmi(z80_context *context)
3634{
3635 if (context->nmi_start < context->int_cycle) {
3636 context->int_cycle = context->nmi_start;
3637 context->int_is_nmi = 1;
3638 }
3639}
3640
3641void z80_run(z80_context * context, uint32_t target_cycle)
3642{
3643 if (context->reset || context->busack) {
3644 context->current_cycle = target_cycle;
3645 } else {
3646 if (context->current_cycle < target_cycle) {
3647 //busreq is sampled at the end of an m-cycle
3648 //we can approximate that by running for a single m-cycle after a bus request
3649 context->sync_cycle = context->busreq ? context->current_cycle + 3*context->options->gen.clock_divider : target_cycle;
3650 if (!context->native_pc) {
3651 context->native_pc = z80_get_native_address_trans(context, context->pc);
3652 }
3653 while (context->current_cycle < context->sync_cycle)
3654 {
3655 if (context->next_int_pulse && (context->int_pulse_end < context->current_cycle || context->int_pulse_end == CYCLE_NEVER)) {
3656 context->next_int_pulse(context);
3657 }
3658 if (context->iff1) {
3659 context->int_cycle = context->int_pulse_start < context->int_enable_cycle ? context->int_enable_cycle : context->int_pulse_start;
3660 context->int_is_nmi = 0;
3661 } else {
3662 context->int_cycle = CYCLE_NEVER;
3663 }
3664 check_nmi(context);
3665
3666 context->target_cycle = context->sync_cycle < context->int_cycle ? context->sync_cycle : context->int_cycle;
3667 dprintf("Running Z80 from cycle %d to cycle %d. Int cycle: %d (%d - %d)\n", context->current_cycle, context->sync_cycle, context->int_cycle, context->int_pulse_start, context->int_pulse_end);
3668 context->options->run(context);
3669 dprintf("Z80 ran to cycle %d\n", context->current_cycle);
3670 }
3671 if (context->busreq) {
3672 context->busack = 1;
3673 context->current_cycle = target_cycle;
3674 }
3675 }
3676 }
3677}
3678
3679void z80_options_free(z80_options *opts)
3680{
3681 for (uint32_t address = 0; address < opts->gen.address_mask; address += NATIVE_CHUNK_SIZE)
3682 {
3683 uint32_t chunk = address / NATIVE_CHUNK_SIZE;
3684 if (opts->gen.native_code_map[chunk].base) {
3685 free(opts->gen.native_code_map[chunk].offsets);
3686 }
3687 }
3688 free(opts->gen.native_code_map);
3689 uint32_t ram_inst_slots = ram_size(&opts->gen) / 1024;
3690 for (uint32_t i = 0; i < ram_inst_slots; i++)
3691 {
3692 free(opts->gen.ram_inst_sizes[i]);
3693 }
3694 free(opts->gen.ram_inst_sizes);
3695 free(opts);
3696}
3697
3698void z80_assert_reset(z80_context * context, uint32_t cycle)
3699{
3700 z80_run(context, cycle);
3701 context->reset = 1;
3702}
3703
3704void z80_clear_reset(z80_context * context, uint32_t cycle)
3705{
3706 z80_run(context, cycle);
3707 if (context->reset) {
3708 //TODO: Handle case where reset is not asserted long enough
3709 context->im = 0;
3710 context->iff1 = context->iff2 = 0;
3711 context->native_pc = NULL;
3712 context->extra_pc = NULL;
3713 context->pc = 0;
3714 context->reset = 0;
3715 if (context->busreq) {
3716 //TODO: Figure out appropriate delay
3717 context->busack = 1;
3718 }
3719 }
3720}
3721
3722void z80_assert_busreq(z80_context * context, uint32_t cycle)
3723{
3724 z80_run(context, cycle);
3725 context->busreq = 1;
3726 //this is an imperfect aproximation since most M-cycles take less tstates than the max
3727 //and a short 3-tstate m-cycle can take an unbounded number due to wait states
3728 if (context->current_cycle - cycle > MAX_MCYCLE_LENGTH * context->options->gen.clock_divider) {
3729 context->busack = 1;
3730 }
3731}
3732
3733void z80_clear_busreq(z80_context * context, uint32_t cycle)
3734{
3735 z80_run(context, cycle);
3736 context->busreq = 0;
3737 context->busack = 0;
3738 //there appears to be at least a 1 Z80 cycle delay between busreq
3739 //being released and resumption of execution
3740 context->current_cycle += context->options->gen.clock_divider;
3741}
3742
3743uint8_t z80_get_busack(z80_context * context, uint32_t cycle)
3744{
3745 z80_run(context, cycle);
3746 return context->busack;
3747}
3748
3749void z80_assert_nmi(z80_context *context, uint32_t cycle)
3750{
3751 context->nmi_start = cycle;
3752 check_nmi(context);
3753}
3754
3755void z80_adjust_cycles(z80_context * context, uint32_t deduction)
3756{
3757 if (context->current_cycle < deduction) {
3758 fprintf(stderr, "WARNING: Deduction of %u cycles when Z80 cycle counter is only %u\n", deduction, context->current_cycle);
3759 context->current_cycle = 0;
3760 } else {
3761 context->current_cycle -= deduction;
3762 }
3763 if (context->int_enable_cycle != CYCLE_NEVER) {
3764 if (context->int_enable_cycle < deduction) {
3765 context->int_enable_cycle = 0;
3766 } else {
3767 context->int_enable_cycle -= deduction;
3768 }
3769 }
3770 if (context->int_pulse_start != CYCLE_NEVER) {
3771 if (context->int_pulse_end < deduction) {
3772 context->int_pulse_start = context->int_pulse_end = CYCLE_NEVER;
3773 } else {
3774 if (context->int_pulse_end != CYCLE_NEVER) {
3775 context->int_pulse_end -= deduction;
3776 }
3777 if (context->int_pulse_start < deduction) {
3778 context->int_pulse_start = 0;
3779 } else {
3780 context->int_pulse_start -= deduction;
3781 }
3782 }
3783 }
3784}
3785
3786uint32_t zbreakpoint_patch(z80_context * context, uint16_t address, code_ptr dst)
3787{
3788 code_info code = {
3789 dst,
3790 dst+32,
3791#ifdef X86_64
3792 8
3793#else
3794 0
3795#endif
3796 };
3797 mov_ir(&code, address, context->options->gen.scratch1, SZ_W);
3798 call(&code, context->bp_stub);
3799 return code.cur-dst;
3800}
3801
3802void zcreate_stub(z80_context * context)
3803{
3804 //FIXME: Stack offset stuff is probably broken on 32-bit
3805 z80_options * opts = context->options;
3806 code_info *code = &opts->gen.code;
3807 uint32_t start_stack_off = code->stack_off;
3808 check_code_prologue(code);
3809 context->bp_stub = code->cur;
3810
3811 //Calculate length of prologue
3812 check_cycles_int(&opts->gen, 0);
3813 int check_int_size = code->cur-context->bp_stub;
3814 code->cur = context->bp_stub;
3815
3816 //Calculate length of patch
3817 int patch_size = zbreakpoint_patch(context, 0, code->cur);
3818
3819#ifdef X86_64
3820 code->stack_off = 8;
3821#endif
3822 //Save context and call breakpoint handler
3823 call(code, opts->gen.save_context);
3824 push_r(code, opts->gen.scratch1);
3825 call_args_abi(code, context->bp_handler, 2, opts->gen.context_reg, opts->gen.scratch1);
3826 mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR);
3827 //Restore context
3828 call(code, opts->gen.load_context);
3829 pop_r(code, opts->gen.scratch1);
3830 //do prologue stuff
3831 cmp_ir(code, 1, opts->gen.cycles, SZ_D);
3832 uint8_t * jmp_off = code->cur+1;
3833 jcc(code, CC_NS, code->cur + 7);
3834 pop_r(code, opts->gen.scratch1);
3835 add_ir(code, check_int_size - patch_size, opts->gen.scratch1, SZ_PTR);
3836#ifdef X86_64
3837 sub_ir(code, 8, RSP, SZ_PTR);
3838#endif
3839 push_r(code, opts->gen.scratch1);
3840 jmp(code, opts->gen.handle_cycle_limit_int);
3841 *jmp_off = code->cur - (jmp_off+1);
3842 //jump back to body of translated instruction
3843 pop_r(code, opts->gen.scratch1);
3844 add_ir(code, check_int_size - patch_size, opts->gen.scratch1, SZ_PTR);
3845 jmp_r(code, opts->gen.scratch1);
3846 code->stack_off = start_stack_off;
3847}
3848
3849void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler)
3850{
3851 context->bp_handler = bp_handler;
3852 uint8_t bit = 1 << (address % 8);
3853 if (!(bit & context->breakpoint_flags[address / 8])) {
3854 context->breakpoint_flags[address / 8] |= bit;
3855 if (!context->bp_stub) {
3856 zcreate_stub(context);
3857 }
3858 uint8_t * native = z80_get_native_address(context, address);
3859 if (native) {
3860 zbreakpoint_patch(context, address, native);
3861 }
3862 }
3863}
3864
3865void zremove_breakpoint(z80_context * context, uint16_t address)
3866{
3867 context->breakpoint_flags[address / 8] &= ~(1 << (address % 8));
3868 uint8_t * native = z80_get_native_address(context, address);
3869 if (native) {
3870 z80_options * opts = context->options;
3871 code_info tmp_code = opts->gen.code;
3872 opts->gen.code.cur = native;
3873 opts->gen.code.last = native + 128;
3874 check_cycles_int(&opts->gen, address);
3875 opts->gen.code = tmp_code;
3876 }
3877}
3878
3879void z80_serialize(z80_context *context, serialize_buffer *buf)
3880{
3881 for (int i = 0; i <= Z80_A; i++)
3882 {
3883 save_int8(buf, context->regs[i]);
3884 }
3885 uint8_t f = context->flags[ZF_S];
3886 f <<= 1;
3887 f |= context->flags[ZF_Z] ;
3888 f <<= 2;
3889 f |= context->flags[ZF_H];
3890 f <<= 2;
3891 f |= context->flags[ZF_PV];
3892 f <<= 1;
3893 f |= context->flags[ZF_N];
3894 f <<= 1;
3895 f |= context->flags[ZF_C];
3896 f |= context->flags[ZF_XY] & 0x28;
3897 save_int8(buf, f);
3898 for (int i = 0; i <= Z80_A; i++)
3899 {
3900 save_int8(buf, context->alt_regs[i]);
3901 }
3902 f = context->alt_flags[ZF_S];
3903 f <<= 1;
3904 f |= context->alt_flags[ZF_Z] ;
3905 f <<= 2;
3906 f |= context->alt_flags[ZF_H];
3907 f <<= 2;
3908 f |= context->alt_flags[ZF_PV];
3909 f <<= 1;
3910 f |= context->alt_flags[ZF_N];
3911 f <<= 1;
3912 f |= context->alt_flags[ZF_C];
3913 f |= context->flags[ZF_XY] & 0x28;
3914 save_int8(buf, f);
3915 save_int16(buf, context->pc);
3916 save_int16(buf, context->sp);
3917 save_int8(buf, context->im);
3918 save_int8(buf, context->iff1);
3919 save_int8(buf, context->iff2);
3920 save_int8(buf, context->int_is_nmi);
3921 save_int8(buf, context->busack);
3922 save_int32(buf, context->current_cycle);
3923 save_int32(buf, context->int_cycle);
3924 save_int32(buf, context->int_enable_cycle);
3925 save_int32(buf, context->int_pulse_start);
3926 save_int32(buf, context->int_pulse_end);
3927 save_int32(buf, context->nmi_start);
3928}
3929
3930void z80_deserialize(deserialize_buffer *buf, void *vcontext)
3931{
3932 z80_context *context = vcontext;
3933 for (int i = 0; i <= Z80_A; i++)
3934 {
3935 context->regs[i] = load_int8(buf);
3936 }
3937 uint8_t f = load_int8(buf);
3938 context->flags[ZF_XY] = f & 0x28;
3939 context->flags[ZF_C] = f & 1;
3940 f >>= 1;
3941 context->flags[ZF_N] = f & 1;
3942 f >>= 1;
3943 context->flags[ZF_PV] = f & 1;
3944 f >>= 2;
3945 context->flags[ZF_H] = f & 1;
3946 f >>= 2;
3947 context->flags[ZF_Z] = f & 1;
3948 f >>= 1;
3949 context->flags[ZF_S] = f;
3950 for (int i = 0; i <= Z80_A; i++)
3951 {
3952 context->alt_regs[i] = load_int8(buf);
3953 }
3954 f = load_int8(buf);
3955 context->alt_flags[ZF_XY] = f & 0x28;
3956 context->alt_flags[ZF_C] = f & 1;
3957 f >>= 1;
3958 context->alt_flags[ZF_N] = f & 1;
3959 f >>= 1;
3960 context->alt_flags[ZF_PV] = f & 1;
3961 f >>= 2;
3962 context->alt_flags[ZF_H] = f & 1;
3963 f >>= 2;
3964 context->alt_flags[ZF_Z] = f & 1;
3965 f >>= 1;
3966 context->alt_flags[ZF_S] = f;
3967 context->pc = load_int16(buf);
3968 context->sp = load_int16(buf);
3969 context->im = load_int8(buf);
3970 context->iff1 = load_int8(buf);
3971 context->iff2 = load_int8(buf);
3972 context->int_is_nmi = load_int8(buf);
3973 context->busack = load_int8(buf);
3974 context->current_cycle = load_int32(buf);
3975 context->int_cycle = load_int32(buf);
3976 context->int_enable_cycle = load_int32(buf);
3977 context->int_pulse_start = load_int32(buf);
3978 context->int_pulse_end = load_int32(buf);
3979 context->nmi_start = load_int32(buf);
3980 context->native_pc = context->extra_pc = NULL;
3981}
3982