zymosis: some cosmetix (no real functional changes)
[zymosis.git] / src / libzymosis / zymosis.c
blob46d90689e231a9c86074feebfe5b68cf1b3a9dd3
1 /*
2 * Z80 CPU emulation engine v0.1.2.1
3 * coded by Ketmar // Invisible Vector (psyc://ketmar.no-ip.org/~ketmar)
4 * Understanding is not required. Only obedience.
6 * This program is free software. It comes without any warranty, to
7 * the extent permitted by applicable law. You can redistribute it
8 * and/or modify it under the terms of the Do What The Fuck You Want
9 * To Public License, Version 2, as published by Sam Hocevar. See
10 * http://www.wtfpl.net/txt/copying/ for more details.
12 #include <stdlib.h>
13 #include <string.h>
15 #include "zymosis.h"
17 #if defined(__GNUC__)
18 # ifndef ZYMOSIS_INLINE
19 # define ZYMOSIS_INLINE static __attribute__((always_inline)) inline
20 # endif
21 # ifndef ZYMOSIS_PURE
22 # define ZYMOSIS_PURE __attribute__((pure))
23 # endif
24 # ifndef ZYMOSIS_CONST
25 # define ZYMOSIS_CONST __attribute__((const))
26 # endif
27 # ifndef ZYMOSIS_FUNC
28 # define ZYMOSIS_FUNC __attribute__((warn_unused_result))
29 # endif
30 #endif
32 #ifndef ZYMOSIS_INLINE
33 # define ZYMOSIS_INLINE static
34 #endif
35 #ifndef ZYMOSIS_PURE
36 # define ZYMOSIS_PURE
37 #endif
38 #ifndef ZYMOSIS_CONST
39 # define ZYMOSIS_CONST
40 #endif
41 #ifndef ZYMOSIS_FUNC
42 # define ZYMOSIS_FUNC
43 #endif
46 /* casting negative integer to unsigned is UB; sigh */
47 #define ZADD_WX(n,v) (uint16_t)(((v) >= 0 ? ((uint32_t)(n)+(uint32_t)(v)) : ((uint32_t)(n)-(uint32_t)(-v))))
50 /******************************************************************************/
51 /* some funny tables */
52 static int32_t tables_inited = 0;
53 static uint8_t parity_tbl[256];
54 static uint8_t sz53_tbl[256]; /* bits 3, 5 and 7 of result, Z flag */
55 static uint8_t sz53p_tbl[256]; /* bits 3, 5 and 7 of result, Z and P flags */
58 //**************************************************************************
60 // various initialisations
62 //**************************************************************************
64 // initialise internal flag tables
65 // WARNING! this is NOT thread-safe!
66 void zym_init_tables (void) {
67 if (tables_inited) return;
68 for (unsigned f = 0; f < 256; ++f) {
69 unsigned n, p;
70 sz53_tbl[f] = (f&ZYM_FLAG_S35);
71 for (n = f, p = 0; n != 0; n >>= 1) p ^= n&0x01u;
72 parity_tbl[f] = (p ? 0 : ZYM_FLAG_PV);
73 sz53p_tbl[f] = (sz53_tbl[f]|parity_tbl[f]);
75 sz53_tbl[0] |= ZYM_FLAG_Z;
76 sz53p_tbl[0] |= ZYM_FLAG_Z;
77 tables_inited = 1;
81 #if defined(__GNUC__)
82 static __attribute__((constructor)) void zym_init_tables_ctor (void) {
83 zym_init_tables();
85 #endif
88 // should be called on new instance of zym_cpu_t to clear all callbacks
89 void zym_clear_callbacks (zym_cpu_t *z80) {
90 if (!tables_inited) zym_init_tables();
91 z80->mem_read = NULL;
92 z80->mem_write = NULL;
93 z80->mem_contention = NULL;
94 z80->port_read = NULL;
95 z80->port_write = NULL;
96 z80->port_contention = NULL;
97 z80->trap_reti = NULL;
98 z80->trap_retn = NULL;
99 z80->trap_ed = NULL;
100 z80->opc_pager = NULL;
104 // clear all flags and callbacks; will reset 'z80->user' too
105 void zym_init (zym_cpu_t *z80) {
106 if (!tables_inited) zym_init_tables();
107 memset(z80, 0, sizeof(*z80));
108 // there is no guarantee that NULL is 0 in the standard (sigh)
109 zym_clear_callbacks(z80);
110 z80->user = NULL;
111 z80->next_event_tstate = -1;
115 // resets Z80 CPU
116 // seems that all regs (and memptr) should be set to 'all 1' here, but i don't care
117 void zym_reset (zym_cpu_t *z80) {
118 if (!tables_inited) zym_init_tables();
119 z80->bc.w = z80->de.w = z80->hl.w = z80->af.w = z80->sp.w = z80->ix.w = z80->iy.w = 0;
120 z80->bcx.w = z80->dex.w = z80->hlx.w = z80->afx.w = 0;
121 z80->pc = z80->prev_pc = z80->org_pc = 0;
122 z80->memptr.w = 0;
123 z80->regI = z80->regR = 0;
124 z80->iff1 = z80->iff2 = 0;
125 z80->im = 0;
126 z80->halted = 0;
127 z80->prev_was_EIDDR = 0;
128 z80->tstates = 0;
129 z80->dd = &z80->hl;
130 z80->flags_q = 0;
134 //**************************************************************************
136 // alternate register set functions
138 //**************************************************************************
140 ZYMOSIS_INLINE void zym_exx_internal (zym_cpu_t *z80) {
141 uint16_t t = z80->bc.w; z80->bc.w = z80->bcx.w; z80->bcx.w = t;
142 t = z80->de.w; z80->de.w = z80->dex.w; z80->dex.w = t;
143 t = z80->hl.w; z80->hl.w = z80->hlx.w; z80->hlx.w = t;
147 ZYMOSIS_INLINE void zym_exaf_internal (zym_cpu_t *z80) {
148 const uint16_t t = z80->af.w; z80->af.w = z80->afx.w; z80->afx.w = t;
152 // swap normal and alternate register sets (except AF/AF')
153 void zym_exx (zym_cpu_t *z80) {
154 zym_exx_internal(z80);
158 // swap normal and alternate AF
159 void zym_exaf (zym_cpu_t *z80) {
160 zym_exaf_internal(z80);
164 /******************************************************************************/
165 /* simulate contented memory access */
166 /* (tstates = tstates+contention+1)*cnt */
167 /* (zym_cpu_t *z80, uint16_t addr, int tstates, zym_memio_t mio) */
168 #define z80_contention(z80_,addr_,tstates_,mio_,mrq_) do { \
169 if ((z80_)->mem_contention != NULL) (z80_)->mem_contention((z80_), (addr_), (tstates_), (mio_), (mrq_)); else (z80_)->tstates += (tstates_); \
170 } while (0)
173 #define z80_contention_by1ts(z80_,addr_,cnt_) do { \
174 if ((z80)->mem_contention != NULL) { \
175 for (unsigned fcnt = (cnt_); fcnt--; (z80_)->mem_contention((z80_), (addr_), 1, ZYM_MEMIO_OTHER, ZYM_MREQ_NONE)) {} \
176 } else { \
177 (z80_)->tstates += (cnt_); \
179 } while (0)
182 #define z80_contention_by1ts_ir(z80_,cnt_) z80_contention_by1ts((z80_), (((uint16_t)(z80_)->regI)<<8)|((z80_)->regR), (cnt_))
183 #define z80_contention_by1ts_pc(z80_,cnt_) z80_contention_by1ts((z80_), (z80_)->pc, (cnt_))
186 /******************************************************************************/
187 ZYMOSIS_INLINE uint8_t z80_port_read (zym_cpu_t *z80, const uint16_t port) {
188 uint8_t value;
189 /* i don't really know: FUSE tester seems to do port read in-between contentions,
190 but the actual emulator code does it after all contentions are done.
191 i guess that doing it in-between is the right way.
192 note: ok, it broke floating bus emulation in ZXEmuT. oopsie!
194 if (z80->port_contention != NULL) {
195 z80->port_contention(z80, port, 1, ZYM_PORTIO_FLAG_IN|ZYM_PORTIO_FLAG_EARLY);
196 z80->port_read_tstates = z80->tstates;
197 #ifdef ZYMOSIS_FUSE_TEST
198 /* for FUSE tests, it should be here */
199 value = z80->port_read(z80, port, ZYM_PORTIO_NORMAL);
200 #endif
201 z80->port_contention(z80, port, 2, ZYM_PORTIO_FLAG_IN);
202 #ifndef ZYMOSIS_FUSE_TEST
203 /* for ZXEmuT floating bus emulation, it should be here */
204 value = z80->port_read(z80, port, ZYM_PORTIO_NORMAL);
205 #endif
206 } else {
207 z80->tstates += 3;
208 z80->port_read_tstates = z80->tstates-2;
209 value = z80->port_read(z80, port, ZYM_PORTIO_NORMAL);
211 ++z80->tstates;
212 return value;
216 ZYMOSIS_INLINE void z80_port_write (zym_cpu_t *z80, const uint16_t port, const uint8_t value) {
217 if (z80->port_contention != NULL) {
218 z80->port_contention(z80, port, 1, ZYM_PORTIO_FLAG_EARLY);
219 z80->port_write(z80, port, value, ZYM_PORTIO_NORMAL);
220 z80->port_contention(z80, port, 2, 0);
221 ++z80->tstates;
222 } else {
223 ++z80->tstates;
224 z80->port_write(z80, port, value, ZYM_PORTIO_NORMAL);
225 z80->tstates += 3;
230 /******************************************************************************/
231 #define z80_peekb_i(z80_,addr_) (z80_)->mem_read((z80_), (addr_), ZYM_MEMIO_OTHER)
232 #define z80_peekb(z80_,addr_) (z80_)->mem_read((z80_), (addr_), ZYM_MEMIO_DATA)
234 #define z80_pokeb_i(z80_,addr_,byte_) (z80_)->mem_write((z80_), (addr_), (byte_), ZYM_MEMIO_OTHER)
235 #define z80_pokeb(z80_,addr_,byte_) (z80_)->mem_write((z80_), (addr_), (byte_), ZYM_MEMIO_DATA)
238 /* t1: setting /MREQ & /RD */
239 /* t2: memory read */
240 ZYMOSIS_INLINE uint8_t z80_peekb_3ts (zym_cpu_t *z80, const uint16_t addr) {
241 z80_contention(z80, addr, 3, ZYM_MEMIO_DATA, ZYM_MREQ_READ);
242 return z80_peekb(z80, addr);
245 ZYMOSIS_INLINE uint8_t z80_peekb_3ts_args (zym_cpu_t *z80, const uint16_t addr) {
246 z80_contention(z80, addr, 3, ZYM_MEMIO_OPCARG, ZYM_MREQ_READ);
247 return z80_peekb(z80, addr);
250 ZYMOSIS_INLINE void z80_peekb_3ts_args_noread (zym_cpu_t *z80, const uint16_t addr) {
251 z80_contention(z80, addr, 3, ZYM_MEMIO_OPCARG, ZYM_MREQ_READ);
254 ZYMOSIS_INLINE uint16_t z80_peekw_6ts (zym_cpu_t *z80, const uint16_t addr) {
255 const uint16_t res = z80_peekb_3ts(z80, addr);
256 return res|(((uint16_t)z80_peekb_3ts(z80, addr+1u))<<8);
259 /* t1: setting /MREQ & /WR */
260 /* t2: memory write */
261 ZYMOSIS_INLINE void z80_pokeb_3ts (zym_cpu_t *z80, const uint16_t addr, const uint8_t value) {
262 z80_contention(z80, addr, 3, ZYM_MEMIO_DATA, ZYM_MREQ_WRITE);
263 z80_pokeb(z80, addr, value);
266 ZYMOSIS_INLINE void z80_pokew_6ts (zym_cpu_t *z80, const uint16_t addr, const uint16_t value) {
267 z80_pokeb_3ts(z80, addr, value&0xffu);
268 z80_pokeb_3ts(z80, addr+1u, (value>>8)&0xffu);
271 ZYMOSIS_INLINE void z80_pokew_6ts_inverted (zym_cpu_t *z80, const uint16_t addr, const uint16_t value) {
272 z80_pokeb_3ts(z80, addr+1u, (value>>8)&0xffu);
273 z80_pokeb_3ts(z80, addr, value&0xffu);
277 ZYMOSIS_INLINE uint16_t z80_getpcw (zym_cpu_t *z80, const zym_bool wait1) {
278 uint16_t res = z80_peekb_3ts_args(z80, z80->pc);
279 ++z80->pc;
280 res |= ((uint16_t)z80_peekb_3ts_args(z80, z80->pc))<<8;
281 if (wait1) z80_contention_by1ts_pc(z80, 1);
282 ++z80->pc;
283 return res;
287 ZYMOSIS_INLINE uint16_t z80_pop_6ts (zym_cpu_t *z80) {
288 uint16_t res = z80_peekb_3ts(z80, z80->sp.w);
289 ++z80->sp.w;
290 res |= ((uint16_t)z80_peekb_3ts(z80, z80->sp.w))<<8;
291 ++z80->sp.w;
292 return res;
295 /* 3 T states write high byte of PC to the stack and decrement SP */
296 /* 3 T states write the low byte of PC and jump to #0066 */
297 ZYMOSIS_INLINE void z80_push_6ts (zym_cpu_t *z80, uint16_t value) {
298 --z80->sp.w;
299 z80_pokeb_3ts(z80, z80->sp.w, (value>>8)&0xffu);
300 --z80->sp.w;
301 z80_pokeb_3ts(z80, z80->sp.w, value&0xffu);
305 /******************************************************************************/
306 /* you are not expected to understand the following bit-mess */
307 /* the only thing you want to know that IT WORKS; just believe me and the testing suite */
308 /* ok, you can consult Z80 manuals to find the affected flags */
309 /* but believe me, it is unnecessary */
311 ZYMOSIS_INLINE void ZYM_ADC_A (zym_cpu_t *z80, const uint8_t b) {
312 const uint16_t o = z80->af.a;
313 uint16_t newv;
314 z80->af.a = (newv = o+b+(z80->af.f&ZYM_FLAG_C))&0xffu; /* ZYM_FLAG_C is 0x01u, so it's safe */
315 z80->flags_q = z80->af.f =
316 sz53_tbl[newv&0xffu]|
317 (newv > 0xffu ? ZYM_FLAG_C : 0)|
318 ((o^(~b))&(o^newv)&0x80u ? ZYM_FLAG_PV : 0)|
319 ((o&0x0fu)+(b&0x0fu)+(z80->af.f&ZYM_FLAG_C) >= 0x10u ? ZYM_FLAG_H : 0);
322 ZYMOSIS_INLINE void ZYM_SBC_A (zym_cpu_t *z80, const uint8_t b) {
323 const uint16_t o = z80->af.a;
324 uint16_t newv;
325 z80->af.a = (newv = ((uint32_t)o-(uint32_t)b-(uint32_t)(z80->af.f&ZYM_FLAG_C))&0xffffu)&0xffu; /* ZYM_FLAG_C is 0x01u, so it's safe */
326 z80->flags_q = z80->af.f =
327 ZYM_FLAG_N|
328 sz53_tbl[newv&0xffu]|
329 (newv > 0xffu ? ZYM_FLAG_C : 0)|
330 ((o^b)&(o^newv)&0x80u ? ZYM_FLAG_PV : 0)|
331 ((int32_t)(o&0x0fu)-(int32_t)(b&0x0fu)-(int32_t)(z80->af.f&ZYM_FLAG_C) < 0 ? ZYM_FLAG_H : 0);
334 ZYMOSIS_INLINE void ZYM_ADD_A (zym_cpu_t *z80, const uint8_t b) {
335 z80->af.f &= ~ZYM_FLAG_C;
336 ZYM_ADC_A(z80, b);
339 ZYMOSIS_INLINE void ZYM_SUB_A (zym_cpu_t *z80, const uint8_t b) {
340 z80->af.f &= ~ZYM_FLAG_C;
341 ZYM_SBC_A(z80, b);
344 ZYMOSIS_INLINE void ZYM_CP_A (zym_cpu_t *z80, const uint8_t b) {
345 const uint8_t o = z80->af.a;
346 const uint8_t newv = ((uint32_t)o-(uint32_t)b)&0xffu;
347 z80->flags_q = z80->af.f =
348 ZYM_FLAG_N|
349 (newv&ZYM_FLAG_S)|
350 (b&ZYM_FLAG_35)|
351 (newv == 0 ? ZYM_FLAG_Z : 0)|
352 (o < b ? ZYM_FLAG_C : 0)|
353 ((o^b)&(o^newv)&0x80u ? ZYM_FLAG_PV : 0)|
354 ((int32_t)(o&0x0fu)-(int32_t)(b&0x0fu) < 0 ? ZYM_FLAG_H : 0);
358 #define ZYM_AND_A(z80_,b_) ((z80_)->flags_q = (z80_)->af.f = sz53p_tbl[(z80_)->af.a&=(b_)]|ZYM_FLAG_H)
359 #define ZYM_OR_A(z80_,b_) ((z80_)->flags_q = (z80_)->af.f = sz53p_tbl[(z80_)->af.a|=(b_)])
360 #define ZYM_XOR_A(z80_,b_) ((z80_)->flags_q = (z80_)->af.f = sz53p_tbl[(z80_)->af.a^=(b_)])
363 /* carry unchanged */
364 ZYMOSIS_INLINE uint8_t ZYM_DEC8 (zym_cpu_t *z80, const uint8_t b) {
365 z80->af.f &= ZYM_FLAG_C;
366 z80->af.f |= ZYM_FLAG_N|
367 (b == 0x80u ? ZYM_FLAG_PV : 0)|
368 (b&0x0fu ? 0 : ZYM_FLAG_H)|
369 sz53_tbl[(((uint32_t)b)-1u)&0xffu];
370 z80->flags_q = z80->af.f;
371 return (((uint32_t)b)-1u)&0xffu;
374 /* carry unchanged */
375 ZYMOSIS_INLINE uint8_t ZYM_INC8 (zym_cpu_t *z80, const uint8_t b) {
376 z80->af.f &= ZYM_FLAG_C;
377 z80->af.f |=
378 (b == 0x7fu ? ZYM_FLAG_PV : 0)|
379 ((b+1u)&0x0fu ? 0 : ZYM_FLAG_H)|
380 sz53_tbl[(b+1u)&0xffu];
381 z80->flags_q = z80->af.f;
382 return ((b+1u)&0xffu);
385 /* cyclic, carry reflects shifted bit */
386 ZYMOSIS_INLINE void ZYM_RLCA (zym_cpu_t *z80) {
387 const uint8_t c = ((z80->af.a>>7)&0x01u);
388 z80->af.a = (z80->af.a<<1)|c;
389 z80->flags_q = z80->af.f = c|(z80->af.a&ZYM_FLAG_35)|(z80->af.f&(ZYM_FLAG_PV|ZYM_FLAG_Z|ZYM_FLAG_S));
392 /* cyclic, carry reflects shifted bit */
393 ZYMOSIS_INLINE void ZYM_RRCA (zym_cpu_t *z80) {
394 const uint8_t c = (z80->af.a&0x01u);
395 z80->af.a = (z80->af.a>>1)|(c<<7);
396 z80->flags_q = z80->af.f = c|(z80->af.a&ZYM_FLAG_35)|(z80->af.f&(ZYM_FLAG_PV|ZYM_FLAG_Z|ZYM_FLAG_S));
399 /* cyclic thru carry */
400 ZYMOSIS_INLINE void ZYM_RLA (zym_cpu_t *z80) {
401 const uint8_t c = ((z80->af.a>>7)&0x01u);
402 z80->af.a = (z80->af.a<<1)|(z80->af.f&ZYM_FLAG_C);
403 z80->flags_q = z80->af.f = c|(z80->af.a&ZYM_FLAG_35)|(z80->af.f&(ZYM_FLAG_PV|ZYM_FLAG_Z|ZYM_FLAG_S));
406 /* cyclic thru carry */
407 ZYMOSIS_INLINE void ZYM_RRA (zym_cpu_t *z80) {
408 const uint8_t c = (z80->af.a&0x01u);
409 z80->af.a = (z80->af.a>>1)|((z80->af.f&ZYM_FLAG_C)<<7);
410 z80->flags_q = z80->af.f = c|(z80->af.a&ZYM_FLAG_35)|(z80->af.f&(ZYM_FLAG_PV|ZYM_FLAG_Z|ZYM_FLAG_S));
413 /* cyclic thru carry */
414 ZYMOSIS_INLINE uint8_t ZYM_RL (zym_cpu_t *z80, uint8_t b) {
415 const uint8_t c = (b>>7)&ZYM_FLAG_C;
416 z80->flags_q = z80->af.f = sz53p_tbl[(b = ((b<<1)&0xffu)|(z80->af.f&ZYM_FLAG_C))]|c;
417 return b;
420 ZYMOSIS_INLINE uint8_t ZYM_RR (zym_cpu_t *z80, uint8_t b) {
421 const uint8_t c = (b&0x01u);
422 z80->flags_q = z80->af.f = sz53p_tbl[(b = (b>>1)|((z80->af.f&ZYM_FLAG_C)<<7))]|c;
423 return b;
426 /* cyclic, carry reflects shifted bit */
427 ZYMOSIS_INLINE uint8_t ZYM_RLC (zym_cpu_t *z80, uint8_t b) {
428 const uint8_t c = ((b>>7)&ZYM_FLAG_C);
429 z80->flags_q = z80->af.f = sz53p_tbl[(b = ((b<<1)&0xffu)|c)]|c;
430 return b;
433 /* cyclic, carry reflects shifted bit */
434 ZYMOSIS_INLINE uint8_t ZYM_RRC (zym_cpu_t *z80, uint8_t b) {
435 const uint8_t c = (b&0x01u);
436 z80->flags_q = z80->af.f = sz53p_tbl[(b = (b>>1)|(c<<7))]|c;
437 return b;
440 /* shift left arithmetic, sets bit 0 to zero, carry reflects shifted bit */
441 ZYMOSIS_INLINE uint8_t ZYM_SLA (zym_cpu_t *z80, uint8_t b) {
442 uint8_t c = ((b>>7)&0x01u);
443 z80->flags_q = z80->af.f = sz53p_tbl[(b <<= 1)]|c;
444 return b;
447 /* shift right arithmetic, sets bit 6 to bit 7, carry reflects shifted bit */
448 ZYMOSIS_INLINE uint8_t ZYM_SRA (zym_cpu_t *z80, uint8_t b) {
449 const uint8_t c = (b&0x01u);
450 z80->flags_q = z80->af.f = sz53p_tbl[(b = (b>>1)|(b&0x80u))]|c;
451 return b;
454 /* shift left logic, sets bit 0 to one, carry reflects shifted bit */
455 ZYMOSIS_INLINE uint8_t ZYM_SLL (zym_cpu_t *z80, uint8_t b) {
456 const uint8_t c = ((b>>7)&0x01u);
457 z80->flags_q = z80->af.f = sz53p_tbl[(b = (b<<1)|0x01u)]|c;
458 return b;
461 /* shift right logic, sets bit 7 to zero, carry reflects shifted bit */
462 ZYMOSIS_INLINE uint8_t ZYM_SRL (zym_cpu_t *z80, uint8_t b) {
463 const uint8_t c = (b&0x01u);
464 z80->flags_q = z80->af.f = sz53p_tbl[(b >>= 1)]|c;
465 return b;
468 /* ddvalue+value */
469 ZYMOSIS_INLINE uint16_t ZYM_ADD_DD (zym_cpu_t *z80, const uint16_t value, const uint16_t ddvalue) {
470 /* `static` is more restrective here, simple `const` should generate better code */
471 /*static*/ const uint8_t hct[8] = { 0, ZYM_FLAG_H, ZYM_FLAG_H, ZYM_FLAG_H, 0, 0, 0, ZYM_FLAG_H };
472 const uint32_t res = (uint32_t)value+(uint32_t)ddvalue;
473 const uint8_t b = ((value&0x0800u)>>11)|((ddvalue&0x0800u)>>10)|((res&0x0800u)>>9);
474 z80->memptr.w = ddvalue+1u;
475 z80->flags_q = z80->af.f =
476 (z80->af.f&(ZYM_FLAG_PV|ZYM_FLAG_Z|ZYM_FLAG_S))|
477 (res > 0xffffu ? ZYM_FLAG_C : 0)|
478 ((res>>8)&ZYM_FLAG_35)|
479 hct[b];
480 return res;
483 /* ddvalue+value */
484 ZYMOSIS_INLINE uint16_t ZYM_ADC_DD (zym_cpu_t *z80, const uint16_t value, const uint16_t ddvalue) {
485 const uint8_t c = (z80->af.f&ZYM_FLAG_C);
486 const uint32_t newv = (uint32_t)value+(uint32_t)ddvalue+(uint32_t)c;
487 const uint16_t res = (uint16_t)newv;
488 z80->memptr.w = ddvalue+1u;
489 z80->flags_q = z80->af.f =
490 ((res>>8)&ZYM_FLAG_S35)|
491 (res == 0 ? ZYM_FLAG_Z : 0)|
492 (newv > 0xffffu ? ZYM_FLAG_C : 0)|
493 ((value^((~ddvalue)&0xffffu))&(value^newv)&0x8000u ? ZYM_FLAG_PV : 0)|
494 ((value&0x0fffu)+(ddvalue&0x0fffu)+c >= 0x1000u ? ZYM_FLAG_H : 0);
495 return res;
498 /* ddvalue-value */
499 ZYMOSIS_INLINE uint16_t ZYM_SBC_DD (zym_cpu_t *z80, const uint16_t value, const uint16_t ddvalue) {
500 const uint8_t tmpB = z80->af.a;
501 //FIXME: MEMPTR docs says that it is still +1 here; why?
502 //FIXME: is this a typo, or is it really working like this?
503 z80->memptr.w = ddvalue+1u;
504 z80->af.a = ddvalue&0xffu;
505 ZYM_SBC_A(z80, value&0xffu);
506 uint16_t res = z80->af.a;
507 z80->af.a = (ddvalue>>8)&0xffu;
508 ZYM_SBC_A(z80, (value>>8)&0xffu);
509 res |= (z80->af.a<<8);
510 z80->af.a = tmpB;
511 z80->flags_q = z80->af.f = (res ? z80->af.f&(~ZYM_FLAG_Z) : z80->af.f|ZYM_FLAG_Z);
512 return res;
515 ZYMOSIS_INLINE void ZYM_BIT (zym_cpu_t *z80, const uint8_t bit, const uint8_t num, const zym_bool mptr) {
516 z80->af.f =
517 ZYM_FLAG_H|
518 (z80->af.f&ZYM_FLAG_C)|
519 (num&ZYM_FLAG_35)|
520 (num&(1<<bit) ? 0 : ZYM_FLAG_PV|ZYM_FLAG_Z)|
521 (bit == 7 ? num&ZYM_FLAG_S : 0);
522 if (mptr) z80->af.f = (z80->af.f&~ZYM_FLAG_35)|(z80->memptr.h&ZYM_FLAG_35);
523 z80->flags_q = z80->af.f;
526 /* we can do this with table lookup, but why bother? */
527 ZYMOSIS_INLINE void ZYM_DAA (zym_cpu_t *z80) {
528 uint8_t tmpI = 0, tmpC = (z80->af.f&ZYM_FLAG_C), tmpA = z80->af.a;
529 if ((z80->af.f&ZYM_FLAG_H) || (tmpA&0x0fu) > 9) tmpI = 6;
530 if (tmpC != 0 || tmpA > 0x99u) tmpI |= 0x60u;
531 if (tmpA > 0x99u) tmpC = ZYM_FLAG_C;
532 if (z80->af.f&ZYM_FLAG_N) ZYM_SUB_A(z80, tmpI); else ZYM_ADD_A(z80, tmpI);
533 z80->flags_q = z80->af.f = (z80->af.f&~(ZYM_FLAG_C|ZYM_FLAG_PV))|tmpC|parity_tbl[z80->af.a];
536 ZYMOSIS_INLINE void ZYM_RRD_A (zym_cpu_t *z80) {
537 const uint8_t tmpB = z80_peekb_3ts(z80, z80->hl.w);
538 /*IOP(4)*/
539 z80->memptr.w = z80->hl.w+1u;
540 z80_contention_by1ts(z80, z80->hl.w, 4);
541 z80_pokeb_3ts(z80, z80->hl.w, (z80->af.a<<4)|(tmpB>>4));
542 z80->af.a = (z80->af.a&0xf0u)|(tmpB&0x0fu);
543 z80->flags_q = z80->af.f = (z80->af.f&ZYM_FLAG_C)|sz53p_tbl[z80->af.a];
546 ZYMOSIS_INLINE void ZYM_RLD_A (zym_cpu_t *z80) {
547 const uint8_t tmpB = z80_peekb_3ts(z80, z80->hl.w);
548 /*IOP(4)*/
549 z80->memptr.w = z80->hl.w+1u;
550 z80_contention_by1ts(z80, z80->hl.w, 4);
551 z80_pokeb_3ts(z80, z80->hl.w, (tmpB<<4)|(z80->af.a&0x0fu));
552 z80->af.a = (z80->af.a&0xf0u)|(tmpB>>4);
553 z80->flags_q = z80->af.f = (z80->af.f&ZYM_FLAG_C)|sz53p_tbl[z80->af.a];
556 ZYMOSIS_INLINE void ZYM_LD_A_IR (zym_cpu_t *z80, const uint8_t ir) {
557 z80->af.a = ir;
558 z80->prev_was_EIDDR = -1;
559 z80_contention_by1ts_ir(z80, 1);
560 z80->flags_q = z80->af.f = sz53_tbl[z80->af.a]|(z80->af.f&ZYM_FLAG_C)|(z80->iff2 ? ZYM_FLAG_PV : 0);
564 /******************************************************************************/
565 #define INC_R (z80->regR = ((z80->regR+1u)&0x7fu)|(z80->regR&0x80u))
566 #define DEC_R (z80->regR = ((z80->regR-1u)&0x7fu)|(z80->regR&0x80u))
568 /* reference code:
569 #define SET_TRUE_CC() do { \
570 switch ((opcode>>3)&0x07u) { \
571 case 0: trueCC = (z80->af.f&ZYM_FLAG_Z) == 0; break; \
572 case 1: trueCC = (z80->af.f&ZYM_FLAG_Z) != 0; break; \
573 case 2: trueCC = (z80->af.f&ZYM_FLAG_C) == 0; break; \
574 case 3: trueCC = (z80->af.f&ZYM_FLAG_C) != 0; break; \
575 case 4: trueCC = (z80->af.f&ZYM_FLAG_PV) == 0; break; \
576 case 5: trueCC = (z80->af.f&ZYM_FLAG_PV) != 0; break; \
577 case 6: trueCC = (z80->af.f&ZYM_FLAG_S) == 0; break; \
578 case 7: trueCC = (z80->af.f&ZYM_FLAG_S) != 0; break; \
580 } while (0)
583 /* branch-less (assuming that `!` is branch-less) code */
584 static const uint8_t ccmask[4] = {
585 ZYM_FLAG_Z,
586 ZYM_FLAG_C,
587 ZYM_FLAG_PV,
588 ZYM_FLAG_S,
590 #define SET_TRUE_CC() trueCC = ((!(z80->af.f&ccmask[(opcode>>4)&0x03u]))^((opcode>>3)&0x01u))
593 /* read opcode after prefix */
594 /*FIXME: this should call a pager too, but meh...*/
595 ZYMOSIS_INLINE uint8_t zym_get_opcode_ext (zym_cpu_t *z80) {
596 z80_contention(z80, z80->pc, 4, ZYM_MEMIO_OPCEXT, ZYM_MREQ_READ);
597 const uint8_t opc = z80->mem_read(z80, z80->pc, ZYM_MEMIO_OPCEXT);
598 if (z80->evenM1 && (z80->tstates&0x01)) ++z80->tstates; /* emulate "even M1" if necessary */
599 ++z80->pc;
600 INC_R;
601 return opc;
605 #define CBX_REPEATED (opcode&0x10u)
606 #define CBX_BACKWARD (opcode&0x08u)
609 int32_t zym_exec_ex (zym_cpu_t *z80, int32_t tscount) {
610 uint8_t opcode;
611 zym_bool gotDD, trueCC;
612 int32_t disp;
613 int32_t tsts; // trap tstates
614 int32_t tstart = z80->tstates;
615 uint8_t tmpB, tmpC, rsrc, rdst;
616 uint16_t tmpW = 0; /* shut up the compiler; it's wrong but stubborn */
617 /* main loop */
618 while ((z80->next_event_tstate < 0 || z80->tstates < z80->next_event_tstate) &&
619 (tscount < 0 || z80->tstates-tstart <= tscount))
621 /* note that real Z80 process prefixes by setting internal flags, blocking /INT
622 for the next opc read, and reading the next opcode.
623 we cannot do that, because for us prefixed instructions are not "flagged".
624 this doesn't matter in practice for anything except double IX/IY prefixes.
625 currently, we're doing a weird hack for such prefixes (rolling back).
626 double prefixes aren't used in any real code, tho, so this doesn't matter much.
628 z80->prev_pc = z80->org_pc;
629 tsts = z80->tstates; /* rememeber to compensate trap cost */
630 /* we should perform opcode fetching in loop, in case we need to
631 refetch the opcode, or rollback on breakpoint
633 for (;;) {
634 z80->refetch = 0;
635 if (z80->bp_hit) { z80->bp_was_hit = 1; z80->bp_hit = 0; return z80->tstates-tstart; }
636 z80->org_pc = z80->pc; /* for callbacks */
637 const int32_t ots = z80->tstates;
638 /* call pager callback */
639 if (z80->opc_pager != NULL) {
640 if (z80->opc_pager(z80)) return z80->tstates-tstart;
642 /* read opcode -- OCR(4) */
643 /* t1: setting /MREQ & /RD */
644 /* t2: memory read */
645 /* t3, t4: decode command, increment R */
646 z80_contention(z80, z80->pc, 4, ZYM_MEMIO_OPCODE, ZYM_MREQ_READ);
647 /* emulate "even M1" if necessary */
648 if (z80->evenM1 && (z80->tstates&0x01)) ++z80->tstates;
649 /* read opcode */
650 opcode = z80->mem_read(z80, z80->pc, ZYM_MEMIO_OPCODE);
651 /* do we need to perform a rollback? */
652 if (!(z80->bp_hit|z80->refetch)) {
653 z80->org_pc = z80->pc++; /* for more callbacks ;-) */
654 INC_R;
655 break;
657 /* rollback tstates */
658 z80->tstates = ots;
660 /* previous Q for SCF/CCF */
661 const uint8_t lastq = z80->flags_q;
662 z80->flags_q = 0;
663 z80->prev_was_EIDDR = 0;
664 disp = gotDD = 0;
665 z80->dd = &z80->hl;
666 /* "HALT" simply executes "NOP" until interrupted */
667 /* check: i'm not sure if it really performs opcode reading */
668 if (z80->halted) { --z80->pc; continue; }
669 /* check for I[XY] prefix */
670 if (opcode == 0xddu || opcode == 0xfdu) {
671 /* this is 256-bit bitmap indicates if the corresponding base opcode is using `(HL)` */
672 /* `static` is more restrictive here, simple `const` should generate better code */
673 /*static*/ const uint32_t withIndexBmp[8] = {
674 0x00u,0x700000u,0x40404040u,0x40bf4040u,0x40404040u,0x40404040u,0x0800u,0x00u
676 /* IX/IY prefix */
677 z80->dd = (opcode == 0xddu ? &z80->ix : &z80->iy);
678 /* we may need to rollback on double prefix */
679 const int32_t ots = z80->tstates;
680 /* read opcode -- OCR(4) */
681 opcode = zym_get_opcode_ext(z80);
682 /* test if this instruction have (HL) */
683 if (withIndexBmp[opcode>>5]&(1u<<(opcode&0x1fu))) {
684 /* 3rd byte is always DISP here */
685 disp = z80_peekb_3ts_args(z80, z80->pc); if (disp > 127) disp -= 256;
686 ++z80->pc;
687 z80->memptr.w = ZADD_WX(z80->dd->w, disp);
688 } else if (opcode == 0xddu || opcode == 0xfdu) {
689 /* rollback; this is not how real Z80 works, but meh... */
690 /* read second prefix again */
691 --z80->pc;
692 /* rollback tstates */
693 z80->tstates = ots;
694 /* rollback R register */
695 DEC_R;
696 /* double prefix works as NOP, and blocks /INT */
697 z80->prev_was_EIDDR = 1;
698 /*FIXME: logically this should reset our Q value, but i am not sure; anyway, this works*/
699 z80->flags_q = 0;
700 /* restart main loop */
701 continue;
703 gotDD = 1;
705 /* ED-prefixed instructions */
706 if (opcode == 0xedu) {
707 z80->dd = &z80->hl; /* ED-prefixed opcodes cannot use IX/IY */
708 /* read opcode -- OCR(4) */
709 opcode = zym_get_opcode_ext(z80);
710 switch (opcode) {
711 /* LDI, LDIR, LDD, LDDR */
712 case 0xa0u: case 0xb0u: case 0xa8u: case 0xb8u:
713 tmpB = z80_peekb_3ts(z80, z80->hl.w);
714 z80_pokeb_3ts(z80, z80->de.w, tmpB);
715 /*MWR(5)*/
716 z80_contention_by1ts(z80, z80->de.w, 2);
717 --z80->bc.w;
718 tmpB = (tmpB+z80->af.a)&0xffu;
719 z80->flags_q = z80->af.f = /* BOO! FEAR THE MIGHTY BITS! */
720 (tmpB&ZYM_FLAG_3)|(z80->af.f&(ZYM_FLAG_C|ZYM_FLAG_Z|ZYM_FLAG_S))|
721 (z80->bc.w != 0 ? ZYM_FLAG_PV : 0)|
722 (tmpB&0x02u ? ZYM_FLAG_5 : 0);
723 if (CBX_REPEATED) {
724 if (z80->bc.w != 0) {
725 /*IOP(5)*/
726 z80_contention_by1ts(z80, z80->de.w, 5);
727 /* do it again */
728 z80->pc -= 2;
729 z80->memptr.w = z80->pc+1u;
732 if (!CBX_BACKWARD) { ++z80->hl.w; ++z80->de.w; } else { --z80->hl.w; --z80->de.w; }
733 break;
734 /* CPI, CPIR, CPD, CPDR */
735 case 0xa1u: case 0xb1u: case 0xa9u: case 0xb9u:
736 tmpB = z80_peekb_3ts(z80, z80->hl.w);
737 /*IOP(5)*/
738 z80_contention_by1ts(z80, z80->hl.w, 5);
739 --z80->bc.w;
740 z80->af.f = /* BOO! FEAR THE MIGHTY BITS! */
741 ZYM_FLAG_N|
742 (z80->af.f&ZYM_FLAG_C)|
743 (z80->bc.w != 0 ? ZYM_FLAG_PV : 0)|
744 ((int32_t)(z80->af.a&0x0fu)-(int32_t)(tmpB&0x0fu) < 0 ? ZYM_FLAG_H : 0);
745 tmpB = ((uint32_t)z80->af.a-(uint32_t)tmpB)&0xffu;
746 z80->af.f |= (tmpB == 0 ? ZYM_FLAG_Z : 0)|(tmpB&ZYM_FLAG_S);
747 if (z80->af.f&ZYM_FLAG_H) tmpB = ((uint16_t)tmpB-1u)&0xffu;
748 z80->af.f |= (tmpB&ZYM_FLAG_3)|(tmpB&0x02u ? ZYM_FLAG_5 : 0);
749 z80->flags_q = z80->af.f;
750 if (CBX_REPEATED) {
751 /* repeated */
752 if ((z80->af.f&(ZYM_FLAG_Z|ZYM_FLAG_PV)) == ZYM_FLAG_PV) {
753 /*IOP(5)*/
754 z80_contention_by1ts(z80, z80->hl.w, 5);
755 /* do it again */
756 z80->pc -= 2;
757 z80->memptr.w = z80->pc+1u;
760 if (CBX_BACKWARD) {
761 --z80->hl.w;
762 --z80->memptr.w; /* new MEMPTR code */
763 } else {
764 ++z80->hl.w;
765 ++z80->memptr.w; /* new MEMPTR code */
767 break;
768 /* OUTI, OTIR, OUTD, OTDR */
769 case 0xa3u: case 0xb3u: case 0xabu: case 0xbbu:
770 --z80->bc.b;
771 /* fallthru */
772 /* INI, INIR, IND, INDR */
773 case 0xa2u: case 0xb2u: case 0xaau: case 0xbau:
774 z80->memptr.w = z80->bc.w;
775 if (CBX_BACKWARD) --z80->memptr.w; else ++z80->memptr.w;
776 /*OCR(5)*/
777 z80_contention_by1ts_ir(z80, 1);
778 if (opcode&0x01u) {
779 /* OUT* */
780 tmpB = z80_peekb_3ts(z80, z80->hl.w);/*MRD(3)*/
781 z80_port_write(z80, z80->bc.w, tmpB);
782 tmpW = z80->hl.w;
783 if (CBX_BACKWARD) --tmpW; else ++tmpW;
784 tmpC = (tmpB+tmpW)&0xffu;
785 } else {
786 /* IN* */
787 tmpB = z80_port_read(z80, z80->bc.w);
788 z80_pokeb_3ts(z80, z80->hl.w, tmpB);/*MWR(3)*/
789 --z80->bc.b;
790 tmpC = (CBX_BACKWARD ? ((uint32_t)tmpB+(uint32_t)z80->bc.c-1u) : (tmpB+z80->bc.c+1u))&0xffu;
792 z80->flags_q = z80->af.f =
793 (tmpB&0x80u ? ZYM_FLAG_N : 0)|
794 (tmpC < tmpB ? ZYM_FLAG_H|ZYM_FLAG_C : 0)|
795 parity_tbl[(tmpC&0x07u)^z80->bc.b]|
796 sz53_tbl[z80->bc.b];
797 if (CBX_REPEATED) {
798 /* repeating commands */
799 if (z80->bc.b != 0) {
800 uint16_t a = (opcode&0x01u ? z80->bc.w : z80->hl.w);
801 /*IOP(5)*/
802 z80_contention_by1ts(z80, a, 5);
803 /* do it again */
804 z80->pc -= 2;
807 if (CBX_BACKWARD) --z80->hl.w; else ++z80->hl.w;
808 break;
809 /* not strings, but some good instructions anyway */
810 default:
811 if ((opcode&0xc0u) == 0x40u) {
812 /* 0x40...0x7f */
813 switch (opcode&0x07u) {
814 /* IN r8,(C) */
815 case 0:
816 z80->memptr.w = z80->bc.w+1u;
817 tmpB = z80_port_read(z80, z80->bc.w);
818 z80->flags_q = z80->af.f = sz53p_tbl[tmpB]|(z80->af.f&ZYM_FLAG_C);
819 switch ((opcode>>3)&0x07u) {
820 case 0: z80->bc.b = tmpB; break;
821 case 1: z80->bc.c = tmpB; break;
822 case 2: z80->de.d = tmpB; break;
823 case 3: z80->de.e = tmpB; break;
824 case 4: z80->hl.h = tmpB; break;
825 case 5: z80->hl.l = tmpB; break;
826 case 7: z80->af.a = tmpB; break;
827 /* 6 affects only flags */
829 break;
830 /* OUT (C),r8 */
831 case 1:
832 z80->memptr.w = z80->bc.w+1u;
833 switch ((opcode>>3)&0x07u) {
834 case 0: tmpB = z80->bc.b; break;
835 case 1: tmpB = z80->bc.c; break;
836 case 2: tmpB = z80->de.d; break;
837 case 3: tmpB = z80->de.e; break;
838 case 4: tmpB = z80->hl.h; break;
839 case 5: tmpB = z80->hl.l; break;
840 case 7: tmpB = z80->af.a; break;
841 /* 6 usually means (HL), but here it is 0xff for CMOS, and 0 for NMOS */
842 default: tmpB = (!z80->cmos ? 0x00u : 0xffu); break; /* `!` must tell the predictor our preferred path, NMOS */
844 z80_port_write(z80, z80->bc.w, tmpB);
845 break;
846 /* SBC HL,rr/ADC HL,rr */
847 case 2:
848 /*IOP(4),IOP(3)*/
849 z80_contention_by1ts_ir(z80, 7);
850 switch ((opcode>>4)&0x03u) {
851 case 0: tmpW = z80->bc.w; break;
852 case 1: tmpW = z80->de.w; break;
853 case 2: tmpW = z80->hl.w; break;
854 default: tmpW = z80->sp.w; break;
856 z80->hl.w = (opcode&0x08u ? ZYM_ADC_DD(z80, tmpW, z80->hl.w) : ZYM_SBC_DD(z80, tmpW, z80->hl.w));
857 break;
858 /* LD (nn),rr/LD rr,(nn) */
859 case 3:
860 tmpW = z80_getpcw(z80, 0);
861 z80->memptr.w = tmpW+1u;
862 if (opcode&0x08u) {
863 /* LD rr,(nn) */
864 switch ((opcode>>4)&0x03u) {
865 case 0: z80->bc.w = z80_peekw_6ts(z80, tmpW); break;
866 case 1: z80->de.w = z80_peekw_6ts(z80, tmpW); break;
867 case 2: z80->hl.w = z80_peekw_6ts(z80, tmpW); break;
868 case 3: z80->sp.w = z80_peekw_6ts(z80, tmpW); break;
870 } else {
871 /* LD (nn),rr */
872 switch ((opcode>>4)&0x03u) {
873 case 0: z80_pokew_6ts(z80, tmpW, z80->bc.w); break;
874 case 1: z80_pokew_6ts(z80, tmpW, z80->de.w); break;
875 case 2: z80_pokew_6ts(z80, tmpW, z80->hl.w); break;
876 case 3: z80_pokew_6ts(z80, tmpW, z80->sp.w); break;
879 break;
880 /* NEG */
881 case 4:
882 tmpB = z80->af.a;
883 z80->af.a = 0;
884 ZYM_SUB_A(z80, tmpB);
885 break;
886 /* RETI/RETN */
887 case 5:
888 /*RETI: 0x4d, 0x5d, 0x6d, 0x7d*/
889 /*RETN: 0x45, 0x55, 0x65, 0x75*/
890 z80->iff1 = z80->iff2;
891 z80->memptr.w = z80->pc = z80_pop_6ts(z80);
892 if (opcode&0x08u) {
893 /* RETI */
894 if (z80->trap_reti != NULL && z80->trap_reti(z80, opcode)) return z80->tstates-tstart;
895 } else {
896 /* RETN */
897 if (z80->trap_retn != NULL && z80->trap_retn(z80, opcode)) return z80->tstates-tstart;
899 break;
900 /* IM n */
901 case 6:
902 switch (opcode) {
903 case 0x56u: case 0x76u: z80->im = 1; break;
904 case 0x5eu: case 0x7eu: z80->im = 2; break;
905 default: z80->im = 0; break;
907 break;
908 /* specials */
909 case 7:
910 switch (opcode) {
911 /* LD I,A */
912 case 0x47u:
913 /*OCR(5)*/
914 z80_contention_by1ts_ir(z80, 1);
915 z80->regI = z80->af.a;
916 break;
917 /* LD R,A */
918 case 0x4fu:
919 /*OCR(5)*/
920 z80_contention_by1ts_ir(z80, 1);
921 z80->regR = z80->af.a;
922 break;
923 /* LD A,I */
924 case 0x57u: ZYM_LD_A_IR(z80, z80->regI); break;
925 /* LD A,R */
926 case 0x5fu: ZYM_LD_A_IR(z80, z80->regR); break;
927 /* RRD */
928 case 0x67u: ZYM_RRD_A(z80); break;
929 /* RLD */
930 case 0x6F: ZYM_RLD_A(z80); break;
933 } else {
934 /* slt and other traps */
935 if (z80->trap_ed != NULL) {
936 z80->tstates = tsts; /* compensate trap cost */
937 if (z80->trap_ed(z80, opcode)) return z80->tstates-tstart;
940 break;
942 continue;
943 } /* 0xed done */
944 /* CB-prefixed instructions */
945 if (opcode == 0xcbu) {
946 /* shifts and bit operations */
947 /* read opcode -- OCR(4) */
948 if (!gotDD) {
949 opcode = zym_get_opcode_ext(z80);
950 } else {
951 z80_contention(z80, z80->pc, 3, ZYM_MEMIO_OPCEXT, ZYM_MREQ_READ);
952 opcode = z80->mem_read(z80, z80->pc, ZYM_MEMIO_OPCEXT);
953 z80_contention_by1ts_pc(z80, 2);
954 ++z80->pc;
956 if (gotDD) {
957 tmpW = ZADD_WX(z80->dd->w, disp);
958 tmpB = z80_peekb_3ts(z80, tmpW);
959 z80_contention_by1ts(z80, tmpW, 1);
960 } else {
961 switch (opcode&0x07u) {
962 case 0: tmpB = z80->bc.b; break;
963 case 1: tmpB = z80->bc.c; break;
964 case 2: tmpB = z80->de.d; break;
965 case 3: tmpB = z80->de.e; break;
966 case 4: tmpB = z80->hl.h; break;
967 case 5: tmpB = z80->hl.l; break;
968 case 6: tmpB = z80_peekb_3ts(z80, z80->hl.w); z80_contention(z80, z80->hl.w, 1, ZYM_MEMIO_DATA, ZYM_MREQ_READ); break;
969 case 7: tmpB = z80->af.a; break;
972 switch ((opcode>>3)&0x1fu) {
973 case 0: tmpB = ZYM_RLC(z80, tmpB); break;
974 case 1: tmpB = ZYM_RRC(z80, tmpB); break;
975 case 2: tmpB = ZYM_RL(z80, tmpB); break;
976 case 3: tmpB = ZYM_RR(z80, tmpB); break;
977 case 4: tmpB = ZYM_SLA(z80, tmpB); break;
978 case 5: tmpB = ZYM_SRA(z80, tmpB); break;
979 case 6: tmpB = ZYM_SLL(z80, tmpB); break;
980 case 7: tmpB = ZYM_SRL(z80, tmpB); break;
981 default:
982 switch ((opcode>>6)&0x03u) {
983 case 1: ZYM_BIT(z80, (opcode>>3)&0x07u, tmpB, (gotDD || (opcode&0x07u) == 6)); break;
984 case 2: tmpB &= ~(1<<((opcode>>3)&0x07u)); break; /* RES */
985 case 3: tmpB |= (1<<((opcode>>3)&0x07u)); break; /* SET */
987 break;
989 if ((opcode&0xc0u) != 0x40u) {
990 /* BITs are not welcome here */
991 if (gotDD) {
992 /* tmpW was set earlier */
993 if ((opcode&0x07u) != 6) z80_pokeb_3ts(z80, tmpW, tmpB);
995 switch (opcode&0x07u) {
996 case 0: z80->bc.b = tmpB; break;
997 case 1: z80->bc.c = tmpB; break;
998 case 2: z80->de.d = tmpB; break;
999 case 3: z80->de.e = tmpB; break;
1000 case 4: z80->hl.h = tmpB; break;
1001 case 5: z80->hl.l = tmpB; break;
1002 case 6: z80_pokeb_3ts(z80, ZADD_WX(z80->dd->w, disp), tmpB); break;
1003 case 7: z80->af.a = tmpB; break;
1006 continue;
1007 } /* 0xcb done */
1008 /* normal things */
1009 switch (opcode&0xc0u) {
1010 /* 0x00..0x3F */
1011 case 0x00u:
1012 switch (opcode&0x07u) {
1013 /* misc,DJNZ,JR,JR cc */
1014 case 0:
1015 if (opcode&0x30u) {
1016 /* branches */
1017 if (opcode&0x20u) {
1018 /* JR cc */
1020 switch ((opcode>>3)&0x03u) {
1021 case 0: trueCC = (z80->af.f&ZYM_FLAG_Z) == 0; break;
1022 case 1: trueCC = (z80->af.f&ZYM_FLAG_Z) != 0; break;
1023 case 2: trueCC = (z80->af.f&ZYM_FLAG_C) == 0; break;
1024 case 3: trueCC = (z80->af.f&ZYM_FLAG_C) != 0; break;
1025 default: trueCC = 0; break;
1028 trueCC = ((!(z80->af.f&ccmask[(opcode>>4)&0x01u]))^((opcode>>3)&0x01u));
1029 } else {
1030 /* DJNZ/JR */
1031 if ((opcode&0x08u) == 0) {
1032 /* DJNZ */
1033 /*OCR(5)*/
1034 z80_contention_by1ts_ir(z80, 1);
1035 --z80->bc.b;
1036 trueCC = (z80->bc.b != 0);
1037 } else {
1038 /* JR */
1039 trueCC = 1;
1042 /* `disp` is always read, but FUSE tests require it this way; sigh */
1043 if (trueCC) {
1044 /* execute branch (relative) */
1045 disp = z80_peekb_3ts_args(z80, z80->pc);
1046 /*IOP(5)*/
1047 if (disp > 127) disp -= 256; /* convert to int8_t */
1048 z80_contention_by1ts_pc(z80, 5);
1049 ++z80->pc;
1050 z80->memptr.w = z80->pc = ZADD_WX(z80->pc, disp);
1051 } else {
1052 z80_peekb_3ts_args_noread(z80, z80->pc);
1053 ++z80->pc;
1055 } else {
1056 /* EX AF,AF' or NOP */
1057 if (opcode != 0) zym_exaf_internal(z80);
1059 break;
1060 /* LD rr,nn/ADD HL,rr */
1061 case 1:
1062 if (opcode&0x08u) {
1063 /* ADD HL,rr */
1064 /*IOP(4),IOP(3)*/
1065 z80_contention_by1ts_ir(z80, 7);
1066 switch ((opcode>>4)&0x03u) {
1067 case 0: z80->dd->w = ZYM_ADD_DD(z80, z80->bc.w, z80->dd->w); break;
1068 case 1: z80->dd->w = ZYM_ADD_DD(z80, z80->de.w, z80->dd->w); break;
1069 case 2: z80->dd->w = ZYM_ADD_DD(z80, z80->dd->w, z80->dd->w); break;
1070 case 3: z80->dd->w = ZYM_ADD_DD(z80, z80->sp.w, z80->dd->w); break;
1072 } else {
1073 /* LD rr,nn */
1074 tmpW = z80_getpcw(z80, 0);
1075 switch ((opcode>>4)&0x03u) {
1076 case 0: z80->bc.w = tmpW; break;
1077 case 1: z80->de.w = tmpW; break;
1078 case 2: z80->dd->w = tmpW; break;
1079 case 3: z80->sp.w = tmpW; break;
1082 break;
1083 /* LD xxx,xxx */
1084 case 2:
1085 switch ((opcode>>3)&0x07u) {
1086 /* LD (BC),A */
1087 case 0: z80_pokeb_3ts(z80, z80->bc.w, z80->af.a); z80->memptr.l = (z80->bc.w+1u)&0xffu; z80->memptr.h = z80->af.a; break;
1088 /* LD A,(BC) */
1089 case 1: z80->af.a = z80_peekb_3ts(z80, z80->bc.w); z80->memptr.w = z80->bc.w+1u; break;
1090 /* LD (DE),A */
1091 case 2: z80_pokeb_3ts(z80, z80->de.w, z80->af.a); z80->memptr.l = (z80->de.w+1u)&0xffu; z80->memptr.h = z80->af.a; break;
1092 /* LD A,(DE) */
1093 case 3: z80->af.a = z80_peekb_3ts(z80, z80->de.w); z80->memptr.w = z80->de.w+1u; break;
1094 /* LD (nn),HL */
1095 case 4:
1096 tmpW = z80_getpcw(z80, 0);
1097 z80->memptr.w = tmpW+1u;
1098 z80_pokew_6ts(z80, tmpW, z80->dd->w);
1099 break;
1100 /* LD HL,(nn) */
1101 case 5:
1102 tmpW = z80_getpcw(z80, 0);
1103 z80->memptr.w = tmpW+1u;
1104 z80->dd->w = z80_peekw_6ts(z80, tmpW);
1105 break;
1106 /* LD (nn),A */
1107 case 6:
1108 tmpW = z80_getpcw(z80, 0);
1109 z80->memptr.l = (tmpW+1u)&0xffu;
1110 z80->memptr.h = z80->af.a;
1111 z80_pokeb_3ts(z80, tmpW, z80->af.a);
1112 break;
1113 /* LD A,(nn) */
1114 case 7:
1115 tmpW = z80_getpcw(z80, 0);
1116 z80->memptr.w = tmpW+1u;
1117 z80->af.a = z80_peekb_3ts(z80, tmpW);
1118 break;
1120 break;
1121 /* INC rr/DEC rr */
1122 case 3:
1123 /*OCR(6)*/
1124 z80_contention_by1ts_ir(z80, 2);
1125 if (opcode&0x08u) {
1126 /*DEC*/
1127 switch ((opcode>>4)&0x03u) {
1128 case 0: --z80->bc.w; break;
1129 case 1: --z80->de.w; break;
1130 case 2: --z80->dd->w; break;
1131 case 3: --z80->sp.w; break;
1133 } else {
1134 /*INC*/
1135 switch ((opcode>>4)&0x03u) {
1136 case 0: ++z80->bc.w; break;
1137 case 1: ++z80->de.w; break;
1138 case 2: ++z80->dd->w; break;
1139 case 3: ++z80->sp.w; break;
1142 break;
1143 /* INC r8 */
1144 case 4:
1145 switch ((opcode>>3)&0x07u) {
1146 case 0: z80->bc.b = ZYM_INC8(z80, z80->bc.b); break;
1147 case 1: z80->bc.c = ZYM_INC8(z80, z80->bc.c); break;
1148 case 2: z80->de.d = ZYM_INC8(z80, z80->de.d); break;
1149 case 3: z80->de.e = ZYM_INC8(z80, z80->de.e); break;
1150 case 4: z80->dd->h = ZYM_INC8(z80, z80->dd->h); break;
1151 case 5: z80->dd->l = ZYM_INC8(z80, z80->dd->l); break;
1152 case 6:
1153 if (gotDD) { --z80->pc; z80_contention_by1ts_pc(z80, 5); ++z80->pc; }
1154 tmpW = ZADD_WX(z80->dd->w, disp);
1155 tmpB = z80_peekb_3ts(z80, tmpW);
1156 z80_contention_by1ts(z80, tmpW, 1);
1157 tmpB = ZYM_INC8(z80, tmpB);
1158 z80_pokeb_3ts(z80, tmpW, tmpB);
1159 break;
1160 case 7: z80->af.a = ZYM_INC8(z80, z80->af.a); break;
1162 break;
1163 /* DEC r8 */
1164 case 5:
1165 switch ((opcode>>3)&0x07u) {
1166 case 0: z80->bc.b = ZYM_DEC8(z80, z80->bc.b); break;
1167 case 1: z80->bc.c = ZYM_DEC8(z80, z80->bc.c); break;
1168 case 2: z80->de.d = ZYM_DEC8(z80, z80->de.d); break;
1169 case 3: z80->de.e = ZYM_DEC8(z80, z80->de.e); break;
1170 case 4: z80->dd->h = ZYM_DEC8(z80, z80->dd->h); break;
1171 case 5: z80->dd->l = ZYM_DEC8(z80, z80->dd->l); break;
1172 case 6:
1173 if (gotDD) { --z80->pc; z80_contention_by1ts_pc(z80, 5); ++z80->pc; }
1174 tmpW = ZADD_WX(z80->dd->w, disp);
1175 tmpB = z80_peekb_3ts(z80, tmpW);
1176 z80_contention_by1ts(z80, tmpW, 1);
1177 tmpB = ZYM_DEC8(z80, tmpB);
1178 z80_pokeb_3ts(z80, tmpW, tmpB);
1179 break;
1180 case 7: z80->af.a = ZYM_DEC8(z80, z80->af.a); break;
1182 break;
1183 /* LD r8,n */
1184 case 6:
1185 tmpB = z80_peekb_3ts_args(z80, z80->pc);
1186 ++z80->pc;
1187 switch ((opcode>>3)&0x07u) {
1188 case 0: z80->bc.b = tmpB; break;
1189 case 1: z80->bc.c = tmpB; break;
1190 case 2: z80->de.d = tmpB; break;
1191 case 3: z80->de.e = tmpB; break;
1192 case 4: z80->dd->h = tmpB; break;
1193 case 5: z80->dd->l = tmpB; break;
1194 case 6:
1195 if (gotDD) { --z80->pc; z80_contention_by1ts_pc(z80, 2); ++z80->pc; }
1196 tmpW = ZADD_WX(z80->dd->w, disp);
1197 z80_pokeb_3ts(z80, tmpW, tmpB);
1198 break;
1199 case 7: z80->af.a = tmpB; break;
1201 break;
1202 /* swim-swim-hungry */
1203 case 7:
1204 switch ((opcode>>3)&0x07u) {
1205 case 0: ZYM_RLCA(z80); break;
1206 case 1: ZYM_RRCA(z80); break;
1207 case 2: ZYM_RLA(z80); break;
1208 case 3: ZYM_RRA(z80); break;
1209 case 4: ZYM_DAA(z80); break;
1210 case 5: /* CPL */
1211 z80->af.a ^= 0xffu;
1212 z80->flags_q = z80->af.f = (z80->af.a&ZYM_FLAG_35)|(ZYM_FLAG_N|ZYM_FLAG_H)|(z80->af.f&(ZYM_FLAG_C|ZYM_FLAG_PV|ZYM_FLAG_Z|ZYM_FLAG_S));
1213 break;
1214 case 6: /* SCF */
1215 /* `!` must tell the predictor our preferred path, NMOS */
1216 z80->flags_q = z80->af.f = (z80->af.f&(ZYM_FLAG_PV|ZYM_FLAG_Z|ZYM_FLAG_S))|((z80->af.a|(!z80->cmos ? lastq^z80->af.f : 0))&ZYM_FLAG_35)|ZYM_FLAG_C;
1217 break;
1218 case 7: /* CCF */
1219 /* `!` must tell the predictor our preferred path, NMOS */
1220 z80->flags_q = z80->af.f = (z80->af.f&(ZYM_FLAG_PV|ZYM_FLAG_Z|ZYM_FLAG_S))|((z80->af.a|(!z80->cmos ? lastq^z80->af.f : 0))&ZYM_FLAG_35)|(z80->af.f&ZYM_FLAG_C ? ZYM_FLAG_H : ZYM_FLAG_C);
1221 break;
1223 break;
1225 break;
1226 /* 0x40..0x7F (LD r8,r8) */
1227 case 0x40u:
1228 if (opcode == 0x76u) { z80->halted = 1; --z80->pc; continue; } /* HALT */
1229 rsrc = (opcode&0x07u);
1230 rdst = ((opcode>>3)&0x07u);
1231 switch (rsrc) {
1232 case 0: tmpB = z80->bc.b; break;
1233 case 1: tmpB = z80->bc.c; break;
1234 case 2: tmpB = z80->de.d; break;
1235 case 3: tmpB = z80->de.e; break;
1236 case 4: tmpB = (gotDD && rdst == 6 ? z80->hl.h : z80->dd->h); break;
1237 case 5: tmpB = (gotDD && rdst == 6 ? z80->hl.l : z80->dd->l); break;
1238 case 6:
1239 if (gotDD) { --z80->pc; z80_contention_by1ts_pc(z80, 5); ++z80->pc; }
1240 tmpW = ZADD_WX(z80->dd->w, disp);
1241 tmpB = z80_peekb_3ts(z80, tmpW);
1242 break;
1243 case 7: tmpB = z80->af.a; break;
1245 switch (rdst) {
1246 case 0: z80->bc.b = tmpB; break;
1247 case 1: z80->bc.c = tmpB; break;
1248 case 2: z80->de.d = tmpB; break;
1249 case 3: z80->de.e = tmpB; break;
1250 case 4: if (gotDD && rsrc == 6) z80->hl.h = tmpB; else z80->dd->h = tmpB; break;
1251 case 5: if (gotDD && rsrc == 6) z80->hl.l = tmpB; else z80->dd->l = tmpB; break;
1252 case 6:
1253 if (gotDD) { --z80->pc; z80_contention_by1ts_pc(z80, 5); ++z80->pc; }
1254 tmpW = ZADD_WX(z80->dd->w, disp);
1255 z80_pokeb_3ts(z80, tmpW, tmpB);
1256 break;
1257 case 7: z80->af.a = tmpB; break;
1259 break;
1260 /* 0x80..0xBF (ALU A,r8) */
1261 case 0x80u:
1262 switch (opcode&0x07u) {
1263 case 0: tmpB = z80->bc.b; break;
1264 case 1: tmpB = z80->bc.c; break;
1265 case 2: tmpB = z80->de.d; break;
1266 case 3: tmpB = z80->de.e; break;
1267 case 4: tmpB = z80->dd->h; break;
1268 case 5: tmpB = z80->dd->l; break;
1269 case 6:
1270 if (gotDD) { --z80->pc; z80_contention_by1ts_pc(z80, 5); ++z80->pc; }
1271 tmpW = ZADD_WX(z80->dd->w, disp);
1272 tmpB = z80_peekb_3ts(z80, tmpW);
1273 break;
1274 case 7: tmpB = z80->af.a; break;
1276 switch ((opcode>>3)&0x07u) {
1277 case 0: ZYM_ADD_A(z80, tmpB); break;
1278 case 1: ZYM_ADC_A(z80, tmpB); break;
1279 case 2: ZYM_SUB_A(z80, tmpB); break;
1280 case 3: ZYM_SBC_A(z80, tmpB); break;
1281 case 4: ZYM_AND_A(z80, tmpB); break;
1282 case 5: ZYM_XOR_A(z80, tmpB); break;
1283 case 6: ZYM_OR_A(z80, tmpB); break;
1284 case 7: ZYM_CP_A(z80, tmpB); break;
1286 break;
1287 /* 0xC0..0xFF */
1288 case 0xC0:
1289 switch (opcode&0x07u) {
1290 /* RET cc */
1291 case 0:
1292 z80_contention_by1ts_ir(z80, 1);
1293 SET_TRUE_CC();
1294 if (trueCC) z80->memptr.w = z80->pc = z80_pop_6ts(z80);
1295 break;
1296 /* POP rr/special0 */
1297 case 1:
1298 if (opcode&0x08u) {
1299 /* special 0 */
1300 switch ((opcode>>4)&0x03u) {
1301 /* RET */
1302 case 0: z80->memptr.w = z80->pc = z80_pop_6ts(z80); break;
1303 /* EXX */
1304 case 1: zym_exx_internal(z80); break;
1305 /* JP (HL) */
1306 case 2: z80->pc = z80->dd->w; break;
1307 /* LD SP,HL */
1308 case 3:
1309 /*OCR(6)*/
1310 z80_contention_by1ts_ir(z80, 2);
1311 z80->sp.w = z80->dd->w;
1312 break;
1314 } else {
1315 /* POP rr */
1316 tmpW = z80_pop_6ts(z80);
1317 switch ((opcode>>4)&0x03u) {
1318 case 0: z80->bc.w = tmpW; break;
1319 case 1: z80->de.w = tmpW; break;
1320 case 2: z80->dd->w = tmpW; break;
1321 case 3: z80->af.w = tmpW; break;
1324 break;
1325 /* JP cc,nn */
1326 case 2:
1327 SET_TRUE_CC();
1328 z80->memptr.w = z80_getpcw(z80, 0);
1329 if (trueCC) z80->pc = z80->memptr.w;
1330 break;
1331 /* special1/special3 */
1332 case 3:
1333 switch ((opcode>>3)&0x07u) {
1334 /* JP nn */
1335 case 0: z80->memptr.w = z80->pc = z80_getpcw(z80, 0); break;
1336 /* OUT (n),A */
1337 case 2:
1338 tmpW = z80_peekb_3ts_args(z80, z80->pc);
1339 ++z80->pc;
1340 z80->memptr.l = (tmpW+1u)&0xffu;
1341 z80->memptr.h = z80->af.a;
1342 tmpW |= (((uint16_t)(z80->af.a))<<8);
1343 z80_port_write(z80, tmpW, z80->af.a);
1344 break;
1345 /* IN A,(n) */
1346 case 3:
1347 tmpB = z80_peekb_3ts_args(z80, z80->pc);
1348 tmpW = (uint16_t)((((uint16_t)(z80->af.a))<<8)|tmpB);
1349 ++z80->pc;
1350 z80->memptr.l = 0;
1351 z80->memptr.h = z80->af.a;
1352 z80->memptr.w += tmpW+1u;
1353 z80->af.a = z80_port_read(z80, tmpW);
1354 break;
1355 /* EX (SP),HL */
1356 case 4:
1357 /*SRL(3),SRH(4)*/
1358 tmpW = z80_peekw_6ts(z80, z80->sp.w);
1359 z80_contention_by1ts(z80, z80->sp.w+1u, 1);
1360 /*SWL(3),SWH(5)*/
1361 z80_pokew_6ts_inverted(z80, z80->sp.w, z80->dd->w);
1362 z80_contention_by1ts(z80, z80->sp.w, 2);
1363 z80->memptr.w = z80->dd->w = tmpW;
1364 break;
1365 /* EX DE,HL */
1366 case 5:
1367 tmpW = z80->de.w;
1368 z80->de.w = z80->hl.w;
1369 z80->hl.w = tmpW;
1370 break;
1371 /* DI */
1372 case 6: z80->iff1 = z80->iff2 = 0; break;
1373 /* EI */
1374 case 7: z80->iff1 = z80->iff2 = 1; z80->prev_was_EIDDR = 1; break;
1376 break;
1377 /* CALL cc,nn */
1378 case 4:
1379 SET_TRUE_CC();
1380 /* MEMPTR docs says that it is like JP */
1381 z80->memptr.w = z80_getpcw(z80, trueCC);
1382 if (trueCC) {
1383 z80_push_6ts(z80, z80->pc);
1384 z80->pc = z80->memptr.w;
1386 break;
1387 /* PUSH rr/special2 */
1388 case 5:
1389 if (opcode&0x08u) {
1390 if (((opcode>>4)&0x03u) == 0) {
1391 /* CALL */
1392 z80->memptr.w = tmpW = z80_getpcw(z80, 1);
1393 z80_push_6ts(z80, z80->pc);
1394 z80->pc = tmpW;
1396 } else {
1397 /* PUSH rr */
1398 /*OCR(5)*/
1399 z80_contention_by1ts_ir(z80, 1);
1400 switch ((opcode>>4)&0x03u) {
1401 case 0: tmpW = z80->bc.w; break;
1402 case 1: tmpW = z80->de.w; break;
1403 case 2: tmpW = z80->dd->w; break;
1404 default: tmpW = z80->af.w; break;
1406 z80_push_6ts(z80, tmpW);
1408 break;
1409 /* ALU A,n */
1410 case 6:
1411 tmpB = z80_peekb_3ts_args(z80, z80->pc);
1412 ++z80->pc;
1413 switch ((opcode>>3)&0x07u) {
1414 case 0: ZYM_ADD_A(z80, tmpB); break;
1415 case 1: ZYM_ADC_A(z80, tmpB); break;
1416 case 2: ZYM_SUB_A(z80, tmpB); break;
1417 case 3: ZYM_SBC_A(z80, tmpB); break;
1418 case 4: ZYM_AND_A(z80, tmpB); break;
1419 case 5: ZYM_XOR_A(z80, tmpB); break;
1420 case 6: ZYM_OR_A(z80, tmpB); break;
1421 case 7: ZYM_CP_A(z80, tmpB); break;
1423 break;
1424 /* RST nnn */
1425 case 7:
1426 /*OCR(5)*/
1427 z80_contention_by1ts_ir(z80, 1);
1428 z80_push_6ts(z80, z80->pc);
1429 z80->memptr.w = z80->pc = opcode&0x38u;
1430 break;
1432 break;
1433 } /* end switch */
1435 return z80->tstates-tstart;
1439 int32_t zym_exec_step (zym_cpu_t *z80) {
1440 const int32_t one = z80->next_event_tstate;
1441 z80->next_event_tstate = -1;
1442 const int32_t res = zym_exec_ex(z80, 1);
1443 z80->next_event_tstate = one;
1444 return res;
1448 /******************************************************************************/
1449 /* changes z80->tstates if interrupt occurs */
1450 int32_t zym_intr (zym_cpu_t *z80) {
1451 uint16_t a;
1452 const int32_t ots = z80->tstates;
1453 /* emulate NMOS Z80 bug: interruptet LD A,<I|R> copies cleared flag */
1454 /*FIXME: what is the state of `z80->flags_q` here? */
1455 if (z80->prev_was_EIDDR < 0) {
1456 z80->prev_was_EIDDR = 0;
1457 if (!z80->cmos) z80->flags_q = (z80->af.f &= ~ZYM_FLAG_PV);
1459 if (z80->prev_was_EIDDR || !z80->iff1) return 0; /* not accepted */
1460 z80->flags_q = 0; /* we cannot do it earlier, because ignored interrupt won't reset flags */
1461 /* skip "HALT" */
1462 if (z80->halted) { z80->halted = 0; ++z80->pc; }
1463 z80->iff1 = z80->iff2 = 0; /* disable interrupts */
1464 switch ((z80->im &= 0x03u)) {
1465 case 3: /* ??? */ z80->im = 0; /* fallthru */
1466 case 0: /* take instruction from the bus (for now we assume that reading from bus always returns 0xff) */
1467 /* with a CALL nnnn on the data bus, it takes 19 cycles: */
1468 /* M1 cycle: 7 T to acknowledge interrupt (where exactly data bus reading occurs?) */
1469 /* M2 cycle: 3 T to read low byte of 'nnnn' from data bus */
1470 /* M3 cycle: 3 T to read high byte of 'nnnn' and decrement SP */
1471 /* M4 cycle: 3 T to write high byte of PC to the stack and decrement SP */
1472 /* M5 cycle: 3 T to write low byte of PC and jump to 'nnnn' */
1473 z80->tstates += 6;
1474 /* fallthru */
1475 case 1: /* just do RST #38 */
1476 INC_R;
1477 z80->tstates += 7; /* M1 cycle: 7 T to acknowledge interrupt and decrement SP */
1478 /* M2 cycle: 3 T states write high byte of PC to the stack and decrement SP */
1479 /* M3 cycle: 3 T states write the low byte of PC and jump to #0038 */
1480 z80_push_6ts(z80, z80->pc);
1481 z80->memptr.w = z80->pc = 0x38u;
1482 break;
1483 case 2:
1484 INC_R;
1485 z80->tstates += 7; /* M1 cycle: 7 T to acknowledge interrupt and decrement SP */
1486 /* M2 cycle: 3 T states write high byte of PC to the stack and decrement SP */
1487 /* M3 cycle: 3 T states write the low byte of PC */
1488 z80_push_6ts(z80, z80->pc);
1489 /* M4 cycle: 3 T to read high byte from the interrupt vector */
1490 /* M5 cycle: 3 T to read low byte from bus and jump to interrupt routine */
1491 a = (((uint16_t)z80->regI)<<8)|0xffu;
1492 z80->memptr.w = z80->pc = z80_peekw_6ts(z80, a);
1493 break;
1495 return z80->tstates-ots; /* accepted */
1499 /* changes z80->tstates if interrupt occurs */
1500 int32_t zym_nmi (zym_cpu_t *z80) {
1501 const int32_t ots = z80->tstates;
1502 /* emulate NMOS Z80 bug: interruptet LD A,<I|R> copies cleared flag */
1503 /*FIXME: what is the state of `z80->flags_q` here? */
1504 if (z80->prev_was_EIDDR < 0) {
1505 z80->prev_was_EIDDR = 0;
1506 if (!z80->cmos) z80->flags_q = (z80->af.f &= ~ZYM_FLAG_PV);
1508 if (z80->prev_was_EIDDR) return 0;
1509 z80->flags_q = 0; /* we cannot do it earlier, because ignored interrupt won't reset flags */
1510 /* skip "HALT" */
1511 if (z80->halted) { z80->halted = 0; ++z80->pc; }
1512 INC_R;
1513 z80->iff1 = 0; /* IFF2 is not changed */
1514 z80->tstates += 5; /* M1 cycle: 5 T states to do an opcode read and decrement SP */
1515 /* M2 cycle: 3 T states write high byte of PC to the stack and decrement SP */
1516 /* M3 cycle: 3 T states write the low byte of PC and jump to #0066 */
1517 z80_push_6ts(z80, z80->pc);
1518 z80->memptr.w = z80->pc = 0x66u;
1519 return z80->tstates-ots;
1523 /******************************************************************************/
1524 uint16_t zym_pop (zym_cpu_t *z80) {
1525 uint16_t res = z80_peekb_i(z80, z80->sp.w);
1526 ++z80->sp.w;
1527 res |= ((uint16_t)z80_peekb_i(z80, z80->sp.w))<<8;
1528 ++z80->sp.w;
1529 return res;
1533 void zym_push (zym_cpu_t *z80, const uint16_t value) {
1534 --z80->sp.w;
1535 z80_pokeb_i(z80, z80->sp.w, (value>>8)&0xffu);
1536 --z80->sp.w;
1537 z80_pokeb_i(z80, z80->sp.w, value&0xffu);
1541 /******************************************************************************
1542 instruction decoding
1543 ====================
1544 00 00y 000 -- special
1545 00 01g 000 -- DJNZ/JR
1546 00 1cc 000 -- JR cc,n
1547 00 rr0 001 -- LD rr,nn
1548 00 rr1 001 -- ADD HL,rr
1549 00 000 010 -- LD (BC),A
1550 00 001 010 -- LD A,(BC)
1551 00 010 010 -- LD (DE),A
1552 00 011 010 -- LD A,(DE)
1553 00 100 010 -- LD (nn),HL
1554 00 101 010 -- LD HL,(nn)
1555 00 110 010 -- LD (nn),A
1556 00 111 010 -- LD A,(nn)
1557 00 rr0 011 -- INC rr
1558 00 rr1 011 -- DEC rr
1559 00 rrr 100 -- INC r8
1560 00 rrr 101 -- DEC r8
1561 00 rrr 110 -- LD r8,n
1562 00 xxx 111 -- special
1565 0 - NOP
1566 1 - EX AF,AF'
1568 0 - DJNZ
1569 1 - JR
1571 00 - NZ
1572 01 - Z
1573 10 - NC
1574 11 - C
1575 xxx:
1576 000 - RLCA
1577 001 - RRCA
1578 010 - RLA
1579 011 - RRA
1580 100 - DAA
1581 101 - CPL
1582 110 - SCF
1583 111 - CCF
1584 rrr:
1585 000 - B
1586 001 - C
1587 010 - D
1588 011 - E
1589 100 - H
1590 101 - L
1591 110 - (HL)
1592 111 - A
1594 00 - BC
1595 01 - DE
1596 10 - HL
1597 11 - SP
1599 ---------------------------------
1601 01 rrr rrr - LD r8,r8 (lo: src)
1603 ---------------------------------
1605 10 alu rrr - ALU a,r8
1606 alu:
1607 000 - ADD
1608 001 - ADC
1609 010 - SUB
1610 011 - SBC
1611 100 - AND
1612 101 - XOR
1613 110 - OR
1614 111 - CP
1616 ---------------------------------
1618 11 ccc 000 -- RET cc
1619 11 rr0 001 -- POP rr
1620 11 xx1 001 -- special0
1621 11 ccc 010 -- JP cc,nn
1622 11 yyy 011 -- special1
1623 11 ccc 100 -- CALL cc,nn
1624 11 rr0 101 -- PUSH rr
1625 11 zz1 101 -- special2
1626 11 alu 110 -- alu A,n
1627 11 aaa 111 -- RST nnn
1630 00 - BC
1631 01 - DE
1632 10 - HL
1633 11 - AF
1634 aaa: RST addr=aaa<<3
1635 ccc:
1636 000 - NZ
1637 001 - Z
1638 010 - NC
1639 011 - C
1640 100 - PO
1641 101 - PE
1642 110 - P
1643 111 - M
1644 alu:
1645 000 - ADD
1646 001 - ADC
1647 010 - SUB
1648 011 - SBC
1649 100 - AND
1650 101 - XOR
1651 110 - OR
1652 111 - CP
1654 00 - RET
1655 01 - EXX
1656 10 - JP HL
1657 11 - LD SP,HL
1658 yyy:
1659 000 - JP nn
1660 001 - CB
1661 010 - OUT (n),A
1662 011 - IN A,(n)
1663 100 - EX (SP),HL
1664 101 - EX DE,HL
1665 110 - DI
1666 111 - EI
1668 00 - CALL nn
1669 01 - DD
1670 10 - ED
1671 11 - FD
1674 ---------------------------------
1677 01 rrr 000 -- IN r8,(C)
1678 01 rrr 001 -- OUT (C),r8
1679 01 rr0 010 -- SBC HL,rr
1680 01 rr1 010 -- ADC HL,rr
1681 01 rr0 011 -- LD (nn),rr
1682 01 rr1 011 -- LD rr,(nn)
1684 01 000 100 -- NEG
1685 01 001 100 -- NEG
1686 01 010 100 -- NEG
1687 01 011 100 -- NEG
1688 01 100 100 -- NEG
1689 01 101 100 -- NEG
1690 01 110 100 -- NEG
1691 01 111 100 -- NEG
1693 01 000 101 -- RETN
1694 01 001 101 -- RETI
1695 01 010 101 -- RETN
1696 01 011 101 -- RETI
1697 01 100 101 -- RETN
1698 01 101 101 -- RETI
1699 01 110 101 -- RETN
1700 01 111 101 -- RETI
1702 01 000 110 -- IM 0
1703 01 001 110 -- IM 0/1
1704 01 010 110 -- IM 1
1705 01 011 110 -- IM 2
1706 01 100 110 -- IM 0
1707 01 101 110 -- IM 0
1708 01 111 110 -- IM 2
1710 01 000 111 -- LD I,A
1711 01 001 111 -- LD R,A
1712 01 010 111 -- LD A,I
1713 01 011 111 -- LD A,R
1714 01 100 111 -- RRD
1715 01 101 111 -- RLD
1716 01 110 111 -- NOP
1717 01 111 111 -- NOP
1720 10 1rd 0tt
1721 r: repeating instruction? (1: yes)
1722 d: direction (0:inc; 1:dec)
1723 tt: instruction type
1724 00: LD
1725 01: CP
1726 10: IN
1727 11: OUT
1729 10 100 000 -- LDI
1730 10 110 000 -- LDIR
1731 10 101 000 -- LDD
1732 10 111 000 -- LDDR
1734 10 100 001 -- CPI
1735 10 110 001 -- CPIR
1736 10 101 001 -- CPD
1737 10 111 001 -- CPDR
1739 10 100 010 -- INI
1740 10 110 010 -- INIR
1741 10 101 010 -- IND
1742 10 111 010 -- INDR
1744 10 100 011 -- OUTI
1745 10 110 011 -- OTIR
1746 10 101 011 -- OUTD
1747 10 111 011 -- OTDR
1750 ---------------------------------
1752 zz xxx rrr
1754 rrr: the usual r8
1757 00 -- see below
1758 01 -- BIT n, r8
1759 10 -- RES n, r8
1760 11 -- SET n, r8
1762 for bitops, xxx is bit number
1764 xxx:
1765 000 - RLC r8
1766 001 - RRC r8
1767 010 - RL r8
1768 011 - RR r8
1769 100 - SLA r8
1770 101 - SRA r8
1771 110 - SLL r8
1772 111 - SRL r8
1774 for DD/FD prefix, 3rd byte is always disp,
1775 and the result is always written to (I<X|Y>+disp)
1778 command reading cycles
1779 ======================
1780 the following is not 100% correct, but the position
1781 of the contention cycles is right
1783 m1 cycle (accoding to the official Zilog manual)
1784 t1: setting /MREQ & /RD
1785 t2: memory read
1786 here comes contetion (AFTER t2!)
1787 t3,t4: decode command, increment R
1789 memory read/write cycles (accoding to the official Zilog manual)
1790 t1,t2: memory address select
1791 here comes contetion (AFTER t2!)
1792 t3: bus read/write
1794 port i/o cycles (accoding to the official Zilog manual)
1795 t1,t2: port address select
1796 tw: automatic wait tick
1797 here comes contetion (AFTER t2!)
1798 t3: bus read/write
1801 flag register bits
1802 ==================
1803 bit 0: carry
1804 bit 1: flagN (see below)
1805 bit 2: parity/overflow
1806 bit 3: bit3
1807 bit 4: half-carry
1808 bit 5: bit5
1809 bit 6: zero
1810 bit 7: sign
1812 flagN:
1813 set if the last operation was a subtraction (used by DAA).
1815 P/V - parity or overflow
1816 parity set if even number of bits set
1817 overflow set if the 2-complement result does not fit in the register
1819 *******************************************************************************/