1 /*
2 * Copyright (c) 2019 Georg Brein. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * 3. Neither the name of the copyright holder nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <stddef.h>
35 #include <string.h>
36 #include <errno.h>
37 #include <wchar.h>
38 #include <setjmp.h>
39 #include <signal.h>
40 #include <time.h>
41
42 #include <sys/time.h>
43 #include <unistd.h>
44
45 #include "tnylpo.h"
46
47
48 unsigned char *memory = NULL;
49
50
51 /*
52 * CPU status
53 */
54 static int flag_i = 0;
55
56
57 /*
58 * CPU registers and flags
59 */
60 int reg_sp = 0;
61 int reg_pc = 0;
62 unsigned char reg_a = 0;
63 unsigned char reg_b = 0;
64 unsigned char reg_c = 0;
65 unsigned char reg_d = 0;
66 unsigned char reg_e = 0;
67 unsigned char reg_h = 0;
68 unsigned char reg_l = 0;
69 static unsigned char alt_reg_a = 0;
70 static unsigned char alt_reg_b = 0;
71 static unsigned char alt_reg_c = 0;
72 static unsigned char alt_reg_d = 0;
73 static unsigned char alt_reg_e = 0;
74 static unsigned char alt_reg_h = 0;
75 static unsigned char alt_reg_l = 0;
76 static unsigned char reg_ixh = 0;
77 static unsigned char reg_ixl = 0;
78 static unsigned char reg_iyh = 0;
79 static unsigned char reg_iyl = 0;
80 static unsigned char reg_r = 0;
81 static unsigned char reg_i = 0;
82 static int flag_s = 0;
83 static int flag_z = 0;
84 static int flag_y = 0;
85 static int flag_h = 0;
86 static int flag_x = 0;
87 static int flag_p = 0;
88 #define flag_v flag_p
89 static int flag_n = 0;
90 static int flag_c = 0;
91 static int alt_flag_s = 0;
92 static int alt_flag_z = 0;
93 static int alt_flag_y = 0;
94 static int alt_flag_h = 0;
95 static int alt_flag_x = 0;
96 static int alt_flag_p = 0;
97 static int alt_flag_n = 0;
98 static int alt_flag_c = 0;
99
100
101 /*
102 * termination flag
103 */
104 int terminate = 0;
105
106
107 /*
108 * dump flag
109 */
110 static sig_atomic_t dump = 0;
111
112
113 /*
114 * reason for termination
115 */
116 enum reason term_reason = OK_NOTRUN;
117
118
119 /*
120 * start of current instruction including prefixes
121 */
122 static int current_instruction = (-1);
123 /*
124 * parts of the current instruction
125 */
126 static int prefix, opcode, opcode2, op_low, op_high, disp;
127 /*
128 * the mysterious internal register which is sometimes visible via X3, X5
129 */
130 static int internal = 0;
131
132
133
134 /*
135 * get word from memory
136 */
137 static inline int
get_word(int address)138 get_word(int address) {
139 int word = memory[(address + 1) & 0xffff];
140 word <<= 8;
141 word |= memory[address];
142 return word;
143 }
144
145
146 /*
147 * store word to memory
148 */
149 static inline void
set_word(int address,int word)150 set_word(int address, int word) {
151 memory[address] = (word & 0xff);
152 memory[(address + 1) & 0xffff] = ((word >> 8) & 0xff);
153 }
154
155
156 static inline int
get_bc(void)157 get_bc(void) { int bc = reg_b; bc <<= 8; bc |= reg_c; return bc; }
158
159 static inline void
set_bc(int bc)160 set_bc(int bc) { reg_c = bc & 0xff; reg_b = (bc >> 8) & 0xff; }
161
162 static inline int
get_de(void)163 get_de(void) { int de = reg_d; de <<= 8; de |= reg_e; return de; }
164
165 static inline void
set_de(int de)166 set_de(int de) { reg_e = de & 0xff; reg_d = (de >> 8) & 0xff; }
167
168 static inline int
get_hl(void)169 get_hl(void) { int hl = reg_h; hl <<= 8; hl |= reg_l; return hl; }
170
171 static inline void
set_hl(int hl)172 set_hl(int hl) { reg_l = hl & 0xff; reg_h = (hl >> 8) & 0xff; }
173
174 static inline int
get_ix(void)175 get_ix(void) { int ix = reg_ixh; ix <<= 8; ix |= reg_ixl; return ix; }
176
177 static inline void
set_ix(int ix)178 set_ix(int ix) { reg_ixl = ix & 0xff; reg_ixh = (ix >> 8) & 0xff; }
179
180 static inline int
get_iy(void)181 get_iy(void) { int iy = reg_iyh; iy <<= 8; iy |= reg_iyl; return iy; }
182
183 static inline void
set_iy(int iy)184 set_iy(int iy) { reg_iyl = iy & 0xff; reg_iyh = (iy >> 8) & 0xff; }
185
186
187 /*
188 * dump registers and memory to log file
189 */
190 static void
dump_machine(const char * label)191 dump_machine(const char *label) {
192 plog("start of %s machine dump", label);
193 plog("a=%02x f=%c%c%c%c%c%c%c%c bc=%04x de=%04x hl=%04x",
194 reg_a, flag_s ? 's' : '-', flag_z ? 'z' : '-',
195 flag_y ? 'y' : '-', flag_h ? 'h' : '-', flag_x ? 'x' : '-',
196 flag_p ? 'p' : '-', flag_n ? 'n' : '-', flag_c ? 'c' : '-',
197 get_bc(), get_de(), get_hl());
198 plog("a\'=%02x f\'=%c%c%c%c%c%c%c%c bc\'=%04x de\'=%04x hl\'=%04x",
199 alt_reg_a, alt_flag_s ? 's' : '-',
200 alt_flag_z ? 'z' : '-', alt_flag_y ? 'y' : '-',
201 alt_flag_h ? 'h' : '-', alt_flag_x ? 'x' : '-',
202 alt_flag_p ? 'p' : '-', alt_flag_n ? 'n' : '-',
203 alt_flag_c ? 'c' : '-', (alt_reg_b << 8) | alt_reg_c,
204 (alt_reg_d << 8) | alt_reg_e, (alt_reg_h << 8) | alt_reg_l);
205 plog("ix=%04x iy=%04x sp=%04x pc=%04x, r=%02x i=%02x",
206 get_ix(), get_iy(), reg_sp, reg_pc, reg_r, reg_i);
207 plog("interrupts %s", flag_i ? "enabled" : "disabled");
208 plog_dump(0, MEMORY_SIZE);
209 plog("end of %s machine dump", label);
210 }
211
212
213 /*
214 * initialize the CPU emulator: allocate main memory, initialize OS emulation
215 */
216 int
cpu_init(void)217 cpu_init(void) {
218 int rc = 0;
219 struct timeval tv;
220 /*
221 * allocate Z80 memory and fill it with HALT instructions
222 */
223 memory = alloc(MEMORY_SIZE);
224 memset(memory, 0x76 /* HALT */, MEMORY_SIZE);
225 /*
226 * set register R to some random value; programs (e. g. Turbo Pascal)
227 * use R for generating random numbers
228 *
229 * No, this random number is not suitable for
230 * cryptographical purposes.
231 */
232 gettimeofday(&tv, NULL);
233 srand((unsigned) tv.tv_usec);
234 reg_r = (rand() & 0x7f);
235 /*
236 * initialize OS emulation
237 */
238 rc = os_init();
239 if (rc) goto premature_exit;
240 /*
241 * perform startup dump
242 */
243 if (conf_dump & DUMP_STARTUP) dump_machine("startup");
244 premature_exit:
245 if (rc) free(memory);
246 return rc;
247 }
248
249
250 /*
251 * get word from stack
252 */
253 static int
pop(void)254 pop(void) {
255 int word;
256 word = memory[reg_sp];
257 reg_sp = ((reg_sp + 1) & 0xffff);
258 word |= (((int) memory[reg_sp]) << 8);
259 reg_sp = ((reg_sp + 1) & 0xffff);
260 return word;
261 }
262
263
264 /*
265 * put word on stack
266 */
267 static void
push(int word)268 push(int word) {
269 reg_sp = ((reg_sp + 0xffff) & 0xffff);
270 memory[reg_sp] = ((word >> 8) & 0xff);
271 reg_sp = ((reg_sp + 0xffff) & 0xffff);
272 memory[reg_sp] = word & 0xff;
273 }
274
275
276 /*
277 * do nothing
278 */
279 static void
inst_nop(void)280 inst_nop(void) { }
281
282
283 /*
284 * load immediate extended
285 */
286 static void
inst_lxi(void)287 inst_lxi(void) {
288 switch (opcode & 0x30) {
289 case 0x00:
290 reg_c = op_low;
291 reg_b = op_high;
292 break;
293 case 0x10:
294 reg_e = op_low;
295 reg_d = op_high;
296 break;
297 case 0x20:
298 if (prefix == 0xdd) {
299 reg_ixl = op_low;
300 reg_ixh = op_high;
301 } else if (prefix == 0xfd) {
302 reg_iyl = op_low;
303 reg_iyh = op_high;
304 } else {
305 reg_l = op_low;
306 reg_h = op_high;
307 }
308 break;
309 case 0x30:
310 reg_sp = op_high;
311 reg_sp <<= 8;
312 reg_sp |= op_low;
313 break;
314 }
315 }
316
317
318 /*
319 * store A extended
320 */
321 static void
inst_stax(void)322 inst_stax(void) {
323 memory[(opcode & 0x10) ? get_de() : get_bc()] = reg_a;
324 }
325
326
327 /*
328 * load A extended
329 */
330 static void
inst_ldax(void)331 inst_ldax(void) {
332 reg_a = memory[(opcode & 0x10) ? get_de() : get_bc()];
333 }
334
335
336 /*
337 * store A
338 */
339 static void
inst_sta(void)340 inst_sta(void) {
341 int addr;
342 addr = op_high;
343 addr <<= 8;
344 addr |= op_low;
345 memory[addr] = reg_a;
346 }
347
348
349 /*
350 * load A
351 */
352 static void
inst_lda(void)353 inst_lda(void) {
354 int addr;
355 addr = op_high;
356 addr <<= 8;
357 addr |= op_low;
358 reg_a = memory[addr];
359 }
360
361
362 /*
363 * store HL/IX/IY
364 */
365 static void
inst_shld(void)366 inst_shld(void) {
367 int addr;
368 unsigned char *lp, *hp;
369 addr = op_high;
370 addr <<= 8;
371 addr |= op_low;
372 lp = memory + addr;
373 hp = memory + ((addr + 1) & 0xffff);
374 switch (prefix) {
375 case 0x00:
376 *lp = reg_l;
377 *hp = reg_h;
378 break;
379 case 0xdd:
380 *lp = reg_ixl;
381 *hp = reg_ixh;
382 break;
383 case 0xfd:
384 *lp = reg_iyl;
385 *hp = reg_iyh;
386 break;
387 }
388 }
389
390
391 /*
392 * load HL/IX/IY
393 */
394 static void
inst_lhld(void)395 inst_lhld(void) {
396 int addr;
397 unsigned char *lp, *hp;
398 addr = op_high;
399 addr <<= 8;
400 addr |= op_low;
401 lp = memory + addr;
402 hp = memory + ((addr + 1) & 0xffff);
403 switch (prefix) {
404 case 0x00:
405 reg_l = *lp;
406 reg_h = *hp;
407 break;
408 case 0xdd:
409 reg_ixl = *lp;
410 reg_ixh = *hp;
411 break;
412 case 0xfd:
413 reg_iyl = *lp;
414 reg_iyh = *hp;
415 break;
416 }
417 }
418
419
420 /*
421 * relative jump
422 */
423 static void
inst_jr(void)424 inst_jr(void) {
425 internal = op_low;
426 if (internal & 0x80) internal |= 0xff00;
427 internal = (internal + reg_pc) & 0xffff;
428 reg_pc = internal;
429 }
430
431
432 /*
433 * conditional relative jump
434 */
435 static void
inst_jrcc(void)436 inst_jrcc(void) {
437 switch (opcode & 0x18) {
438 case 0x00: if (! flag_z) inst_jr(); break;
439 case 0x08: if (flag_z) inst_jr(); break;
440 case 0x10: if (! flag_c) inst_jr(); break;
441 case 0x18: if (flag_c) inst_jr(); break;
442 }
443 }
444
445
446 /*
447 * DJNZ
448 */
449 static void
inst_djnz(void)450 inst_djnz(void) {
451 reg_b = reg_b ? reg_b - 1 : 0xff;
452 if (reg_b) inst_jr();
453 }
454
455
456 /*
457 * EX AF,AF'
458 */
459 static void
inst_exaf(void)460 inst_exaf(void) {
461 unsigned char uc;
462 int i;
463 uc = reg_a; reg_a = alt_reg_a; alt_reg_a = uc;
464 i = flag_c; flag_c = alt_flag_c; alt_flag_c = i;
465 i = flag_n; flag_n = alt_flag_n; alt_flag_n = i;
466 i = flag_p; flag_v = alt_flag_p; alt_flag_p = i;
467 i = flag_x; flag_x = alt_flag_x; alt_flag_x = i;
468 i = flag_h; flag_h = alt_flag_h; alt_flag_h = i;
469 i = flag_y; flag_y = alt_flag_y; alt_flag_y = i;
470 i = flag_z; flag_z = alt_flag_z; alt_flag_z = i;
471 i = flag_s; flag_s = alt_flag_s; alt_flag_s = i;
472 }
473
474
475 /*
476 * set carry flag
477 */
478 static void
inst_scf(void)479 inst_scf(void) {
480 flag_y = ((reg_a & 0x20) != 0);
481 flag_h = 0;
482 flag_x = ((reg_a & 0x08) != 0);
483 flag_n = 0;
484 flag_c = 1;
485 }
486
487
488 /*
489 * complement carry flag
490 */
491 static void
inst_ccf(void)492 inst_ccf(void) {
493 flag_y = ((reg_a & 0x20) != 0);
494 flag_h = flag_c;
495 flag_x = ((reg_a & 0x08) != 0);
496 flag_n = 0;
497 flag_c = (flag_c == 0);
498 }
499
500
501 /*
502 * halt CPU: terminates program execution
503 */
504 static void
inst_halt(void)505 inst_halt(void) {
506 plog("0x%04x: HALT executed", current_instruction);
507 terminate = 1;
508 term_reason = ERR_HALT;
509 }
510
511
512 /*
513 * complement A
514 */
515 static void
inst_cpl(void)516 inst_cpl(void) {
517 reg_a ^= 0xff;
518 flag_y = ((reg_a & 0x20) != 0);
519 flag_h = 1;
520 flag_x = ((reg_a & 0x08) != 0);
521 flag_n = 1;
522 }
523
524
525 /*
526 * helper function for inst_rla(), inst_rlca(), inst_rra(), and inst_rrca()
527 */
528 static void
rot_flags(void)529 rot_flags(void) {
530 flag_y = ((reg_a & 0x20) != 0);
531 flag_h = 0;
532 flag_x = ((reg_a & 0x08) != 0);
533 flag_n = 0;
534 }
535
536
537 /*
538 * 9-Bit rotation of A to the left
539 */
540 static void
inst_rla(void)541 inst_rla(void) {
542 unsigned t;
543 t = reg_a;
544 t <<= 1;
545 t |= flag_c;
546 flag_c = ((t & 0x100) == 0x100);
547 reg_a = (unsigned char) (t & 0xff);
548 rot_flags();
549 }
550
551
552 /*
553 * 8-Bit rotation of A to the left
554 */
555 static void
inst_rlca(void)556 inst_rlca(void) {
557 flag_c = ((reg_a & 0x80) == 0x80);
558 reg_a <<= 1;
559 reg_a &= 0xff;
560 reg_a |= flag_c;
561 rot_flags();
562 }
563
564
565 /*
566 * 9-Bit rotation of A to the right
567 */
568 static void
inst_rra(void)569 inst_rra(void) {
570 unsigned t;
571 t = reg_a;
572 if (flag_c) t |= 0x100;
573 flag_c = ((t & 0x01) == 0x01);
574 t >>= 1;
575 reg_a = (unsigned char) (t & 0xff);
576 rot_flags();
577 }
578
579
580 /*
581 * 8-Bit rotation of A to the right
582 */
583 static void
inst_rrca(void)584 inst_rrca(void) {
585 flag_c = ((reg_a & 0x01) == 0x01);
586 reg_a >>= 1;
587 if (flag_c) reg_a |= 0x80;
588 rot_flags();
589 }
590
591
592 /*
593 * return address of 8-bit register/memory operand
594 * n is the 3-bit field from the opcode describing the register/memory operand:
595 * (0=b, 1=c, 2=d, 3=e, 4=h/ixh/iyh, 5=l/ixl/iyl, 6=(hl)/(ix+d)/(iy+d), 7=a)
596 * a is the second 3-bit operand field from the same opcode (or zero if
597 * there is none)
598 */
599 static unsigned char *
operand8(int n,int a)600 operand8(int n, int a) {
601 switch (n) {
602 case 0: return ®_b;
603 case 1: return ®_c;
604 case 2: return ®_d;
605 case 3: return ®_e;
606 case 4:
607 if (a == 6) return ®_h;
608 switch (prefix) {
609 case 0xdd: return ®_ixh;
610 case 0xfd: return ®_iyh;
611 default: return ®_h;
612 }
613 case 5:
614 if (a == 6) return ®_l;
615 switch (prefix) {
616 case 0xdd: return ®_ixl;
617 case 0xfd: return ®_iyl;
618 default: return ®_l;
619 }
620 case 6:
621 switch (prefix) {
622 case 0xdd:
623 internal = disp;
624 if (internal & 0x80) internal |= 0xff00;
625 internal = (get_ix() + internal) & 0xffff;
626 return memory + internal;
627 case 0xfd:
628 internal = disp;
629 if (internal & 0x80) internal |= 0xff00;
630 internal = (get_iy() + internal) & 0xffff;
631 return memory + internal;
632 default:
633 return memory + get_hl();
634 }
635 default: return ®_a;
636 }
637
638 }
639
640
641 /*
642 * move 8-bit data
643 */
644 static void
inst_mov(void)645 inst_mov(void) {
646 int d, s;
647 unsigned char *dp, *sp;
648 d = ((opcode >> 3) & 0x07);
649 s = (opcode & 0x07);
650 dp = operand8(d, s);
651 sp = operand8(s, d);
652 *dp = *sp;
653 }
654
655
656 /*
657 * move 8-bit immediate
658 */
659 static void
inst_mvi(void)660 inst_mvi(void) {
661 *operand8((opcode >> 3) & 0x07, 0) = op_low;
662 }
663
664
665 /*
666 * returns sumand1 + summand2 + carry, sets flags
667 */
668 static unsigned char
add8(unsigned char summand1,unsigned char summand2,int carry)669 add8(unsigned char summand1, unsigned char summand2, int carry) {
670 int c6;
671 unsigned s1 = summand1, s2 = summand2, su, cy = carry ? 1 : 0;
672 /*
673 * unrolled loop
674 */
675 su = (s1 ^ s2 ^ cy) & 0x01;
676 cy = ((s2 & cy) | (s1 & (s2 | cy))) & 0x01;
677 cy <<= 1;
678 su |= (s1 ^ s2 ^ cy) & 0x02;
679 cy = ((s2 & cy) | (s1 & (s2 | cy))) & 0x02;
680 cy <<= 1;
681 su |= (s1 ^ s2 ^ cy) & 0x04;
682 cy = ((s2 & cy) | (s1 & (s2 | cy))) & 0x04;
683 cy <<= 1;
684 su |= (s1 ^ s2 ^ cy) & 0x08;
685 cy = ((s2 & cy) | (s1 & (s2 | cy))) & 0x08;
686 flag_h = (cy != 0);
687 cy <<= 1;
688 su |= (s1 ^ s2 ^ cy) & 0x10;
689 cy = ((s2 & cy) | (s1 & (s2 | cy))) & 0x10;
690 cy <<= 1;
691 su |= (s1 ^ s2 ^ cy) & 0x20;
692 cy = ((s2 & cy) | (s1 & (s2 | cy))) & 0x20;
693 cy <<= 1;
694 su |= (s1 ^ s2 ^ cy) & 0x40;
695 cy = ((s2 & cy) | (s1 & (s2 | cy))) & 0x40;
696 c6 = (cy != 0);
697 cy <<= 1;
698 su |= (s1 ^ s2 ^ cy) & 0x80;
699 cy = ((s2 & cy) | (s1 & (s2 | cy))) & 0x80;
700 flag_c = (cy != 0);
701 flag_n = 0;
702 flag_v = flag_c ^ c6;
703 flag_x = ((su & 0x08) != 0);
704 flag_y = ((su & 0x20) != 0);
705 flag_z = (su == 0);
706 flag_s = ((su & 0x80) != 0);
707 return (unsigned char) su;
708 }
709
710
711 /*
712 * returns minuend - subtrahend - carry, sets flags
713 */
714 static unsigned char
sub8(unsigned char minuend,unsigned char subtrahend,int carry)715 sub8(unsigned char minuend, unsigned char subtrahend, int carry) {
716 int c6;
717 unsigned mi = minuend, sb = subtrahend, df, cy = carry ? 1 : 0;
718 /*
719 * unrolled loop
720 */
721 df = (mi ^ sb ^ cy) & 0x01;
722 cy = ((sb & cy) | (~mi & (sb | cy))) & 0x01;
723 cy <<= 1;
724 df |= (mi ^ sb ^ cy) & 0x02;
725 cy = ((sb & cy) | (~mi & (sb | cy))) & 0x02;
726 cy <<= 1;
727 df |= (mi ^ sb ^ cy) & 0x04;
728 cy = ((sb & cy) | (~mi & (sb | cy))) & 0x04;
729 cy <<= 1;
730 df |= (mi ^ sb ^ cy) & 0x08;
731 cy = ((sb & cy) | (~mi & (sb | cy))) & 0x08;
732 flag_h = (cy != 0);
733 cy <<= 1;
734 df |= (mi ^ sb ^ cy) & 0x10;
735 cy = ((sb & cy) | (~mi & (sb | cy))) & 0x10;
736 cy <<= 1;
737 df |= (mi ^ sb ^ cy) & 0x20;
738 cy = ((sb & cy) | (~mi & (sb | cy))) & 0x20;
739 cy <<= 1;
740 df |= (mi ^ sb ^ cy) & 0x40;
741 cy = ((sb & cy) | (~mi & (sb | cy))) & 0x40;
742 c6 = (cy != 0);
743 cy <<= 1;
744 df |= (mi ^ sb ^ cy) & 0x80;
745 cy = ((sb & cy) | (~mi & (sb | cy))) & 0x80;
746 flag_c = (cy != 0);
747 flag_n = 1;
748 flag_v = flag_c ^ c6;
749 flag_x = ((df & 0x08) != 0);
750 flag_y = ((df & 0x20) != 0);
751 flag_z = (df == 0);
752 flag_s = ((df & 0x80) != 0);
753 return (unsigned char) df;
754 }
755
756
757 /*
758 * returns s1 + s2 + carry, sets flags
759 */
760 static unsigned
add16(unsigned s1,unsigned s2,int carry)761 add16(unsigned s1, unsigned s2, int carry) {
762 int c14 = 0, i;
763 unsigned su = 0, cy = carry ? 1 : 0, ma = 1;
764 for (i = 0; i < 16; i++) {
765 su |= (s1 ^ s2 ^ cy) & ma;
766 cy = ((s2 & cy) | (s1 & (s2 | cy))) & ma;
767 if (i == 11) flag_h = (cy != 0);
768 if (i == 14) c14 = (cy != 0);
769 if (i == 15) flag_c = (cy != 0);
770 cy <<= 1;
771 ma <<= 1;
772 }
773 flag_n = 0;
774 flag_v = flag_c ^ c14;
775 flag_x = ((su & 0x0800) != 0);
776 flag_y = ((su & 0x2000) != 0);
777 flag_z = (su == 0);
778 flag_s = ((su & 0x8000) != 0);
779 return su;
780 }
781
782
783 /*
784 * returns s1 - s2 - carry, sets flags
785 */
786 static unsigned
sub16(unsigned mi,unsigned sb,int carry)787 sub16(unsigned mi, unsigned sb, int carry) {
788 int c14 = 0, i;
789 unsigned df = 0, cy = carry ? 1 : 0, ma = 1;
790 for (i = 0; i < 16; i++) {
791 df |= (mi ^ sb ^ cy) & ma;
792 cy = ((sb & cy) | (~mi & (sb | cy))) & ma;
793 if (i == 11) flag_h = (cy != 0);
794 if (i == 14) c14 = (cy != 0);
795 if (i == 15) flag_c = (cy != 0);
796 cy <<= 1;
797 ma <<= 1;
798 }
799 flag_n = 1;
800 flag_v = flag_c ^ c14;
801 flag_x = ((df & 0x0800) != 0);
802 flag_y = ((df & 0x2000) != 0);
803 flag_z = (df == 0);
804 flag_s = ((df & 0x8000) != 0);
805 return df;
806 }
807
808
809 /*
810 * 8-bit increment
811 */
812 static void
inst_inr(void)813 inst_inr(void) {
814 unsigned char *dp;
815 /*
816 * doesn't affect carry flag
817 */
818 int old_c = flag_c;
819 dp = operand8((opcode >> 3) & 0x07, 0);
820 *dp = add8(*dp, 1, 0);
821 flag_c = old_c;
822 }
823
824
825 /*
826 * 16-bit increment
827 */
828 static void
inst_inx(void)829 inst_inx(void) {
830 switch (opcode & 0x30) {
831 case 0x00: set_bc((get_bc() + 1) & 0xffff); break;
832 case 0x10: set_de((get_de() + 1) & 0xffff); break;
833 case 0x20:
834 switch (prefix) {
835 case 0x00: set_hl((get_hl() + 1) & 0xffff); break;
836 case 0xdd: set_ix((get_ix() + 1) & 0xffff); break;
837 case 0xfd: set_iy((get_iy() + 1) & 0xffff); break;
838 }
839 break;
840 case 0x30: reg_sp = ((reg_sp + 1) & 0xffff); break;
841 }
842 }
843
844
845 /*
846 * 8-bit decrement
847 */
848 static void
inst_dcr(void)849 inst_dcr(void) {
850 unsigned char *dp;
851 /*
852 * doesn't affect carry flag
853 */
854 int old_c = flag_c;
855 dp = operand8((opcode >> 3) & 0x07, 0);
856 *dp = sub8(*dp, 1, 0);
857 flag_c = old_c;
858 }
859
860
861 /*
862 * 16-bit decrement
863 */
864 static void
inst_dcx(void)865 inst_dcx(void) {
866 switch (opcode & 0x30) {
867 case 0x00: set_bc((get_bc() + 0xffff) & 0xffff); break;
868 case 0x10: set_de((get_de() + 0xffff) & 0xffff); break;
869 case 0x20:
870 switch (prefix) {
871 case 0x00: set_hl((get_hl() + 0xffff) & 0xffff); break;
872 case 0xdd: set_ix((get_ix() + 0xffff) & 0xffff); break;
873 case 0xfd: set_iy((get_iy() + 0xffff) & 0xffff); break;
874 }
875 break;
876 case 0x30: reg_sp = ((reg_sp + 0xffff) & 0xffff); break;
877 }
878 }
879
880
881 /*
882 * 16-bit addition without carry
883 */
884 static void
inst_dad(void)885 inst_dad(void) {
886 /*
887 * flags S, Z, and P are not modified
888 */
889 int old_s = flag_s, old_z = flag_z, old_p = flag_p;
890 unsigned s = 0;
891 switch (opcode & 0x30) {
892 case 0x00: s = get_bc(); break;
893 case 0x10: s = get_de(); break;
894 case 0x20:
895 switch (prefix) {
896 case 0x00: s = get_hl(); break;
897 case 0xdd: s = get_ix(); break;
898 case 0xfd: s = get_iy(); break;
899 }
900 break;
901 case 0x30: s = reg_sp; break;
902 }
903 switch (prefix) {
904 case 0x00:
905 internal = get_hl();
906 set_hl(add16(internal, s, 0));
907 break;
908 case 0xdd:
909 internal = get_ix();
910 set_ix(add16(internal, s, 0));
911 break;
912 case 0xfd:
913 internal = get_iy();
914 set_iy(add16(internal, s, 0));
915 break;
916 }
917 flag_s = old_s;
918 flag_z = old_z;
919 flag_p = old_p;
920 }
921
922
923 /*
924 * calculate parity of a byte (even number of bits: 1, odd number of bits: 0)
925 */
926 static int
parity(unsigned char byte)927 parity(unsigned char byte) {
928 int p = 1;
929 while (byte) {
930 p ^= (byte & 0x01);
931 byte >>= 1;
932 }
933 return p;
934 }
935
936
937 /*
938 * adjust A for BCD arithmetic after addition or subtraction
939 */
940 static void
inst_daa(void)941 inst_daa(void) {
942 int high = (reg_a >> 4) & 0x0f, low = reg_a & 0x0f, new_c, new_h;
943 unsigned char diff;
944 /*
945 * calculate adjustment byte for A
946 */
947 if (flag_c) {
948 if (low < 0xa) {
949 diff = flag_h ? 0x66 : 0x60;
950 } else {
951 diff = 0x66;
952 }
953 } else {
954 if (low < 0xa) {
955 if (high < 0xa) {
956 diff = flag_h ? 0x06 : 0x00;
957 } else {
958 diff = flag_h ? 0x66 : 0x60;
959 }
960 } else {
961 diff = (high < 0x9) ? 0x06 : 0x66;
962 }
963 }
964 /*
965 * calculate new C flag
966 */
967 if (flag_c) {
968 new_c = 1;
969 } else {
970 if (low < 0xa) {
971 new_c = (high < 0xa) ? 0 : 1;
972 } else {
973 new_c = (high < 0x9) ? 0 : 1;
974 }
975 }
976 /*
977 * calculate new H flag
978 */
979 if (flag_n) {
980 if (flag_h) {
981 new_h = (low < 0x6) ? 1 : 0;
982 } else {
983 new_h = 0;
984 }
985 } else {
986 new_h = (low < 0xa) ? 0 : 1;
987 }
988 /*
989 * adjust A, set flags S, Z, Y, X, and N
990 */
991 reg_a = flag_n ? sub8(reg_a, diff, 0) : add8(reg_a, diff, 0);
992 /*
993 * set P/V flag from parity of A
994 */
995 flag_p = parity(reg_a);
996 /*
997 * set flags C and H calculated above
998 */
999 flag_c = new_c;
1000 flag_h = new_h;
1001 }
1002
1003
1004 /*
1005 * 8-bit add to A
1006 */
1007 static void
inst_add(void)1008 inst_add(void) { reg_a = add8(reg_a, *operand8(opcode & 0x07, 0), 0); }
1009
1010
1011 /*
1012 * 8-bit add to A immediate
1013 */
1014 static void
inst_adi(void)1015 inst_adi(void) { reg_a = add8(reg_a, op_low, 0); }
1016
1017
1018 /*
1019 * 8-bit add with carry to A
1020 */
1021 static void
inst_adc(void)1022 inst_adc(void) { reg_a = add8(reg_a, *operand8(opcode & 0x07, 0), flag_c); }
1023
1024
1025 /*
1026 * 8-bit add with carry to A immediate
1027 */
1028 static void
inst_aci(void)1029 inst_aci(void) { reg_a = add8(reg_a, op_low, flag_c); }
1030
1031
1032 /*
1033 * 8-bit subtract from A
1034 */
1035 static void
inst_sub(void)1036 inst_sub(void) { reg_a = sub8(reg_a, *operand8(opcode & 0x07, 0), 0); }
1037
1038
1039 /*
1040 * 8-bit subtract from A immediate
1041 */
1042 static void
inst_sui(void)1043 inst_sui(void) { reg_a = sub8(reg_a, op_low, 0); }
1044
1045
1046 /*
1047 * 8-bit subtract with borrow from A
1048 */
1049 static void
inst_sbca(void)1050 inst_sbca(void) { reg_a = sub8(reg_a, *operand8(opcode & 0x07, 0), flag_c); }
1051
1052
1053 /*
1054 * 8-bit subtract with borrow from A immediate
1055 */
1056 static void
inst_sbi(void)1057 inst_sbi(void) { reg_a = sub8(reg_a, op_low, flag_c); }
1058
1059
1060 /*
1061 * 8-bit compare to A
1062 */
1063 static void
inst_cmp(void)1064 inst_cmp(void) {
1065 unsigned char op = *operand8(opcode & 0x07, 0);
1066 sub8(reg_a, op, 0);
1067 flag_x = ((op & 0x08) == 0x08);
1068 flag_y = ((op & 0x20) == 0x20);
1069 }
1070
1071
1072 /*
1073 * 8-bit compare to A immediate
1074 */
1075 static void
inst_cmpi(void)1076 inst_cmpi(void) {
1077 sub8(reg_a, op_low, 0);
1078 flag_x = ((op_low & 0x08) == 0x08);
1079 flag_y = ((op_low & 0x20) == 0x20);
1080 }
1081
1082
1083 /*
1084 * set flags after inst_and/ani/or/ori/xor/xri()
1085 */
1086 static void
log_flags(void)1087 log_flags(void) {
1088 flag_s = ((reg_a & 0x80) == 0x80);
1089 flag_z = reg_a ? 0 : 1;
1090 flag_y = ((reg_a & 0x20) == 0x20);
1091 flag_x = ((reg_a & 0x08) == 0x08);
1092 flag_p = parity(reg_a);
1093 flag_n = 0;
1094 flag_c = 0;
1095 }
1096
1097
1098 /*
1099 * logical and with A
1100 */
1101 static void
inst_and(void)1102 inst_and(void) {
1103 reg_a &= *operand8(opcode & 0x07, 0);
1104 flag_h = 1;
1105 log_flags();
1106 }
1107
1108
1109 /*
1110 * logical and with A immediate
1111 */
1112 static void
inst_ani(void)1113 inst_ani(void) {
1114 reg_a &= op_low;
1115 flag_h = 1;
1116 log_flags();
1117 }
1118
1119
1120 /*
1121 * logical or with A
1122 */
1123 static void
inst_or(void)1124 inst_or(void) {
1125 reg_a |= *operand8(opcode & 0x07, 0);
1126 flag_h = 0;
1127 log_flags();
1128 }
1129
1130
1131 /*
1132 * logical or with A immediate
1133 */
1134 static void
inst_ori(void)1135 inst_ori(void) {
1136 reg_a |= op_low;
1137 flag_h = 0;
1138 log_flags();
1139 }
1140
1141
1142 /*
1143 * logical xor with A
1144 */
1145 static void
inst_xor(void)1146 inst_xor(void) {
1147 reg_a ^= *operand8(opcode & 0x07, 0);
1148 flag_h = 0;
1149 log_flags();
1150 }
1151
1152
1153 /*
1154 * logical xor with A immediate
1155 */
1156 static void
inst_xri(void)1157 inst_xri(void) {
1158 reg_a ^= op_low;
1159 flag_h = 0;
1160 log_flags();
1161 }
1162
1163
1164 /*
1165 * unconditional jump
1166 */
1167 static void
inst_jp(void)1168 inst_jp(void) {
1169 reg_pc = op_high;
1170 reg_pc <<= 8;
1171 reg_pc |= op_low;
1172 }
1173
1174
1175 /*
1176 * common part of ret, ret cc, and retn
1177 */
1178 static void
do_ret(void)1179 do_ret(void) {
1180 reg_pc = pop();
1181 }
1182
1183
1184 /*
1185 * unconditional return
1186 */
1187 static void
inst_ret(void)1188 inst_ret(void) {
1189 /*
1190 * handle magic addresses for BDOS and BIOS calls
1191 */
1192 if (current_instruction >= MAGIC_ADDRESS) {
1193 os_call(current_instruction - MAGIC_ADDRESS);
1194 }
1195 do_ret();
1196 }
1197
1198
1199 /*
1200 * unconditional call
1201 */
1202 static void
inst_call(void)1203 inst_call(void) {
1204 push(reg_pc);
1205 inst_jp();
1206 }
1207
1208
1209 /*
1210 * restart
1211 */
1212 static void
inst_rst(void)1213 inst_rst(void) {
1214 push(reg_pc);
1215 reg_pc = (opcode & 0x38);
1216 }
1217
1218
1219 /*
1220 * return true if condition from jp cc, call cc, or ret cc is met
1221 */
1222 static int
condition_met(void)1223 condition_met(void) {
1224 switch (opcode & 0x38) {
1225 case 0x00: return (! flag_z);
1226 case 0x08: return flag_z;
1227 case 0x10: return (! flag_c);
1228 case 0x18: return flag_c;
1229 case 0x20: return (! flag_p);
1230 case 0x28: return flag_p;
1231 case 0x30: return (! flag_s);
1232 default /* case 0x38 */: return flag_s;
1233 }
1234 }
1235
1236
1237 /*
1238 * conditional jump
1239 */
1240 static void
inst_jpcc(void)1241 inst_jpcc(void) { if (condition_met()) inst_jp(); }
1242
1243
1244 /*
1245 * conditional return
1246 */
1247 static void
inst_retcc(void)1248 inst_retcc(void) { if (condition_met()) do_ret(); }
1249
1250
1251 /*
1252 * conditional call
1253 */
1254 static void
inst_callcc(void)1255 inst_callcc(void) { if (condition_met()) inst_call(); }
1256
1257
1258 /*
1259 * push word register to stack
1260 */
1261 static void
inst_push(void)1262 inst_push(void) {
1263 int word;
1264 switch (opcode & 0x30) {
1265 /*
1266 * BC
1267 */
1268 case 0x00: word = get_bc(); break;
1269 /*
1270 * DE
1271 */
1272 case 0x10: word = get_de(); break;
1273 case 0x20:
1274 switch (prefix) {
1275 /*
1276 * IX
1277 */
1278 case 0xdd: word = get_ix(); break;
1279 /*
1280 * IY
1281 */
1282 case 0xfd: word = get_iy(); break;
1283 /*
1284 * HL
1285 */
1286 default: word = get_hl(); break;
1287 }
1288 break;
1289 default:
1290 /*
1291 * AF
1292 */
1293 word = reg_a;
1294 word <<= 8;
1295 if (flag_s) word |= 0x80;
1296 if (flag_z) word |= 0x40;
1297 if (flag_y) word |= 0x20;
1298 if (flag_h) word |= 0x10;
1299 if (flag_x) word |= 0x08;
1300 if (flag_p) word |= 0x04;
1301 if (flag_n) word |= 0x02;
1302 if (flag_c) word |= 0x01;
1303 break;
1304 }
1305 push(word);
1306 }
1307
1308
1309 /*
1310 * pop word register from stack
1311 */
1312 static void
inst_pop(void)1313 inst_pop(void) {
1314 int word = pop();
1315 switch (opcode & 0x30) {
1316 /*
1317 * BC
1318 */
1319 case 0x00: set_bc(word); break;
1320 /*
1321 * DE
1322 */
1323 case 0x10: set_de(word); break;
1324 case 0x20:
1325 switch (prefix) {
1326 /*
1327 * IX
1328 */
1329 case 0xdd: set_ix(word); break;
1330 /*
1331 * IY
1332 */
1333 case 0xfd: set_iy(word); break;
1334 /*
1335 * HL
1336 */
1337 default: set_hl(word); break;
1338 }
1339 break;
1340 default:
1341 /*
1342 * AF
1343 */
1344 reg_a = ((word >> 8) & 0xff);
1345 flag_s = ((word & 0x80) == 0x80);
1346 flag_z = ((word & 0x40) == 0x40);
1347 flag_y = ((word & 0x20) == 0x20);
1348 flag_h = ((word & 0x10) == 0x10);
1349 flag_x = ((word & 0x08) == 0x08);
1350 flag_p = ((word & 0x04) == 0x04);
1351 flag_n = ((word & 0x02) == 0x02);
1352 flag_c = ((word & 0x01) == 0x01);
1353 break;
1354 }
1355
1356 }
1357
1358
1359 /*
1360 * exchange word registers
1361 */
1362 static void
inst_exx(void)1363 inst_exx(void) {
1364 unsigned char uc;
1365 uc = reg_b; reg_b = alt_reg_b; alt_reg_b = uc;
1366 uc = reg_c; reg_c = alt_reg_c; alt_reg_c = uc;
1367 uc = reg_d; reg_d = alt_reg_d; alt_reg_d = uc;
1368 uc = reg_e; reg_e = alt_reg_e; alt_reg_e = uc;
1369 uc = reg_h; reg_h = alt_reg_h; alt_reg_h = uc;
1370 uc = reg_l; reg_l = alt_reg_l; alt_reg_l = uc;
1371 }
1372
1373
1374 /*
1375 * exchange DE and HL
1376 */
1377 static void
inst_xchg(void)1378 inst_xchg(void) {
1379 unsigned char uc;
1380 uc = reg_h; reg_h = reg_d; reg_d = uc;
1381 uc = reg_l; reg_l = reg_e; reg_e = uc;
1382 }
1383
1384
1385 /*
1386 * exchange HL, IX, or IY with top of stack
1387 */
1388 static void
inst_xthl(void)1389 inst_xthl(void) {
1390 unsigned char *rlp, *rhp, *slp, *shp, uc;
1391 switch (prefix) {
1392 case 0xdd: rhp = ®_ixh; rlp = ®_ixl; break;
1393 case 0xfd: rhp = ®_iyh; rlp = ®_iyl; break;
1394 default: rhp = ®_h; rlp = ®_l; break;
1395 }
1396 slp = memory + reg_sp;
1397 shp = memory + ((reg_sp + 1) & 0xffff);
1398 uc = *slp; *slp = *rlp; *rlp = uc;
1399 uc = *shp; *shp = *rhp; *rhp = uc;
1400 }
1401
1402
1403 /*
1404 * jump to address in HL, IX, or IY
1405 */
1406 static void
inst_pchl(void)1407 inst_pchl(void) {
1408 switch (prefix) {
1409 case 0xdd: reg_pc = get_ix(); break;
1410 case 0xfd: reg_pc = get_iy(); break;
1411 default: reg_pc = get_hl(); break;
1412 }
1413 }
1414
1415
1416 /*
1417 * set SP to address in HL, IX, or IY
1418 */
1419 static void
inst_sphl(void)1420 inst_sphl(void) {
1421 switch (prefix) {
1422 case 0xdd: reg_sp = get_ix(); break;
1423 case 0xfd: reg_sp = get_iy(); break;
1424 default: reg_sp = get_hl(); break;
1425 }
1426 }
1427
1428
1429 /*
1430 * get byte from port to A
1431 */
1432 static void
inst_ina(void)1433 inst_ina(void) {
1434 reg_a = 0x00;
1435 }
1436
1437
1438 /*
1439 * put byte in A to port
1440 */
1441 static void
inst_outa(void)1442 inst_outa(void) { }
1443
1444
1445 /*
1446 * enable interrupts
1447 */
1448 static void
inst_ei(void)1449 inst_ei(void) {
1450 flag_i = 1;
1451 }
1452
1453
1454 /*
1455 * disable interrupts
1456 */
1457 static void
inst_di(void)1458 inst_di(void) {
1459 flag_i = 0;
1460 }
1461
1462
1463 /*
1464 * same as operand8(), but for I/O instructions: no modification by
1465 * prefixes, and code 6 doesn't reference (HL)
1466 */
1467 static unsigned char *
io_operand(int n)1468 io_operand(int n) {
1469 switch (n) {
1470 case 0: return ®_b;
1471 case 1: return ®_c;
1472 case 2: return ®_d;
1473 case 3: return ®_e;
1474 case 4: return ®_h;
1475 case 5: return ®_l;
1476 case 6: return NULL;
1477 default: return ®_a;
1478 }
1479 }
1480
1481
1482 /*
1483 * IN r,(C) (dummy, always reads 0)
1484 */
1485 static void
inst_inc(void)1486 inst_inc(void) {
1487 unsigned char *dp = io_operand((opcode2 >> 3) & 0x07);
1488 if (dp) *dp = 0;
1489 flag_s = 0; /* result 0 */
1490 flag_z = 1; /* result 0 */
1491 flag_y = 0; /* result 0 */
1492 flag_h = 0;
1493 flag_x = 0; /* result 0 */
1494 flag_p = 0; /* result 0 */
1495 flag_n = 0;
1496 }
1497
1498
1499 /*
1500 * OUT (C), r (dummy, doesn't do anything)
1501 */
1502 static void
inst_outc(void)1503 inst_outc(void) { }
1504
1505
1506 /*
1507 * decrease PC by two (used for LDIR/LDDR/CPIR/CPDR/INIR/INDR/OTIR/OTDR)
1508 */
1509 static void
repeat_block(void)1510 repeat_block(void) {
1511 reg_pc = ((reg_pc + 0xfffe) & 0xffff);
1512 }
1513
1514
1515 /*
1516 * OUTI (dummy apart from its side effects, which are strange)
1517 */
1518 static void
inst_outi(void)1519 inst_outi(void) {
1520 int hl = get_hl(), k = memory[hl], new_n, new_c, new_h, new_p;
1521 set_hl((hl + 1) & 0xffff);
1522 new_n = ((k & 0x80) == 0x80);
1523 k += reg_l;
1524 new_c = new_h = (k > 255);
1525 new_p = parity((k & 7) ^ reg_b);
1526 reg_b = sub8(reg_b, 1, 0);
1527 flag_c = new_c;
1528 flag_n = new_n;
1529 flag_p = new_p;
1530 flag_h = new_h;
1531 }
1532
1533
1534 /*
1535 * OTIR (like OUTI, but decrease PC by two if B != 0
1536 */
1537 static void
inst_otir(void)1538 inst_otir(void) {
1539 inst_outi();
1540 if (reg_b) repeat_block();
1541 }
1542
1543
1544 /*
1545 * OUTD (dummy apart from its side effects, which are strange)
1546 */
1547 static void
inst_outd(void)1548 inst_outd(void) {
1549 int hl = get_hl(), k = memory[hl], new_n, new_c, new_h, new_p;
1550 set_hl((hl + 0xffff) & 0xffff);
1551 new_n = ((k & 0x80) == 0x80);
1552 k += reg_l;
1553 new_c = new_h = (k > 255);
1554 new_p = parity((k & 7) ^ reg_b);
1555 reg_b = sub8(reg_b, 1, 0);
1556 flag_c = new_c;
1557 flag_n = new_n;
1558 flag_p = new_p;
1559 flag_h = new_h;
1560 }
1561
1562
1563 /*
1564 * OTDR (like OUTD, but decrease PC by two if B != 0
1565 */
1566 static void
inst_otdr(void)1567 inst_otdr(void) {
1568 inst_outd();
1569 if (reg_b) repeat_block();
1570 }
1571
1572
1573 /*
1574 * INI (dummy apart from its side effects, which are strange)
1575 */
1576 static void
inst_ini(void)1577 inst_ini(void) {
1578 int hl = get_hl(), k = 0, new_n, new_c, new_h, new_p;
1579 memory[hl] = k;
1580 set_hl((hl + 1) & 0xffff);
1581 new_n = ((k & 0x80) == 0x80);
1582 k += (reg_c + 1) & 0xff;
1583 new_c = new_h = (k > 255);
1584 new_p = parity((k & 7) ^ reg_b);
1585 reg_b = sub8(reg_b, 1, 0);
1586 flag_c = new_c;
1587 flag_n = new_n;
1588 flag_p = new_p;
1589 flag_h = new_h;
1590 }
1591
1592
1593 /*
1594 * INIR (like INI, but decrease PC by two if B != 0
1595 */
1596 static void
inst_inir(void)1597 inst_inir(void) {
1598 inst_ini();
1599 if (reg_b) repeat_block();
1600 }
1601
1602
1603 /*
1604 * IND (dummy apart from its side effects, which are strange)
1605 */
1606 static void
inst_ind(void)1607 inst_ind(void) {
1608 int hl = get_hl(), k = 0, new_n, new_c, new_h, new_p;
1609 memory[hl] = k;
1610 set_hl((hl + 0xffff) & 0xffff);
1611 new_n = ((k & 0x80) == 0x80);
1612 k += reg_c ? 0xff : reg_c - 1;
1613 new_c = new_h = (k > 255);
1614 new_p = parity((k & 7) ^ reg_b);
1615 reg_b = sub8(reg_b, 1, 0);
1616 flag_c = new_c;
1617 flag_n = new_n;
1618 flag_p = new_p;
1619 flag_h = new_h;
1620 }
1621
1622
1623 /*
1624 * INDR (like IND, but decrease PC by two if B != 0
1625 */
1626 static void
inst_indr(void)1627 inst_indr(void) {
1628 inst_ind();
1629 if (reg_b) repeat_block();
1630 }
1631
1632
1633 /*
1634 * NEG
1635 */
1636 static void
inst_neg(void)1637 inst_neg(void) {
1638 reg_a = sub8(0, reg_a, 0);
1639 }
1640
1641
1642 /*
1643 * RETN and RETI do the same (which is in this implementation the same
1644 * as a simple RET, since there is no NMI and no IFF2
1645 */
1646 static void
inst_retn(void)1647 inst_retn(void) {
1648 do_ret();
1649 }
1650
1651
1652 /*
1653 * IM 0/1/2 are dummies, since there are no interrupts in this
1654 * implementation
1655 */
1656 static void
inst_im0(void)1657 inst_im0(void) { }
1658
1659
1660 static void
inst_im1(void)1661 inst_im1(void) { }
1662
1663
1664 static void
inst_im2(void)1665 inst_im2(void) { }
1666
1667
1668 /*
1669 * set flags for LD A,I and LD A,R
1670 */
1671 static void
ldair_flags(void)1672 ldair_flags(void) {
1673 flag_s = ((reg_a & 0x80) == 0x80);
1674 flag_z = (reg_a == 0);
1675 flag_y = ((reg_a & 0x20) == 0x20);
1676 flag_h = 0;
1677 flag_x = ((reg_a & 0x08) == 0x08);
1678 flag_p = flag_i;
1679 flag_n = 0;
1680 }
1681
1682
1683 /*
1684 * LD A,I
1685 */
1686 static void
inst_ldai(void)1687 inst_ldai(void) {
1688 reg_a = reg_i;
1689 ldair_flags();
1690 }
1691
1692
1693 /*
1694 * LD I,A
1695 */
1696 static void
inst_ldia(void)1697 inst_ldia(void) {
1698 reg_i = reg_a;
1699 }
1700
1701
1702 /*
1703 * LD A,R
1704 */
1705 static void
inst_ldar(void)1706 inst_ldar(void) {
1707 reg_a = reg_r;
1708 ldair_flags();
1709 }
1710
1711
1712 /*
1713 * LD R,A
1714 */
1715 static void
inst_ldra(void)1716 inst_ldra(void) {
1717 reg_r = reg_a;
1718 }
1719
1720
1721 /*
1722 * ADC HL,rr
1723 */
1724 static void
inst_adchl(void)1725 inst_adchl(void) {
1726 unsigned value;
1727 internal = get_hl();
1728 switch (opcode2 & 0x30) {
1729 case 0x00: value = get_bc(); break;
1730 case 0x10: value = get_de(); break;
1731 case 0x20: value = internal; break;
1732 default: value = reg_sp; break;
1733 }
1734 set_hl(add16(internal, value, flag_c));
1735 }
1736
1737
1738 /*
1739 * SBC HL,rr
1740 */
1741 static void
inst_sbchl(void)1742 inst_sbchl(void) {
1743 unsigned value;
1744 internal = get_hl();
1745 switch (opcode2 & 0x30) {
1746 case 0x00: value = get_bc(); break;
1747 case 0x10: value = get_de(); break;
1748 case 0x20: value = internal; break;
1749 default: value = reg_sp; break;
1750 }
1751 set_hl(sub16(internal, value, flag_c));
1752 }
1753
1754
1755 /*
1756 * common part of LDI and LDD
1757 */
1758 static void
ldx(int up)1759 ldx(int up) {
1760 int hl, de, bc, t;
1761 bc = get_bc();
1762 de = get_de();
1763 hl = get_hl();
1764 t = memory[de] = memory[hl];
1765 t += reg_a;
1766 if (up) {
1767 hl = ((hl + 1) & 0xffff);
1768 de = ((de + 1) & 0xffff);
1769 } else {
1770 hl = ((hl + 0xffff) & 0xffff);
1771 de = ((de + 0xffff) & 0xffff);
1772 }
1773 bc = ((bc + 0xffff) & 0xffff);
1774 set_bc(bc);
1775 set_de(de);
1776 set_hl(hl);
1777 flag_y = (t & 0x02) == 0x02;
1778 flag_h = 0;
1779 flag_x = (t & 0x08) == 0x08;
1780 flag_p = (bc != 0);
1781 flag_n = 0;
1782 }
1783
1784
1785 /*
1786 * LDI
1787 */
1788 static void
inst_ldi(void)1789 inst_ldi(void) { ldx(1); }
1790
1791
1792 /*
1793 * LDIR (repeats LDI until P is clear, i. e. BC == 0)
1794 */
1795 static void
inst_ldir(void)1796 inst_ldir(void) {
1797 inst_ldi();
1798 if (flag_p) repeat_block();
1799 }
1800
1801
1802 /*
1803 * LDD
1804 */
1805 static void
inst_ldd(void)1806 inst_ldd(void) { ldx(0); }
1807
1808
1809 /*
1810 * LDDR (repeats LDD until P is clear, i. e. BC == 0)
1811 */
1812 static void
inst_lddr(void)1813 inst_lddr(void) {
1814 inst_ldd();
1815 if (flag_p) repeat_block();
1816 }
1817
1818
1819 /*
1820 * common part of CPI and CPD
1821 */
1822 static void
cpx(int up)1823 cpx(int up) {
1824 int hl, bc, t, old_c;
1825 old_c = flag_c;
1826 bc = get_bc();
1827 hl = get_hl();
1828 t = sub8(reg_a, memory[hl], 0);
1829 t += flag_h;
1830 hl = up ? ((hl + 1) & 0xffff) : ((hl + 0xffff) & 0xffff);
1831 bc = ((bc + 0xffff) & 0xffff);
1832 set_bc(bc);
1833 set_hl(hl);
1834 flag_y = ((t & 0x02) == 0x02);
1835 flag_x = ((t & 0x08) == 0x08);
1836 flag_p = (bc != 0);
1837 flag_c = old_c;
1838 }
1839
1840
1841 /*
1842 * CPI
1843 */
1844 static void
inst_cpi(void)1845 inst_cpi(void) { cpx(1); }
1846
1847
1848 /*
1849 * CPIR (repeats CPI until P is clear, i. e. BC == 0)
1850 */
1851 static void
inst_cpir(void)1852 inst_cpir(void) {
1853 inst_cpi();
1854 if (flag_p && ! flag_z) repeat_block();
1855 }
1856
1857
1858 /*
1859 * CPD
1860 */
1861 static void
inst_cpd(void)1862 inst_cpd(void) { cpx(0); }
1863
1864
1865 /*
1866 * CPDR (repeats CPD until P is clear, i. e. BC == 0)
1867 */
1868 static void
inst_cpdr(void)1869 inst_cpdr(void) {
1870 inst_cpd();
1871 if (flag_p && ! flag_z) repeat_block();
1872 }
1873
1874
1875 /*
1876 * LD rr,(nn)
1877 */
1878 static void
inst_lrrd(void)1879 inst_lrrd(void) {
1880 int t;
1881 t = op_high;
1882 t <<= 8;
1883 t |= op_low;
1884 t = get_word(t);
1885 switch (opcode2 & 0x30) {
1886 case 0x00: set_bc(t); break;
1887 case 0x10: set_de(t); break;
1888 case 0x20: set_hl(t); break;
1889 default: reg_sp = t; break;
1890 }
1891 }
1892
1893
1894 /*
1895 * LD (nn),rr
1896 */
1897 static void
inst_srrd(void)1898 inst_srrd(void) {
1899 int t;
1900 t = op_high;
1901 t <<= 8;
1902 t |= op_low;
1903 switch (opcode2 & 0x30) {
1904 case 0x00: set_word(t, get_bc()); break;
1905 case 0x10: set_word(t, get_de()); break;
1906 case 0x20: set_word(t, get_hl()); break;
1907 default: set_word(t, reg_sp); break;
1908 }
1909 }
1910
1911
1912 /*
1913 * helper function to set the flags after Z80 (as opposed to
1914 * 8080) specific shift and rotate operations
1915 */
1916 static void
shift_flags(unsigned char data)1917 shift_flags(unsigned char data) {
1918 flag_s = ((data & 0x80) == 0x80);
1919 flag_z = (data == 0x00);
1920 flag_y = ((data & 0x20) == 0x20);
1921 flag_h = 0;
1922 flag_x = ((data & 0x08) == 0x08);
1923 flag_p = parity(data);
1924 flag_n = 0;
1925 }
1926
1927
1928 /*
1929 * RLD
1930 */
1931 static void
inst_rld(void)1932 inst_rld(void) {
1933 int t, hl = get_hl();
1934 t = memory[hl];
1935 memory[hl] = ((t << 4) & 0xf0) | (reg_a & 0x0f);
1936 reg_a = (reg_a & 0xf0) | ((t >> 4) & 0xf);
1937 shift_flags(reg_a);
1938 }
1939
1940
1941 /*
1942 * RRD
1943 */
1944 static void
inst_rrd(void)1945 inst_rrd(void) {
1946 int t, hl = get_hl();
1947 t = memory[hl];
1948 memory[hl] = ((t >> 4) & 0x0f) | ((reg_a << 4) & 0x0f);
1949 reg_a = (reg_a & 0xf0) | (t & 0xf);
1950 shift_flags(reg_a);
1951 }
1952
1953
1954 /*
1955 * RLC/RRC/RL/RR/SLA/SRA/SLL/SRL/BIT/RES/SET
1956 *
1957 * two-byte opcodes starting in 0xcb; there are only 11 separate
1958 * instructions with a very similar structure, so this doesn't merit
1959 * a separate dispatch table.
1960 */
1961 static void
inst_cb(void)1962 inst_cb(void) {
1963 int r = (opcode2 & 0x07), temp;
1964 unsigned char *op1, *op2, byte;
1965 if (prefix) {
1966 /*
1967 * if there is a prefix, the source and one destination
1968 * operand is always an indexed memory location
1969 */
1970 op1 = operand8(6, 0);
1971 /*
1972 * only a register can be the other destination operand
1973 * and it is never i[xy][lh].
1974 */
1975 op2 = (r == 6) ? NULL : operand8(r, 6);
1976 } else {
1977 /*
1978 * without a prefix there is only one operand (both
1979 * source and destination)
1980 */
1981 op1 = operand8(r, 0);
1982 op2 = NULL;
1983 }
1984 byte = *op1;
1985 switch (opcode2 & 0xc0) {
1986 case 0x00:
1987 /*
1988 * shift and rotate instructions
1989 */
1990 switch (opcode2 & 0x38) {
1991 case 0x00:
1992 /*
1993 * RLC: 8-bit rotate left
1994 */
1995 flag_c = ((byte & 0x80) == 0x80);
1996 byte = (((byte << 1) | flag_c) & 0xff);
1997 break;
1998 case 0x08:
1999 /*
2000 * RRC: 8-bit rotate right
2001 */
2002 flag_c = ((byte & 0x01) == 0x01);
2003 byte = (((byte >> 1) | (flag_c ? 0x80 : 0x00)) & 0xff);
2004 break;
2005 case 0x10:
2006 /*
2007 * RL: 9-bit rotate left
2008 */
2009 temp = ((byte & 0x80) == 0x80);
2010 byte = (((byte << 1) | flag_c) & 0xff);
2011 flag_c = temp;
2012 break;
2013 case 0x18:
2014 /*
2015 * RR: 9-bit rotate right
2016 */
2017 temp = ((byte & 0x01) == 0x01);
2018 byte = (((byte >> 1) | (flag_c ? 0x80 : 0x00)) & 0xff);
2019 flag_c = temp;
2020 break;
2021 case 0x20:
2022 /*
2023 * SLA: arithmetical (and logical) left shift
2024 */
2025 flag_c = ((byte & 0x80) == 0x80);
2026 byte = ((byte << 1) & 0xfe);
2027 break;
2028 case 0x28:
2029 /*
2030 * SRA: arithmetical right shift
2031 */
2032 temp = (byte & 0x80);
2033 flag_c = ((byte & 0x01) == 0x01);
2034 byte = (((byte >> 1) | temp)) & 0xff;
2035 break;
2036 case 0x30:
2037 /*
2038 * SLL: like SLA, but shifts in 1
2039 */
2040 flag_c = ((byte & 0x80) == 0x80);
2041 byte = (((byte << 1) | 0x01) & 0xff);
2042 break;
2043 case 0x38:
2044 /*
2045 * SRL: logical right shift
2046 */
2047 flag_c = ((byte & 0x01) == 0x01);
2048 byte = ((byte >> 1) & 0x7f);
2049 break;
2050 }
2051 shift_flags(byte);
2052 break;
2053 case 0x40:
2054 /*
2055 * BIT
2056 */
2057 byte &= (1 << ((opcode2 >> 3) & 0x07));
2058 flag_n = 0;
2059 flag_p = flag_z = (byte == 0);
2060 flag_h = 1;
2061 flag_s = ((byte & 0x80) == 0x80);
2062 /*
2063 * flags X and Y have complicated rules in this instructon
2064 */
2065 if (r == 6) {
2066 flag_x = ((internal & 0x0800) == 0x0800);
2067 flag_y = ((internal & 0x2000) == 0x2000);
2068 } else {
2069 flag_x = ((byte & 0x08) == 0x08);
2070 flag_y = ((byte & 0x20) == 0x20);
2071 }
2072 /*
2073 * no operand is modified by BIT
2074 */
2075 goto no_save;
2076 case 0x80:
2077 /*
2078 * RES
2079 */
2080 byte &= ~(1 << ((opcode2 >> 3) & 0x07));
2081 break;
2082 case 0xc0:
2083 /*
2084 * SET
2085 */
2086 byte |= 1 << ((opcode2 >> 3) & 0x07);
2087 break;
2088 }
2089 *op1 = byte;
2090 if (op2) *op2 = byte;
2091 no_save:
2092 return;
2093 }
2094
2095
2096 /*
2097 * operand/displacement fetch
2098 */
2099 static inline int
fetch(void)2100 fetch(void) {
2101 int byte;
2102 byte = memory[reg_pc];
2103 reg_pc = ((reg_pc + 1) & 0xffff);
2104 return byte;
2105 }
2106
2107
2108 /*
2109 * opcode/prefix fetch: increase R
2110 */
2111 static inline int
fetch_m1(void)2112 fetch_m1(void) {
2113 int t = reg_r;
2114 int opcode = fetch();
2115 /*
2116 * increase the lower 7 bits of R by 1, leave bit 7 unchanged
2117 */
2118 reg_r = (t & 0x80) | ((t + 1) & 0x7f);
2119 return opcode;
2120 }
2121
2122
2123 /*
2124 * flags and structures of the instruction dispatch tables
2125 */
2126 enum flags {
2127 OP_0 = 0,
2128 OP_INDEXED = 1, /* indexed addressing */
2129 OP_ARG8 = 2, /* has an 8-bit displacement/operand */
2130 OP_ARG16 = 4 /* has a 16-bit address/operand */
2131 };
2132
2133 struct instruction {
2134 void (*handler_p)(void);
2135 enum flags flags;
2136 };
2137
2138
2139 /*
2140 * dispatcher table for instructions staring in 0xed
2141 */
2142 static const struct instruction ed_plane[256] = {
2143 /*00*/ { inst_nop, OP_0 },
2144 /*01*/ { inst_nop, OP_0 },
2145 /*02*/ { inst_nop, OP_0 },
2146 /*03*/ { inst_nop, OP_0 },
2147 /*04*/ { inst_nop, OP_0 },
2148 /*05*/ { inst_nop, OP_0 },
2149 /*06*/ { inst_nop, OP_0 },
2150 /*07*/ { inst_nop, OP_0 },
2151 /*08*/ { inst_nop, OP_0 },
2152 /*09*/ { inst_nop, OP_0 },
2153 /*0a*/ { inst_nop, OP_0 },
2154 /*0b*/ { inst_nop, OP_0 },
2155 /*0c*/ { inst_nop, OP_0 },
2156 /*0d*/ { inst_nop, OP_0 },
2157 /*0e*/ { inst_nop, OP_0 },
2158 /*0f*/ { inst_nop, OP_0 },
2159 /*10*/ { inst_nop, OP_0 },
2160 /*11*/ { inst_nop, OP_0 },
2161 /*12*/ { inst_nop, OP_0 },
2162 /*13*/ { inst_nop, OP_0 },
2163 /*14*/ { inst_nop, OP_0 },
2164 /*15*/ { inst_nop, OP_0 },
2165 /*16*/ { inst_nop, OP_0 },
2166 /*17*/ { inst_nop, OP_0 },
2167 /*18*/ { inst_nop, OP_0 },
2168 /*19*/ { inst_nop, OP_0 },
2169 /*1a*/ { inst_nop, OP_0 },
2170 /*1b*/ { inst_nop, OP_0 },
2171 /*1c*/ { inst_nop, OP_0 },
2172 /*1d*/ { inst_nop, OP_0 },
2173 /*1e*/ { inst_nop, OP_0 },
2174 /*1f*/ { inst_nop, OP_0 },
2175 /*20*/ { inst_nop, OP_0 },
2176 /*21*/ { inst_nop, OP_0 },
2177 /*22*/ { inst_nop, OP_0 },
2178 /*23*/ { inst_nop, OP_0 },
2179 /*24*/ { inst_nop, OP_0 },
2180 /*25*/ { inst_nop, OP_0 },
2181 /*26*/ { inst_nop, OP_0 },
2182 /*27*/ { inst_nop, OP_0 },
2183 /*28*/ { inst_nop, OP_0 },
2184 /*29*/ { inst_nop, OP_0 },
2185 /*2a*/ { inst_nop, OP_0 },
2186 /*2b*/ { inst_nop, OP_0 },
2187 /*2c*/ { inst_nop, OP_0 },
2188 /*2d*/ { inst_nop, OP_0 },
2189 /*2e*/ { inst_nop, OP_0 },
2190 /*2f*/ { inst_nop, OP_0 },
2191 /*30*/ { inst_nop, OP_0 },
2192 /*31*/ { inst_nop, OP_0 },
2193 /*32*/ { inst_nop, OP_0 },
2194 /*33*/ { inst_nop, OP_0 },
2195 /*34*/ { inst_nop, OP_0 },
2196 /*35*/ { inst_nop, OP_0 },
2197 /*36*/ { inst_nop, OP_0 },
2198 /*37*/ { inst_nop, OP_0 },
2199 /*38*/ { inst_nop, OP_0 },
2200 /*39*/ { inst_nop, OP_0 },
2201 /*3a*/ { inst_nop, OP_0 },
2202 /*3b*/ { inst_nop, OP_0 },
2203 /*3c*/ { inst_nop, OP_0 },
2204 /*3d*/ { inst_nop, OP_0 },
2205 /*3e*/ { inst_nop, OP_0 },
2206 /*3f*/ { inst_nop, OP_0 },
2207 /*40*/ { inst_inc, OP_0 },
2208 /*41*/ { inst_outc, OP_0 },
2209 /*42*/ { inst_sbchl, OP_0 },
2210 /*43*/ { inst_srrd, OP_ARG16 },
2211 /*44*/ { inst_neg, OP_0 },
2212 /*45*/ { inst_retn, OP_0 },
2213 /*46*/ { inst_im0, OP_0 },
2214 /*47*/ { inst_ldia, OP_0 },
2215 /*48*/ { inst_inc, OP_0 },
2216 /*49*/ { inst_outc, OP_0 },
2217 /*4a*/ { inst_adchl, OP_0 },
2218 /*4b*/ { inst_lrrd, OP_ARG16 },
2219 /*4c*/ { inst_neg, OP_0 },
2220 /*4d*/ { inst_retn, OP_0 }, /* reti */
2221 /*4e*/ { inst_im0, OP_0 },
2222 /*4f*/ { inst_ldra, OP_0 },
2223 /*50*/ { inst_inc, OP_0 },
2224 /*51*/ { inst_outc, OP_0 },
2225 /*52*/ { inst_sbchl, OP_0 },
2226 /*53*/ { inst_srrd, OP_ARG16 },
2227 /*54*/ { inst_neg, OP_0 },
2228 /*55*/ { inst_retn, OP_0 },
2229 /*56*/ { inst_im1, OP_0 },
2230 /*57*/ { inst_ldai, OP_0 },
2231 /*58*/ { inst_inc, OP_0 },
2232 /*59*/ { inst_outc, OP_0 },
2233 /*5a*/ { inst_adchl, OP_0 },
2234 /*5b*/ { inst_lrrd, OP_ARG16 },
2235 /*5c*/ { inst_neg, OP_0 },
2236 /*5d*/ { inst_retn, OP_0 },
2237 /*5e*/ { inst_im2, OP_0 },
2238 /*5f*/ { inst_ldar, OP_0 },
2239 /*60*/ { inst_inc, OP_0 },
2240 /*61*/ { inst_outc, OP_0 },
2241 /*62*/ { inst_sbchl, OP_0 },
2242 /*63*/ { inst_srrd, OP_ARG16 },
2243 /*64*/ { inst_neg, OP_0 },
2244 /*65*/ { inst_retn, OP_0 },
2245 /*66*/ { inst_im0, OP_0 },
2246 /*67*/ { inst_rrd, OP_0 },
2247 /*68*/ { inst_inc, OP_0 },
2248 /*69*/ { inst_outc, OP_0 },
2249 /*6a*/ { inst_adchl, OP_0 },
2250 /*6b*/ { inst_lrrd, OP_ARG16 },
2251 /*6c*/ { inst_neg, OP_0 },
2252 /*6d*/ { inst_retn, OP_0 },
2253 /*6e*/ { inst_im0, OP_0 },
2254 /*6f*/ { inst_rld, OP_0 },
2255 /*70*/ { inst_inc, OP_0 },
2256 /*71*/ { inst_outc, OP_0 },
2257 /*72*/ { inst_sbchl, OP_0 },
2258 /*73*/ { inst_srrd, OP_ARG16 },
2259 /*74*/ { inst_neg, OP_0 },
2260 /*75*/ { inst_retn, OP_0 },
2261 /*76*/ { inst_im1, OP_0 },
2262 /*77*/ { inst_nop, OP_0 },
2263 /*78*/ { inst_inc, OP_0 },
2264 /*79*/ { inst_outc, OP_0 },
2265 /*7a*/ { inst_adchl, OP_0 },
2266 /*7b*/ { inst_lrrd, OP_ARG16 },
2267 /*7c*/ { inst_neg, OP_0 },
2268 /*7d*/ { inst_retn, OP_0 },
2269 /*7e*/ { inst_im2, OP_0 },
2270 /*7f*/ { inst_nop, OP_0 },
2271 /*80*/ { inst_nop, OP_0 },
2272 /*81*/ { inst_nop, OP_0 },
2273 /*82*/ { inst_nop, OP_0 },
2274 /*83*/ { inst_nop, OP_0 },
2275 /*84*/ { inst_nop, OP_0 },
2276 /*85*/ { inst_nop, OP_0 },
2277 /*86*/ { inst_nop, OP_0 },
2278 /*87*/ { inst_nop, OP_0 },
2279 /*88*/ { inst_nop, OP_0 },
2280 /*89*/ { inst_nop, OP_0 },
2281 /*8a*/ { inst_nop, OP_0 },
2282 /*8b*/ { inst_nop, OP_0 },
2283 /*8c*/ { inst_nop, OP_0 },
2284 /*8d*/ { inst_nop, OP_0 },
2285 /*8e*/ { inst_nop, OP_0 },
2286 /*8f*/ { inst_nop, OP_0 },
2287 /*90*/ { inst_nop, OP_0 },
2288 /*91*/ { inst_nop, OP_0 },
2289 /*92*/ { inst_nop, OP_0 },
2290 /*93*/ { inst_nop, OP_0 },
2291 /*94*/ { inst_nop, OP_0 },
2292 /*95*/ { inst_nop, OP_0 },
2293 /*96*/ { inst_nop, OP_0 },
2294 /*97*/ { inst_nop, OP_0 },
2295 /*98*/ { inst_nop, OP_0 },
2296 /*99*/ { inst_nop, OP_0 },
2297 /*9a*/ { inst_nop, OP_0 },
2298 /*9b*/ { inst_nop, OP_0 },
2299 /*9c*/ { inst_nop, OP_0 },
2300 /*9d*/ { inst_nop, OP_0 },
2301 /*9e*/ { inst_nop, OP_0 },
2302 /*9f*/ { inst_nop, OP_0 },
2303 /*a0*/ { inst_ldi, OP_0 },
2304 /*a1*/ { inst_cpi, OP_0 },
2305 /*a2*/ { inst_ini, OP_0 },
2306 /*a3*/ { inst_outi, OP_0 },
2307 /*a4*/ { inst_nop, OP_0 },
2308 /*a5*/ { inst_nop, OP_0 },
2309 /*a6*/ { inst_nop, OP_0 },
2310 /*a7*/ { inst_nop, OP_0 },
2311 /*a8*/ { inst_ldd, OP_0 },
2312 /*a9*/ { inst_cpd, OP_0 },
2313 /*aa*/ { inst_ind, OP_0 },
2314 /*ab*/ { inst_outd, OP_0 },
2315 /*ac*/ { inst_nop, OP_0 },
2316 /*ad*/ { inst_nop, OP_0 },
2317 /*ae*/ { inst_nop, OP_0 },
2318 /*af*/ { inst_nop, OP_0 },
2319 /*b0*/ { inst_ldir, OP_0 },
2320 /*b1*/ { inst_cpir, OP_0 },
2321 /*b2*/ { inst_inir, OP_0 },
2322 /*b3*/ { inst_otir, OP_0 },
2323 /*b4*/ { inst_nop, OP_0 },
2324 /*b5*/ { inst_nop, OP_0 },
2325 /*b6*/ { inst_nop, OP_0 },
2326 /*b7*/ { inst_nop, OP_0 },
2327 /*b8*/ { inst_lddr, OP_0 },
2328 /*b9*/ { inst_cpdr, OP_0 },
2329 /*ba*/ { inst_indr, OP_0 },
2330 /*bb*/ { inst_otdr, OP_0 },
2331 /*bc*/ { inst_nop, OP_0 },
2332 /*bd*/ { inst_nop, OP_0 },
2333 /*be*/ { inst_nop, OP_0 },
2334 /*bf*/ { inst_nop, OP_0 },
2335 /*c0*/ { inst_nop, OP_0 },
2336 /*c1*/ { inst_nop, OP_0 },
2337 /*c2*/ { inst_nop, OP_0 },
2338 /*c3*/ { inst_nop, OP_0 },
2339 /*c4*/ { inst_nop, OP_0 },
2340 /*c5*/ { inst_nop, OP_0 },
2341 /*c6*/ { inst_nop, OP_0 },
2342 /*c7*/ { inst_nop, OP_0 },
2343 /*c8*/ { inst_nop, OP_0 },
2344 /*c9*/ { inst_nop, OP_0 },
2345 /*ca*/ { inst_nop, OP_0 },
2346 /*cb*/ { inst_nop, OP_0 },
2347 /*cc*/ { inst_nop, OP_0 },
2348 /*cd*/ { inst_nop, OP_0 },
2349 /*ce*/ { inst_nop, OP_0 },
2350 /*cf*/ { inst_nop, OP_0 },
2351 /*d0*/ { inst_nop, OP_0 },
2352 /*d1*/ { inst_nop, OP_0 },
2353 /*d2*/ { inst_nop, OP_0 },
2354 /*d3*/ { inst_nop, OP_0 },
2355 /*d4*/ { inst_nop, OP_0 },
2356 /*d5*/ { inst_nop, OP_0 },
2357 /*d6*/ { inst_nop, OP_0 },
2358 /*d7*/ { inst_nop, OP_0 },
2359 /*d8*/ { inst_nop, OP_0 },
2360 /*d9*/ { inst_nop, OP_0 },
2361 /*da*/ { inst_nop, OP_0 },
2362 /*db*/ { inst_nop, OP_0 },
2363 /*dc*/ { inst_nop, OP_0 },
2364 /*dd*/ { inst_nop, OP_0 },
2365 /*de*/ { inst_nop, OP_0 },
2366 /*df*/ { inst_nop, OP_0 },
2367 /*e0*/ { inst_nop, OP_0 },
2368 /*e1*/ { inst_nop, OP_0 },
2369 /*e2*/ { inst_nop, OP_0 },
2370 /*e3*/ { inst_nop, OP_0 },
2371 /*e4*/ { inst_nop, OP_0 },
2372 /*e5*/ { inst_nop, OP_0 },
2373 /*e6*/ { inst_nop, OP_0 },
2374 /*e7*/ { inst_nop, OP_0 },
2375 /*e8*/ { inst_nop, OP_0 },
2376 /*e9*/ { inst_nop, OP_0 },
2377 /*ea*/ { inst_nop, OP_0 },
2378 /*eb*/ { inst_nop, OP_0 },
2379 /*ec*/ { inst_nop, OP_0 },
2380 /*ed*/ { inst_nop, OP_0 },
2381 /*ee*/ { inst_nop, OP_0 },
2382 /*ef*/ { inst_nop, OP_0 },
2383 /*f0*/ { inst_nop, OP_0 },
2384 /*f1*/ { inst_nop, OP_0 },
2385 /*f2*/ { inst_nop, OP_0 },
2386 /*f3*/ { inst_nop, OP_0 },
2387 /*f4*/ { inst_nop, OP_0 },
2388 /*f5*/ { inst_nop, OP_0 },
2389 /*f6*/ { inst_nop, OP_0 },
2390 /*f7*/ { inst_nop, OP_0 },
2391 /*f8*/ { inst_nop, OP_0 },
2392 /*f9*/ { inst_nop, OP_0 },
2393 /*fa*/ { inst_nop, OP_0 },
2394 /*fb*/ { inst_nop, OP_0 },
2395 /*fc*/ { inst_nop, OP_0 },
2396 /*fd*/ { inst_nop, OP_0 },
2397 /*fe*/ { inst_nop, OP_0 },
2398 /*ff*/ { inst_nop, OP_0 }
2399 };
2400
2401
2402 /*
2403 * base plane function dispatcher table
2404 * (contains more or less the 8080-compatible instructions)
2405 */
2406 static const struct instruction base_plane[256] = {
2407 /*00*/ { inst_nop, OP_0 },
2408 /*01*/ { inst_lxi, OP_ARG16 },
2409 /*02*/ { inst_stax, OP_0 },
2410 /*03*/ { inst_inx, OP_0 },
2411 /*04*/ { inst_inr, OP_0 },
2412 /*05*/ { inst_dcr, OP_0 },
2413 /*06*/ { inst_mvi, OP_ARG8 },
2414 /*07*/ { inst_rlca, OP_0 },
2415 /*08*/ { inst_exaf, OP_0 },
2416 /*09*/ { inst_dad, OP_0 },
2417 /*0a*/ { inst_ldax, OP_0 },
2418 /*0b*/ { inst_dcx, OP_0 },
2419 /*0c*/ { inst_inr, OP_0 },
2420 /*0d*/ { inst_dcr, OP_0 },
2421 /*0e*/ { inst_mvi, OP_ARG8 },
2422 /*0f*/ { inst_rrca, OP_0 },
2423 /*10*/ { inst_djnz, OP_ARG8 },
2424 /*11*/ { inst_lxi, OP_ARG16 },
2425 /*12*/ { inst_stax, OP_0 },
2426 /*13*/ { inst_inx, OP_0 },
2427 /*14*/ { inst_inr, OP_0 },
2428 /*15*/ { inst_dcr, OP_0 },
2429 /*16*/ { inst_mvi, OP_ARG8 },
2430 /*17*/ { inst_rla, OP_0 },
2431 /*18*/ { inst_jr, OP_ARG8 },
2432 /*19*/ { inst_dad, OP_0 },
2433 /*1a*/ { inst_ldax, OP_0 },
2434 /*1b*/ { inst_dcx, OP_0 },
2435 /*1c*/ { inst_inr, OP_0 },
2436 /*1d*/ { inst_dcr, OP_0 },
2437 /*1e*/ { inst_mvi, OP_ARG8 },
2438 /*1f*/ { inst_rra, OP_0 },
2439 /*20*/ { inst_jrcc, OP_ARG8 },
2440 /*21*/ { inst_lxi, OP_ARG16 },
2441 /*22*/ { inst_shld, OP_ARG16 },
2442 /*23*/ { inst_inx, OP_0 },
2443 /*24*/ { inst_inr, OP_0 },
2444 /*25*/ { inst_dcr, OP_0 },
2445 /*26*/ { inst_mvi, OP_ARG8 },
2446 /*27*/ { inst_daa, OP_0 },
2447 /*28*/ { inst_jrcc, OP_ARG8 },
2448 /*29*/ { inst_dad, OP_0 },
2449 /*2a*/ { inst_lhld, OP_ARG16 },
2450 /*2b*/ { inst_dcx, OP_0 },
2451 /*2c*/ { inst_inr, OP_0 },
2452 /*2d*/ { inst_dcr, OP_0 },
2453 /*2e*/ { inst_mvi, OP_ARG8 },
2454 /*2f*/ { inst_cpl, OP_0 },
2455 /*30*/ { inst_jrcc, OP_ARG8 },
2456 /*31*/ { inst_lxi, OP_ARG16 },
2457 /*32*/ { inst_sta, OP_ARG16 },
2458 /*33*/ { inst_inx, OP_0 },
2459 /*34*/ { inst_inr, OP_INDEXED },
2460 /*35*/ { inst_dcr, OP_INDEXED },
2461 /*36*/ { inst_mvi, OP_INDEXED|OP_ARG8 },
2462 /*37*/ { inst_scf, OP_0 },
2463 /*38*/ { inst_jrcc, OP_ARG8 },
2464 /*39*/ { inst_dad, OP_0 },
2465 /*3a*/ { inst_lda, OP_ARG16 },
2466 /*3b*/ { inst_dcx, OP_0 },
2467 /*3c*/ { inst_inr, OP_0 },
2468 /*3d*/ { inst_dcr, OP_0 },
2469 /*3e*/ { inst_mvi, OP_ARG8 },
2470 /*3f*/ { inst_ccf, OP_0 },
2471 /*40*/ { inst_mov, OP_0 },
2472 /*41*/ { inst_mov, OP_0 },
2473 /*42*/ { inst_mov, OP_0 },
2474 /*43*/ { inst_mov, OP_0 },
2475 /*44*/ { inst_mov, OP_0 },
2476 /*45*/ { inst_mov, OP_0 },
2477 /*46*/ { inst_mov, OP_INDEXED },
2478 /*47*/ { inst_mov, OP_0 },
2479 /*48*/ { inst_mov, OP_0 },
2480 /*49*/ { inst_mov, OP_0 },
2481 /*4a*/ { inst_mov, OP_0 },
2482 /*4b*/ { inst_mov, OP_0 },
2483 /*4c*/ { inst_mov, OP_0 },
2484 /*4d*/ { inst_mov, OP_0 },
2485 /*4e*/ { inst_mov, OP_INDEXED },
2486 /*4f*/ { inst_mov, OP_0 },
2487 /*50*/ { inst_mov, OP_0 },
2488 /*51*/ { inst_mov, OP_0 },
2489 /*52*/ { inst_mov, OP_0 },
2490 /*53*/ { inst_mov, OP_0 },
2491 /*54*/ { inst_mov, OP_0 },
2492 /*55*/ { inst_mov, OP_0 },
2493 /*56*/ { inst_mov, OP_INDEXED },
2494 /*57*/ { inst_mov, OP_0 },
2495 /*58*/ { inst_mov, OP_0 },
2496 /*59*/ { inst_mov, OP_0 },
2497 /*5a*/ { inst_mov, OP_0 },
2498 /*5b*/ { inst_mov, OP_0 },
2499 /*5c*/ { inst_mov, OP_0 },
2500 /*5d*/ { inst_mov, OP_0 },
2501 /*5e*/ { inst_mov, OP_INDEXED },
2502 /*5f*/ { inst_mov, OP_0 },
2503 /*60*/ { inst_mov, OP_0 },
2504 /*61*/ { inst_mov, OP_0 },
2505 /*62*/ { inst_mov, OP_0 },
2506 /*63*/ { inst_mov, OP_0 },
2507 /*64*/ { inst_mov, OP_0 },
2508 /*65*/ { inst_mov, OP_0 },
2509 /*66*/ { inst_mov, OP_INDEXED },
2510 /*67*/ { inst_mov, OP_0 },
2511 /*68*/ { inst_mov, OP_0 },
2512 /*69*/ { inst_mov, OP_0 },
2513 /*6a*/ { inst_mov, OP_0 },
2514 /*6b*/ { inst_mov, OP_0 },
2515 /*6c*/ { inst_mov, OP_0 },
2516 /*6d*/ { inst_mov, OP_0 },
2517 /*6e*/ { inst_mov, OP_INDEXED },
2518 /*6f*/ { inst_mov, OP_0 },
2519 /*70*/ { inst_mov, OP_INDEXED },
2520 /*71*/ { inst_mov, OP_INDEXED },
2521 /*72*/ { inst_mov, OP_INDEXED },
2522 /*73*/ { inst_mov, OP_INDEXED },
2523 /*74*/ { inst_mov, OP_INDEXED },
2524 /*75*/ { inst_mov, OP_INDEXED },
2525 /*76*/ { inst_halt, OP_0 },
2526 /*77*/ { inst_mov, OP_INDEXED },
2527 /*78*/ { inst_mov, OP_0 },
2528 /*79*/ { inst_mov, OP_0 },
2529 /*7a*/ { inst_mov, OP_0 },
2530 /*7b*/ { inst_mov, OP_0 },
2531 /*7c*/ { inst_mov, OP_0 },
2532 /*7d*/ { inst_mov, OP_0 },
2533 /*7e*/ { inst_mov, OP_INDEXED },
2534 /*7f*/ { inst_mov, OP_0 },
2535 /*80*/ { inst_add, OP_0 },
2536 /*81*/ { inst_add, OP_0 },
2537 /*82*/ { inst_add, OP_0 },
2538 /*83*/ { inst_add, OP_0 },
2539 /*84*/ { inst_add, OP_0 },
2540 /*85*/ { inst_add, OP_0 },
2541 /*86*/ { inst_add, OP_INDEXED },
2542 /*87*/ { inst_add, OP_0 },
2543 /*88*/ { inst_adc, OP_0 },
2544 /*89*/ { inst_adc, OP_0 },
2545 /*8a*/ { inst_adc, OP_0 },
2546 /*8b*/ { inst_adc, OP_0 },
2547 /*8c*/ { inst_adc, OP_0 },
2548 /*8d*/ { inst_adc, OP_0 },
2549 /*8e*/ { inst_adc, OP_INDEXED },
2550 /*8f*/ { inst_adc, OP_0 },
2551 /*90*/ { inst_sub, OP_0 },
2552 /*91*/ { inst_sub, OP_0 },
2553 /*92*/ { inst_sub, OP_0 },
2554 /*93*/ { inst_sub, OP_0 },
2555 /*94*/ { inst_sub, OP_0 },
2556 /*95*/ { inst_sub, OP_0 },
2557 /*96*/ { inst_sub, OP_INDEXED },
2558 /*97*/ { inst_sub, OP_0 },
2559 /*98*/ { inst_sbca, OP_0 },
2560 /*99*/ { inst_sbca, OP_0 },
2561 /*9a*/ { inst_sbca, OP_0 },
2562 /*9b*/ { inst_sbca, OP_0 },
2563 /*9c*/ { inst_sbca, OP_0 },
2564 /*9d*/ { inst_sbca, OP_0 },
2565 /*9e*/ { inst_sbca, OP_INDEXED },
2566 /*9f*/ { inst_sbca, OP_0 },
2567 /*a0*/ { inst_and, OP_0 },
2568 /*a1*/ { inst_and, OP_0 },
2569 /*a2*/ { inst_and, OP_0 },
2570 /*a3*/ { inst_and, OP_0 },
2571 /*a4*/ { inst_and, OP_0 },
2572 /*a5*/ { inst_and, OP_0 },
2573 /*a6*/ { inst_and, OP_INDEXED },
2574 /*a7*/ { inst_and, OP_0 },
2575 /*a8*/ { inst_xor, OP_0 },
2576 /*a9*/ { inst_xor, OP_0 },
2577 /*aa*/ { inst_xor, OP_0 },
2578 /*ab*/ { inst_xor, OP_0 },
2579 /*ac*/ { inst_xor, OP_0 },
2580 /*ad*/ { inst_xor, OP_0 },
2581 /*ae*/ { inst_xor, OP_INDEXED },
2582 /*af*/ { inst_xor, OP_0 },
2583 /*b0*/ { inst_or, OP_0 },
2584 /*b1*/ { inst_or, OP_0 },
2585 /*b2*/ { inst_or, OP_0 },
2586 /*b3*/ { inst_or, OP_0 },
2587 /*b4*/ { inst_or, OP_0 },
2588 /*b5*/ { inst_or, OP_0 },
2589 /*b6*/ { inst_or, OP_INDEXED },
2590 /*b7*/ { inst_or, OP_0 },
2591 /*b8*/ { inst_cmp, OP_0 },
2592 /*b9*/ { inst_cmp, OP_0 },
2593 /*ba*/ { inst_cmp, OP_0 },
2594 /*bb*/ { inst_cmp, OP_0 },
2595 /*bc*/ { inst_cmp, OP_0 },
2596 /*bd*/ { inst_cmp, OP_0 },
2597 /*be*/ { inst_cmp, OP_INDEXED },
2598 /*bf*/ { inst_cmp, OP_0 },
2599 /*c0*/ { inst_retcc, OP_0 },
2600 /*c1*/ { inst_pop, OP_0 },
2601 /*c2*/ { inst_jpcc, OP_ARG16 },
2602 /*c3*/ { inst_jp, OP_ARG16 },
2603 /*c4*/ { inst_callcc, OP_ARG16 },
2604 /*c5*/ { inst_push, OP_0 },
2605 /*c6*/ { inst_adi, OP_ARG8 },
2606 /*c7*/ { inst_rst, OP_0 },
2607 /*c8*/ { inst_retcc, OP_0 },
2608 /*c9*/ { inst_ret, OP_0 },
2609 /*ca*/ { inst_jpcc, OP_ARG16 },
2610 /*cb*/ { inst_cb, OP_INDEXED },
2611 /*cc*/ { inst_callcc, OP_ARG16 },
2612 /*cd*/ { inst_call, OP_ARG16 },
2613 /*ce*/ { inst_aci, OP_ARG8 },
2614 /*cf*/ { inst_rst, OP_0 },
2615 /*d0*/ { inst_retcc, OP_0 },
2616 /*d1*/ { inst_pop, OP_0 },
2617 /*d2*/ { inst_jpcc, OP_ARG16 },
2618 /*d3*/ { inst_outa, OP_ARG8 },
2619 /*d4*/ { inst_callcc, OP_ARG16 },
2620 /*d5*/ { inst_push, OP_0 },
2621 /*d6*/ { inst_sui, OP_ARG8 },
2622 /*d7*/ { inst_rst, OP_0 },
2623 /*d8*/ { inst_retcc, OP_0 },
2624 /*d9*/ { inst_exx, OP_0 },
2625 /*da*/ { inst_jpcc, OP_ARG16 },
2626 /*db*/ { inst_ina, OP_ARG8 },
2627 /*dc*/ { inst_callcc, OP_ARG16 },
2628 /*dd*/ { NULL, OP_0 },
2629 /*de*/ { inst_sbi, OP_ARG8 },
2630 /*df*/ { inst_rst, OP_0 },
2631 /*e0*/ { inst_retcc, OP_0 },
2632 /*e1*/ { inst_pop, OP_0 },
2633 /*e2*/ { inst_jpcc, OP_ARG16 },
2634 /*e3*/ { inst_xthl, OP_0 },
2635 /*e4*/ { inst_callcc, OP_ARG16 },
2636 /*e5*/ { inst_push, OP_0 },
2637 /*e6*/ { inst_ani, OP_ARG8 },
2638 /*e7*/ { inst_rst, OP_0 },
2639 /*e8*/ { inst_retcc, OP_0 },
2640 /*e9*/ { inst_pchl, OP_0 },
2641 /*ea*/ { inst_jpcc, OP_ARG16 },
2642 /*eb*/ { inst_xchg, OP_0 },
2643 /*ec*/ { inst_callcc, OP_ARG16 },
2644 /*ed*/ { NULL, OP_0 },
2645 /*ee*/ { inst_xri, OP_ARG8 },
2646 /*ef*/ { inst_rst, OP_0 },
2647 /*f0*/ { inst_retcc, OP_0 },
2648 /*f1*/ { inst_pop, OP_0 },
2649 /*f2*/ { inst_jpcc, OP_ARG16 },
2650 /*f3*/ { inst_di, OP_0 },
2651 /*f4*/ { inst_callcc, OP_ARG16 },
2652 /*f5*/ { inst_push, OP_0 },
2653 /*f6*/ { inst_ori, OP_ARG8 },
2654 /*f7*/ { inst_rst, OP_0 },
2655 /*f8*/ { inst_retcc, OP_0 },
2656 /*f9*/ { inst_sphl, OP_0 },
2657 /*fa*/ { inst_jpcc, OP_ARG16 },
2658 /*fb*/ { inst_ei, OP_0 },
2659 /*fc*/ { inst_callcc, OP_ARG16 },
2660 /*fd*/ { NULL, OP_0 },
2661 /*fe*/ { inst_cmpi, OP_ARG8 },
2662 /*ff*/ { inst_rst, OP_0 }
2663 };
2664
2665
2666 /*
2667 * instruction counters
2668 */
2669 static unsigned long counters[256];
2670 static unsigned long ed_counters[256];
2671 static unsigned long cb_counters[256];
2672 static unsigned long dd_counters[256];
2673 static unsigned long fd_counters[256];
2674 static unsigned long dd_cb_counters[256];
2675 static unsigned long fd_cb_counters[256];
2676
2677
2678 /*
2679 * longjmp on reception of SIGINT, SIGTERM, or SIGQUIT
2680 */
2681 static jmp_buf signal_jmp;
2682
2683
2684 /*
2685 * signal handler just jumps to the top of the main loop
2686 */
handler(int s)2687 static void handler(int s) {
2688 struct sigaction sa;
2689 switch (s) {
2690 case SIGTERM:
2691 case SIGQUIT:
2692 case SIGINT:
2693 /*
2694 * these signals are handled only once; repeated
2695 * occurrences are ignored
2696 */
2697 sa.sa_handler = SIG_IGN;
2698 sigemptyset(&sa.sa_mask);
2699 sa.sa_flags = 0;
2700 sigaction(SIGTERM, &sa, NULL);
2701 sigaction(SIGQUIT, &sa, NULL);
2702 sigaction(SIGINT, &sa, NULL);
2703 longjmp(signal_jmp, 1);
2704 break;
2705 case SIGUSR1:
2706 dump = 1;
2707 break;
2708 }
2709 }
2710
2711
2712 /*
2713 * after this number of instructions, the console is polled
2714 */
2715 #define POLL_INTERVAL (128 * 1024)
2716
2717
2718 /*
2719 * start emulation proper
2720 */
2721 void
cpu_run(void)2722 cpu_run(void) {
2723 int poll_counter = 0, delay_counter = 0;
2724 const struct instruction *inst_p;
2725 struct sigaction sa;
2726 struct timespec delay;
2727 /*
2728 * initialize the nanosecond delay value
2729 */
2730 if (delay_nanoseconds > 0) {
2731 memset(&delay, 0, sizeof delay);
2732 delay.tv_sec = delay_nanoseconds / 1000000000;
2733 delay.tv_nsec = delay_nanoseconds % 1000000000;
2734 }
2735 /*
2736 * catch signals for termination of a runaway program
2737 */
2738 if (setjmp(signal_jmp)) {
2739 if (! terminate) {
2740 terminate = 1;
2741 term_reason = ERR_SIGNAL;
2742 }
2743 } else {
2744 /*
2745 * signals causing the emulation to terminate with
2746 * status ERR_SIGNAL; the handlers block the occurrence
2747 * of the other signals to avoid calling logjmp() twice.
2748 */
2749 sa.sa_handler = handler;
2750 sigemptyset(&sa.sa_mask);
2751 sigaddset(&sa.sa_mask, SIGTERM);
2752 sigaddset(&sa.sa_mask, SIGQUIT);
2753 sigaddset(&sa.sa_mask, SIGINT);
2754 sa.sa_flags = 0;
2755 sigaction(SIGTERM, &sa, NULL);
2756 sigaction(SIGQUIT, &sa, NULL);
2757 sigaction(SIGINT, &sa, NULL);
2758 }
2759 /*
2760 * install signal handler if dump signals are requested
2761 */
2762 if (conf_dump & DUMP_SIGNAL) {
2763 sa.sa_handler = handler;
2764 sigemptyset(&sa.sa_mask);
2765 sa.sa_flags = 0;
2766 sigaction(SIGUSR1, &sa, NULL);
2767 }
2768 while (! terminate) {
2769 /*
2770 * dump machine state
2771 */
2772 if (dump) {
2773 dump = 0;
2774 dump_machine("signal");
2775 }
2776 /*
2777 * mark start of new instruction
2778 */
2779 current_instruction = reg_pc;
2780 /*
2781 * fetch next opcode, handle instruction prefixes
2782 */
2783 prefix = 0x00;
2784 for (;;) {
2785 opcode = fetch_m1();
2786 if (opcode != 0xdd && opcode != 0xfd) break;
2787 prefix = opcode;
2788 }
2789 inst_p = base_plane + opcode;
2790 /*
2791 * get optional displacement
2792 */
2793 if (prefix && (inst_p->flags & OP_INDEXED)) disp = fetch();
2794 /*
2795 * instructions starting in 0xed are handled in
2796 * a slightly different way (contrary to those starting in
2797 * 0xcb they are not influenced by prefixes and have
2798 * non-uniform arguments)
2799 */
2800 if (opcode == 0xcb) {
2801 opcode2 = prefix ? fetch_m1() : fetch();
2802 if (log_level >= LL_COUNTERS) {
2803 switch (prefix) {
2804 case 0xdd: dd_cb_counters[opcode2]++; break;
2805 case 0xfd: fd_cb_counters[opcode2]++; break;
2806 default: cb_counters[opcode2]++; break;
2807 }
2808 }
2809 } else if (opcode == 0xed) {
2810 opcode2 = fetch_m1();
2811 inst_p = ed_plane + opcode2;
2812 if (log_level >= LL_COUNTERS) {
2813 ed_counters[opcode2]++;
2814 }
2815 } else {
2816 if (log_level >= LL_COUNTERS) {
2817 switch (prefix) {
2818 case 0xdd: dd_counters[opcode]++; break;
2819 case 0xfd: fd_counters[opcode]++; break;
2820 default: counters[opcode]++; break;
2821 }
2822 }
2823 }
2824 /*
2825 * get optional 8-bit argument
2826 */
2827 if (inst_p->flags & OP_ARG8) op_low = fetch();
2828 /*
2829 * get optional 16-bit argument
2830 */
2831 if (inst_p->flags & OP_ARG16) {
2832 op_low = fetch();
2833 op_high = fetch();
2834 }
2835 /*
2836 * execute instruction
2837 */
2838 (*inst_p->handler_p)();
2839 /*
2840 * Poll the console in regular intervals; this is a rather
2841 * clumsy solution to keep the VT52 emulation happy even
2842 * if a program doesn't care about console input for a
2843 * prolonged period.
2844 */
2845 poll_counter++;
2846 if (poll_counter == POLL_INTERVAL) {
2847 poll_counter = 0;
2848 console_poll();
2849 }
2850 if (delay_count > 0) {
2851 /*
2852 * add a delay of delay_nanoseconds every
2853 * delay_count emulated instructions
2854 */
2855 delay_counter++;
2856 if (delay_counter >= delay_count) {
2857 delay_counter = 0;
2858 nanosleep(&delay, NULL);
2859 }
2860 }
2861 }
2862 }
2863
2864
2865 /*
2866 * copy the instruction call counters of a instruction plane to the log
2867 */
2868 static void
dump_plane(unsigned long counters[256],const char * name)2869 dump_plane(unsigned long counters[256], const char *name) {
2870 int low, high, n;
2871 char buffer[1024], *cp;
2872 /*
2873 * check if all counters in the plane are zero
2874 */
2875 for (n = 0; n < 256 && ! counters[n]; n++);
2876 if (n == 256) {
2877 /*
2878 * all counters are zero: log a single line
2879 * (this will be the case for planes other than the
2880 * base plane after executing a 8080 program)
2881 */
2882 plog("instruction counters for %s: all zero", name);
2883 } else {
2884 /*
2885 * at least one counter is greater than zero:
2886 * log full table
2887 */
2888 plog("instruction counters for %s:", name);
2889 cp = buffer;
2890 cp += sprintf(cp, " ");
2891 for (high = 0; high < 16; high++) {
2892 cp += sprintf(cp, " %1xy", high);
2893 }
2894 plog("%s", buffer);
2895 for (low = 0; low < 16; low++) {
2896 cp = buffer;
2897 cp += sprintf(cp, "x%1x", low);
2898 for (high = 0; high < 16; high++) {
2899 n = high * 16 + low;
2900 if (counters[n]) {
2901 cp += sprintf(cp, " %10lu",
2902 counters[n]);
2903 } else {
2904 cp += sprintf(cp, " -");
2905 }
2906 }
2907 plog("%s", buffer);
2908 }
2909 }
2910 }
2911
2912
2913 /*
2914 * save (parts of) the Z80 memory as an Intel Hex file
2915 */
2916 static int
save_memory_hex(void)2917 save_memory_hex(void) {
2918 int rc = 0;
2919 int addr, bytes, checksum, i;
2920 FILE *fp = NULL;
2921 /*
2922 * create text file
2923 */
2924 fp = fopen(conf_save_file, "w");
2925 if (! fp) {
2926 perr("cannot create %s: %s", conf_save_file, strerror(errno));
2927 rc = (-1);
2928 goto premature_exit;
2929 }
2930 /*
2931 * save data in records of at most 32 bytes
2932 */
2933 addr = conf_save_start;
2934 while (addr <= conf_save_end) {
2935 bytes = conf_save_end - addr + 1;
2936 if (bytes > 32) bytes = 32;
2937 checksum = bytes + ((addr >> 8) & 0xff) + (addr & 0xff);
2938 fprintf(fp, ":%02X%04X00", bytes, addr);
2939 for (i = 0; i < bytes; i++) {
2940 fprintf(fp, "%02X", memory[addr + i]);
2941 checksum += memory[addr + i];
2942 }
2943 checksum = ((0x100 - (checksum & 0xff)) & 0xff);
2944 fprintf(fp, "%02X\n", checksum);
2945 addr += bytes;
2946 }
2947 /*
2948 * write EOF record
2949 */
2950 checksum = 0 + ((conf_save_start >> 8) & 0xff) +
2951 (conf_save_start & 0xff) + 1;
2952 checksum = ((0x100 - (checksum & 0xff)) & 0xff);
2953 fprintf(fp, ":00%04X01%02X\n", conf_save_start, checksum);
2954 /*
2955 * summary error check
2956 */
2957 if (ferror(fp)) {
2958 perr("write error in %s: %s", conf_save_file, strerror(errno));
2959 rc = (-1);
2960 }
2961 premature_exit:
2962 if (fp) {
2963 /*
2964 * close text file
2965 */
2966 if (fclose(fp)) {
2967 perr("cannot close %s: %s", conf_save_file,
2968 strerror(errno));
2969 rc = (-1);
2970 }
2971 }
2972 return rc;
2973 }
2974
2975
2976 /*
2977 * save (parts of) the Z80 memory as a binary file
2978 */
2979 static int
save_memory_bin(void)2980 save_memory_bin(void) {
2981 int rc = 0;
2982 size_t n;
2983 FILE *fp = NULL;
2984 /*
2985 * create binary file
2986 */
2987 fp = fopen(conf_save_file, "wb");
2988 if (! fp) {
2989 perr("cannot create %s: %s", conf_save_file, strerror(errno));
2990 rc = (-1);
2991 goto premature_exit;
2992 }
2993 /*
2994 * write memory contents
2995 */
2996 n = conf_save_end - conf_save_start + 1;
2997 if (fwrite(memory + conf_save_start, sizeof memory[0], n, fp) != n) {
2998 perr("write error on %s: %s", conf_save_file, strerror(errno));
2999 rc = (-1);
3000 }
3001 premature_exit:
3002 if (fp) {
3003 /*
3004 * close binary file
3005 */
3006 if (fclose(fp)) {
3007 perr("cannot close %s: %s", conf_save_file,
3008 strerror(errno));
3009 rc = (-1);
3010 }
3011 }
3012 return rc;
3013 }
3014
3015
3016 /*
3017 * clean up after emulation run
3018 */
3019 int
cpu_exit(void)3020 cpu_exit(void) {
3021 int rc = 0;
3022 /*
3023 * finalize OS emulation
3024 */
3025 rc = os_exit();
3026 /*
3027 * perform exit or error dump
3028 */
3029 if (conf_dump & DUMP_EXIT) {
3030 dump_machine("exit");
3031 } else if (conf_dump & DUMP_ERROR) {
3032 if (term_reason > OK_CTRLC) dump_machine("error");
3033 }
3034 /*
3035 * display reason for program termination
3036 */
3037 switch (term_reason) {
3038 case OK_NOTRUN:
3039 break;
3040 case OK_TERM:
3041 break;
3042 case OK_CTRLC:
3043 break;
3044 case ERR_BOOT:
3045 perr("BIOS cold boot entry called");
3046 break;
3047 case ERR_BDOSARG:
3048 perr("invalid argument in BDOS call");
3049 break;
3050 case ERR_SELECT:
3051 perr("access to invalid/unconfigured disk");
3052 break;
3053 case ERR_RODISK:
3054 perr("attempted write access to read-only disk");
3055 break;
3056 case ERR_ROFILE:
3057 perr("attempted write access to read-only file");
3058 break;
3059 case ERR_HOST:
3060 perr("host system call failed");
3061 break;
3062 case ERR_LOGIC:
3063 perr("guest program logic error");
3064 break;
3065 case ERR_SIGNAL:
3066 perr("program execution stopped by signal");
3067 break;
3068 case ERR_HALT:
3069 perr("HALT instruction executed");
3070 break;
3071 }
3072 if (term_reason <= OK_CTRLC) {
3073 if (conf_save_file) {
3074 /*
3075 * save (part of) the Z80 memory area
3076 * on regular program termination
3077 */
3078 if (conf_save_hex) {
3079 if (save_memory_hex()) rc = (-1);
3080 } else {
3081 if (save_memory_bin()) rc = (-1);
3082 }
3083 }
3084 } else {
3085 rc = (-1);
3086 }
3087 /*
3088 * deallocate memory
3089 */
3090 free(memory);
3091 /*
3092 * dump instruction counters
3093 */
3094 if (log_level >= LL_COUNTERS) {
3095 dump_plane(counters, "base plane");
3096 dump_plane(cb_counters, "0xcb plane");
3097 dump_plane(dd_counters, "0xdd base plane");
3098 dump_plane(dd_cb_counters, "0xdd 0xcb plane");
3099 dump_plane(ed_counters, "0xed plane");
3100 dump_plane(fd_counters, "0xfd base plane");
3101 dump_plane(fd_cb_counters, "0xfd 0xcb plane");
3102 }
3103 return rc;
3104 }
3105