1 /*-----------------------------------------------------------------------*\
2 | main.c -- main driver program for the z80 emulator -- all I/O |
3 | to the Unix world is done from this file -- "z80.c" calls various |
4 | functions within this file |
5 | |
6 | Copyright 1986-1988 by Parag Patel. All Rights Reserved. |
7 | Copyright 1994-1995 by CodeGen, Inc. All Rights Reserved. |
8 \*-----------------------------------------------------------------------*/
9
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <fcntl.h>
14 #include <signal.h>
15 #include <errno.h>
16 #include <string.h>
17 #include <ctype.h>
18
19 #include "defs.h"
20 #include "vt.h"
21
22 #if defined macintosh
23 # include <Types.h>
24 # include <Events.h>
25 # ifdef THINK_C
26 # include <console.h>
27 # endif
28 #elif defined DJGPP
29 # include <pc.h>
30 #elif defined _WIN32
31 #
32 #else /* UNIX */
33 # include <unistd.h>
34 # include <sys/ioctl.h>
35 # if defined POSIX_TTY
36 # include <sys/termios.h>
37 # elif defined BeBox
38 # include <termios.h>
39 # else
40 # include <termio.h>
41 # endif
42 #endif
43
44 #define INTR_CHAR 31 /* control-underscore */
45
46 extern int errno;
47
48
49 /* globally visible vars */
50 static FILE *logfile = NULL;
51
52
53 #ifndef _WIN32
54 # if defined UNIX || defined BeBox
55 # ifdef POSIX_TTY
56 # define termio termios
57 # endif
58 static struct termio rawterm, oldterm; /* for raw terminal I/O */
59 # endif
60 #endif
61
62 #ifdef _WIN32
63 static int have_term = 0; /* no terminal in Win32 */
64 #else
65 static int have_term = 1; /* FALSE if terminal initialization failed */
66 #endif
67
68 static void dumptrace(z80info *z80);
69
70
jgets(char * s,int len,FILE * f)71 char *jgets(char *s, int len, FILE *f)
72 {
73 char *rtn = fgets(s, len, f);
74 if (rtn)
75 {
76 int x;
77 for (x = 0; s[x] && s[x] != '\r' && s[x] != '\n'; ++x);
78 s[x] = 0;
79 }
80 return rtn;
81 }
82
83 /*-----------------------------------------------------------------------*\
84 | resetterm -- reset terminal characteristics to original settings
85 \*-----------------------------------------------------------------------*/
86
87 void
resetterm(void)88 resetterm(void)
89 {
90 #ifndef _WIN32
91 if (have_term)
92 tcsetattr(fileno(stdin), TCSADRAIN, &oldterm);
93 #endif
94 }
95
96
97
98 /*-----------------------------------------------------------------------*\
99 | setterm -- set terminal characteristics to raw mode
100 \*-----------------------------------------------------------------------*/
101
102 void
setterm(void)103 setterm(void)
104 {
105 #ifndef _WIN32
106 if (have_term)
107 tcsetattr(fileno(stdin), TCSADRAIN, &rawterm);
108 #endif
109 }
110
111
112
113 /*-----------------------------------------------------------------------*\
114 | initterm -- initialize terminal stuff -- called once on startup
115 | and then after returning from a sub-shell
116 \*-----------------------------------------------------------------------*/
117
118 static void
initterm(void)119 initterm(void)
120 {
121 #ifdef _WIN32
122 fprintf(stderr, "Sorry, terminal not found, using cooked mode.\n");
123 have_term = 0;
124 #else
125 if (tcgetattr(fileno(stdin), &oldterm))
126 {
127 fprintf(stderr, "Sorry, terminal not found, using cooked mode.\n");
128 have_term = 0;
129 }
130 else {
131 rawterm = oldterm;
132 rawterm.c_iflag &= ~(ICRNL | IXON | IXOFF | INLCR | ICRNL);
133 rawterm.c_lflag &= ~(ICANON | ECHO);
134 rawterm.c_cc[VSUSP] = -1;
135 rawterm.c_cc[VQUIT] = -1;
136 rawterm.c_cc[VERASE] = -1;
137 rawterm.c_cc[VKILL] = -1;
138 }
139 // tcsetattr(fileno(stdin), TCSADRAIN, &rawterm);
140
141 #if 0
142 /* rawterm.c_lflag &= ~(ISIG | ICANON | ECHO); */
143 rawterm.c_lflag &= ~(ICANON | ECHO);
144 #ifdef IENQAK
145 rawterm.c_iflag &= ~(IENQAK | IXON | IXOFF | INLCR | ICRNL);
146 #else
147 rawterm.c_iflag &= ~(IXON | IXOFF | INLCR | ICRNL);
148 #endif
149 rawterm.c_oflag &= ~OPOST;
150 rawterm.c_cc[VINTR] = INTR_CHAR;
151 rawterm.c_cc[VSUSP] = -1;
152 rawterm.c_cc[VQUIT] = -1;
153 rawterm.c_cc[VERASE] = -1;
154 rawterm.c_cc[VKILL] = -1;
155 rawterm.c_cc[VMIN] = 1; /* MIN number of chars */
156 rawterm.c_cc[VTIME] = 0; /* TIME timeout value */
157 #endif
158 #endif
159 }
160
161
162
163
164 /*-----------------------------------------------------------------------*\
165 | command -- called when user-level commands are needed by the z80
166 | for some reason or another
167 \*-----------------------------------------------------------------------*/
168
169 static void
command(z80info * z80)170 command(z80info *z80)
171 {
172 int i, j, t, e;
173 char str[256], *s;
174 FILE *fp;
175 static word pe = 0;
176 static word po = 0;
177
178 resetterm();
179 printf("\n");
180
181 loop: /* "infinite" loop */
182
183 /* prompt for a command from the user & then do it */
184 printf("Cmd: ");
185 fflush(stdout);
186 *str = '\0';
187 fgets(str, sizeof str - 1, stdin);
188
189 for (s = str; *s == ' ' || *s == '\t'; s++)
190 ;
191
192 switch (isupper(*(unsigned char *)s) ? tolower(*(unsigned char *)s) : *s)
193 {
194 case '?': /* help */
195 printf(" Q(uit) T(race on/off) S(tep trace) D(ump regs)\n");
196 printf(" E(xamine memory) P(oke memory) R(egister modify)\n");
197 printf(" L(oad binary) C(ontinue running - <CR> if Step)\n");
198 printf(" G(o) B(oot CP/M) Z(80 disassembled dump)\n");
199 printf(" W(write memory to file) X,Y(-set/clear breakpoint)\n");
200 printf(" O(output to \"logfile\")\n\n");
201 printf(" !(fork shell) ?(command list) V(ersion)\n\n");
202 break;
203
204 case 'o':
205 if (logfile != NULL)
206 {
207 fclose(logfile);
208 logfile = NULL;
209 printf(" Logging off.\n");
210 }
211 else
212 {
213 printf(" Logfile name? ");
214 jgets(str, sizeof(str), stdin);
215
216 for (s = str; isspace(*(unsigned char *)s); s++)
217 ;
218
219 if (*s == '\0')
220 break;
221
222 logfile = fopen(s, "w");
223
224 if (logfile == NULL)
225 printf("Cannot open logfile!\n");
226 else
227 printf(" Logging on.\n");
228 }
229
230 break;
231
232 case '!': /* fork a shell */
233 system("exec ${SHELL:-/bin/sh}");
234 initterm();
235 printf("\n");
236 break;
237
238 case 'q': /* quit */
239 if (logfile != NULL)
240 fclose(logfile);
241
242 exit(0);
243 break;
244
245 case 'v': /* version */
246 printf(" Version %s\n", VERSION);
247 break;
248
249 case 'b': /* boot cp/m */
250 setterm();
251 sysreset(z80);
252 return;
253 break;
254
255 case 't': /* toggle trace mode */
256 z80->trace = !z80->trace;
257 printf(" Trace %s\n", z80->trace ? "on" : "off");
258 break;
259
260 case 's': /* toggle step-trace mode */
261 z80->step = !z80->step;
262 printf(" Step-trace %s\n", z80->step ? "on" : "off");
263 printf(" Trace %s\n", z80->trace ? "on" : "off");
264 break;
265
266 case 'd': /* dump registers */
267 dumptrace(z80);
268 break;
269
270 case 'e': /* examine memory */
271 printf(" Starting at loc? (%.4X) : ", pe);
272 jgets(str, sizeof(str), stdin);
273 t = pe;
274 sscanf(str, "%x", &t);
275 pe = t;
276
277 for (i = 0; i <= 8; i++)
278 {
279 printf(" %.4X: ", pe);
280
281 for (j = 0; j <= 0xF; j++)
282 printf("%.2X ", z80->mem[pe++]);
283
284 printf("\n");
285 }
286
287 break;
288
289 case 'w': /* write memory to file */
290 printf(" Starting at loc? ");
291 jgets(str, sizeof(str), stdin);
292 sscanf(str, "%x", &t);
293 printf(" Ending at loc? ");
294 jgets(str, sizeof(str), stdin);
295 sscanf(str, "%x", &e);
296 fp = fopen("mem", "w");
297
298 if (fp == NULL)
299 printf("Cannot open file 'mem' for writing!\n");
300 else
301 {
302 j = 0;
303
304 for (i = t; i < e; i++)
305 {
306 if (j++ > 9)
307 {
308 fprintf(fp, "\n");
309 j = 0;
310 }
311
312 fprintf(fp, "0x%X, ", z80->mem[i]);
313 }
314
315 fprintf(fp, "\n");
316 fclose(fp);
317 }
318
319 break;
320
321 case 'x': /* set breakpoint */
322 #ifdef MEM_BREAK
323 printf(" Set breakpoint at loc? (A for abort): ");
324 jgets(str, sizeof(str), stdin);
325
326 if (tolower(*(unsigned char *)str) == 'a' || *str == '\0')
327 break;
328
329 sscanf(str, "%x", &t);
330
331 if (t < 0 || t >= sizeof z80->mem)
332 {
333 printf("Cannot set breakpoint at addr 0x%X\n", t);
334 break;
335 }
336
337 if (!(z80->membrk[t] & M_BREAKPOINT))
338 {
339 printf(" Breakpoint set at addr 0x%X\n", t);
340 z80->membrk[t] |= M_BREAKPOINT;
341 z80->numbrks++;
342 }
343 #else
344 printf("Sorry, Z80 has not been compiled with MEM_BREAK.\n");
345 #endif /* MEM_BREAK */
346 break;
347
348 case 'y': /* clear breakpoints */
349 #ifdef MEM_BREAK
350 printf(" Clear breakpoint at loc? (A for all) : ");
351 jgets(str, sizeof(str), stdin);
352
353 if (tolower(*(unsigned char *)str) == 'a')
354 {
355 for (i = 0; i < sizeof z80->membrk; i++)
356 z80->membrk[i] &= ~M_BREAKPOINT;
357
358 z80->numbrks = 0;
359 printf(" All breakpoints cleared\n");
360 break;
361 }
362
363 sscanf(str, "%x", &t);
364
365 if (t < 0 || t >= sizeof z80->mem)
366 {
367 printf(" Cannot clear breakpoint at addr 0x%X\n", t);
368 break;
369 }
370
371 if (z80->membrk[t] & M_BREAKPOINT)
372 {
373 printf("Breakpoint cleared at addr 0x%X\n", t);
374 z80->membrk[t] &= ~M_BREAKPOINT;
375 z80->numbrks--;
376 }
377 #else
378 printf("Sorry, Z80 has not been compiled with MEM_BREAK.\n");
379 #endif /* MEM_BREAK */
380 break;
381
382 case 'z': /* z80 disassembled memory dump */
383 printf(" Starting at loc? (%.4X) : ", pe);
384 jgets(str, sizeof(str), stdin);
385 t = pe;
386 sscanf(str, "%x", &t);
387 pe = t;
388
389 for (i = 0; i < 0x10; i++)
390 {
391 printf(" %.4X: ", pe);
392 j = pe;
393 pe += disassem(z80, pe, stdout);
394 t = disassemlen(z80);
395
396 while (t++ < 15)
397 putchar(' ');
398
399 while (j < pe)
400 printf(" %.2X", z80->mem[j++]);
401
402 printf("\n");
403 }
404
405 break;
406
407 case 'p': /* poke memory */
408 printf(" Start at loc? (%.4X) : ", po);
409 jgets(str, sizeof(str), stdin);
410 sscanf(str, "%x", &i);
411 po = i;
412
413 for (;;)
414 {
415 printf(" Mem[%.4X] (%.2X) = ", po, z80->mem[po]);
416 jgets(str, sizeof(str), stdin);
417
418 for (s = str; *s == ' ' || *s == '\t'; s++)
419 ;
420
421 if (*s == '~') /* exit? */
422 {
423 po = i;
424 break;
425 }
426
427 if (*s == '\0') /* leave the value alone */
428 continue;
429
430 j = 0;
431 sscanf(str, "%x", &j);
432 z80->mem[po] = j;
433 po++;
434 }
435 break;
436
437 case 'r': /* set a register */
438 printf(" Value? = ");
439 jgets(str, sizeof(str), stdin);
440 i = 0;
441 sscanf(str, "%x", &i);
442 printf(" Reg? (A,F,B,C,D,E,H,L,IX,IY,SP,PC) : ");
443 jgets(str, sizeof(str), stdin);
444
445 for (s = str; *s == ' ' || *s == '\t'; s++)
446 ;
447
448 switch (tolower(*(unsigned char *)s))
449 {
450 case 'a': A = i; break;
451 case 'f': F = i; break;
452 case 'b': B = i; break;
453 case 'c': C = i; break;
454 case 'd': D = i; break;
455 case 'e': E = i; break;
456 case 'h': H = i; break;
457 case 'l': L = i; break;
458 case 'i':
459 if (tolower(((unsigned char *)s)[1]) == 'x')
460 IX = i;
461 else if (tolower(((unsigned char *)s)[1]) == 'y')
462 IY = i;
463
464 break;
465
466 case 'x': IX = i; break;
467 case 'y': IY = i; break;
468 case 's': SP = i; break;
469 case 'p': PC = i; break;
470
471 default:
472 printf("No such register\n");
473 break;
474 }
475
476 break;
477
478 case 'l': /* load a file into z80 memory */
479 printf(" File-name: ");
480 jgets(str, sizeof(str), stdin);
481
482 if (!loadfile(z80, str))
483 fprintf(stderr, "Cannot load file %s!\r\n", str);
484
485 break;
486
487 case '\0': /* carriage-return */
488 case '\r':
489 case '\n':
490 if (z80->trace && z80->step)
491 goto cont;
492
493 break;
494
495 case 'c': /* continue z80 execution */
496 case 'g':
497 cont:
498 setterm();
499
500 if (z80->trace)
501 {
502 z80->event = TRUE;
503 z80->halt = TRUE;
504 }
505
506 return;
507
508 default:
509 /*putchar('\007');*/
510 printf("\007Command \"%s\" not recognized\n", s);
511 break;
512 }
513
514 goto loop;
515 }
516
517
518
519
520 /*-----------------------------------------------------------------------*\
521 | dumptrace -- dump the z80 registers in an easy-to-trace format
522 | -- note that the dump takes exactly one line so that changes in
523 | register values are easier to spot -- disassembles the z80 code
524 \*-----------------------------------------------------------------------*/
525
526 static void
dumptrace(z80info * z80)527 dumptrace(z80info *z80)
528 {
529 printf("a%.2X f%.2X bc%.4X de%.4X hl%.4X ",
530 A, F, BC, DE, HL);
531 printf("ix%.4X iy%.4X sp%.4X pc%.4X:%.2X ",
532 IX, IY, SP, PC, z80->mem[PC]);
533 disassem(z80, PC, stdout);
534 printf("\r\n");
535
536 if (logfile)
537 {
538 fprintf(logfile, "a%.2X f%.2X bc%.4X de%.4X hl%.4X ",
539 A, F, BC, DE, HL);
540 fprintf(logfile, "ix%.4X iy%.4X sp%.4X pc%.4X:%.2X ",
541 IX, IY, SP, PC, z80->mem[PC]);
542 disassem(z80, PC, logfile);
543 fprintf(logfile, "\r\n");
544 }
545 }
546
547
548
549 #define HEXVAL(c) (('0' <= (c) && (c) <= '9') ? (c) - '0' :\
550 (('a' <= (c) && (c) <= 'f') ? (c) - 'a' + 10 :\
551 (('A' <= (c) && (c) <= 'F') ? (c) - 'A' + 10 :\
552 -1 )))
553
554 static int
gethex(FILE * fp)555 gethex(FILE *fp)
556 {
557 int i, j;
558
559 i = getc(fp);
560 j = getc(fp);
561
562 if (i < 0 || j < 0)
563 return -1;
564
565 i = HEXVAL(i);
566 j = HEXVAL(j);
567
568 if (i < 0 || j < 0)
569 return -1;
570
571 return (i << 4) | j;
572 }
573
574
575 static int
loadhex(z80info * z80,FILE * fp)576 loadhex(z80info *z80, FILE *fp)
577 {
578 int start = TRUE;
579 int len, line, i;
580 word addr, check, t;
581
582 for (line = 1; getc(fp) >= 0; line++) /* should be a ':' */
583 {
584 if ((len = gethex(fp)) <= 0)
585 break;
586
587 check = len;
588
589 if ((i = gethex(fp)) < 0)
590 break;
591
592 addr = (word)i;
593 check += addr;
594
595 if ((i = gethex(fp)) < 0)
596 break;
597
598 t = (word)i;
599 check += t;
600 addr = (addr << 8) | t;
601
602 if (start)
603 PC = addr, start = FALSE;
604
605 if ((i = gethex(fp)) < 0) /* ??? */
606 break;
607
608 check += (word)i;
609
610 while (len-- > 0)
611 {
612 if ((i = gethex(fp)) < 0)
613 break;
614
615 t = (word)i;
616 check += t;
617 z80->mem[addr] = t;
618 addr++;
619 }
620
621 if ((i = gethex(fp)) < 0) /* checksum */
622 break;
623
624 t = (word)i;
625
626 if ((t + check) & 0xFF)
627 {
628 fprintf(stderr, "%d: Checksum error: %.2X != 0!\r\n",
629 line, (t + check) & 0xFF);
630 return FALSE;
631 }
632
633 if (getc(fp) < 0) /* should be a '\n' */
634 break;
635 }
636
637 return TRUE;
638 }
639
640
641
642 /*-----------------------------------------------------------------------*\
643 | getword -- return a 16-bit word from the specified file
644 \*-----------------------------------------------------------------------*/
645
646 static int
getword(FILE * file)647 getword(FILE *file)
648 {
649 int w;
650
651 w = getc(file) << 8;
652 w |= getc(file);
653 return w;
654 }
655
656
657
658 /*-----------------------------------------------------------------------*\
659 | loadpisces -- load the specified file (assumed to be in Pisces+
660 | format) into the z80 memory for subsequent execution
661 \*-----------------------------------------------------------------------*/
662
663 static int
loadpisces(z80info * z80,FILE * file)664 loadpisces(z80info *z80, FILE *file)
665 {
666 int numbytes, i;
667 unsigned short loadaddr;
668
669 /* ignore the 1st 12 words in the file - the 13th word is the starting
670 PC value - the 14th is also ignored */
671 for (i = 0; i < 12; i++)
672 getword(file);
673
674 PC = getword(file);
675 getword(file);
676
677 /* read in each block of words into the z80 memory - each block
678 specifies the number of bytes in the block and the address to load
679 the data into */
680 while (getword(file) != EOF)
681 {
682 numbytes = getword(file);
683 loadaddr = getword(file);
684 getword(file);
685
686 for (; numbytes > 0; numbytes -= 2)
687 {
688 z80->mem[loadaddr] = getc(file);
689 loadaddr++;
690 z80->mem[loadaddr] = getc(file);
691 loadaddr++;
692 }
693 }
694
695 return TRUE;
696 }
697
698
699 static void
suffix(char * str,const char * suff)700 suffix(char *str, const char *suff)
701 {
702 while(*str != '\0' && *str != '.')
703 str++;
704
705 strcpy(str, suff);
706 }
707
708
709 boolean
loadfile(z80info * z80,const char * fname)710 loadfile(z80info *z80, const char *fname)
711 {
712 char buf[200];
713 FILE *fp;
714 int ret;
715
716 if ((fp = fopen(fname, "r")) != NULL)
717 {
718 ret = loadhex(z80, fp);
719 fclose(fp);
720 return ret;
721 }
722
723 strcpy(buf, fname);
724 suffix(buf, ".hex");
725
726 if ((fp = fopen(buf, "r")) != NULL)
727 {
728 ret = loadhex(z80, fp);
729 fclose(fp);
730 return ret;
731 }
732
733 strcpy(buf, fname);
734 suffix(buf, ".X");
735
736 if ((fp = fopen(buf, "r")) != NULL)
737 {
738 ret = loadpisces(z80, fp);
739 fclose(fp);
740 return ret;
741 }
742
743 return FALSE;
744 }
745
746
747
748 /* input -- z80 input instruction -- this function is called whenever
749 an input ports is referenced from the z80 to handle the real I/O --
750 it returns a byte to the z80 just like the real I/O instruction --
751 the arguments represent the data on the bus as it would be for a real
752 z80 - this routine is restarted later if there is no input pending,
753 and we must wait for some to occur */
754
755 boolean
input(z80info * z80,byte haddr,byte laddr,byte * val)756 input(z80info *z80, byte haddr, byte laddr, byte *val)
757 {
758 int data;
759
760 /* just uses the lower 8-bits of the I/O address for now... */
761 switch (laddr)
762 {
763
764 /* return a character from the keyboard - wait for it if necessary --
765 return "last" if we have already read in something via 0x01 */
766 case 0x00:
767 if (1)
768 {
769 #if defined macintosh
770 EventRecord ev;
771
772 again:
773 fflush(stdout);
774
775 while (!WaitNextEvent(keyDownMask | autoKeyMask,
776 &ev, 20, nil))
777 ;
778
779 data = ev.message & charCodeMask;
780
781 if ((data == '.' && (ev.modifiers & cmdKey)) ||
782 data == INTR_CHAR)
783 {
784 command(z80);
785 goto again;
786 }
787 else if (data == 'q' && (ev.modifiers & cmdKey))
788 exit(0);
789 #elif defined DJGPP
790 fflush(stdout);
791 data = getkey();
792
793 while (data == INTR_CHAR)
794 {
795 command(z80);
796 data = getkey();
797 }
798 #else /* TCGETA */
799 fflush(stdout);
800 data = kget(0);
801 // data = getchar();
802
803 while ((data < 0 && errno == EINTR) ||
804 data == INTR_CHAR)
805 {
806 command(z80);
807 data = kget(0);
808 // data = getchar();
809 }
810 #endif
811 }
812
813 *val = data & 0x7F;
814 break;
815
816 /* return 0xFF if we have a character waiting to be read - save the
817 character in "last" for 0x00 above */
818 case 0x01:
819 #if defined macintosh
820 {
821 EventRecord ev;
822 *val = EventAvail(keyDownMask | autoKeyMask, &ev) ?
823 0xFF : 0;
824 }
825 #elif defined DJGPP
826 *val = (kbhit()) ? 0xFF : 0;
827 #else /* UNIX or BeBox */
828 fflush(stdout);
829
830 if (constat())
831 *val = 0xFF;
832 else
833 *val = 0x00;
834
835 #endif
836 break;
837
838 /* default - prompt the user for an input byte */
839 default:
840 resetterm();
841 printf("INPUT : addr = %X%X DATA = ", haddr, laddr);
842 fflush(stdout);
843 scanf("%x", &data);
844 setterm();
845 *val = data;
846 break;
847 }
848
849 return TRUE;
850 }
851
852
853 /*-----------------------------------------------------------------------*\
854 | output -- output the data at the specified I/O address
855 \*-----------------------------------------------------------------------*/
856
857 void
output(z80info * z80,byte haddr,byte laddr,byte data)858 output(z80info *z80, byte haddr, byte laddr, byte data)
859 {
860 if (laddr == 0xFF) {
861 /* BIOS call - interrupt the z80 before the next instruction
862 since we may have to mess with the PC & other stuff -
863 otherwise we would do it right here */
864 z80->event = TRUE;
865 z80->halt = TRUE;
866 z80->syscall = TRUE;
867 z80->biosfn = data;
868
869 if (z80->trace)
870 {
871 printf("BIOS call %d\r\n", z80->biosfn);
872
873 if (logfile)
874 fprintf(logfile, "BIOS call %d\r\n",
875 z80->biosfn);
876 }
877 } else if (laddr == 0) {
878 /* output a character to the screen */
879 // putchar(data);
880 vt52(data);
881
882 if (logfile != NULL)
883 putc(data, logfile);
884 } else {
885 /* dump the data for our user */
886 printf("OUTPUT: addr = %X%X DATA = %X\r\n", haddr, laddr,data);
887 }
888 }
889
890
891
892 /*-----------------------------------------------------------------------*\
893 | haltcpu -- this is called after the z80 halts -- it is used for
894 | tracing & such
895 \*-----------------------------------------------------------------------*/
896
897 void
haltcpu(z80info * z80)898 haltcpu(z80info *z80)
899 {
900 z80->halt = FALSE;
901
902 /* we were interrupted by a Unix signal */
903 if (z80->sig)
904 {
905 if (z80->sig != SIGINT)
906 printf("\r\nCaught signal %d.\r\n", z80->sig);
907
908 z80->sig = 0;
909 command(z80);
910 return;
911 }
912
913 /* we are tracing execution of the z80 */
914 if (z80->trace)
915 {
916 /* re-enable tracing */
917 z80->event = TRUE;
918 z80->halt = TRUE;
919 dumptrace(z80);
920
921 if (z80->step)
922 command(z80);
923 }
924
925 /* a CP/M syscall - done here so tracing still works */
926 if (z80->syscall)
927 {
928 z80->syscall = FALSE;
929 bios(z80, z80->biosfn);
930 }
931 }
932
933 word
read_mem(z80info * z80,word addr)934 read_mem(z80info *z80, word addr)
935 {
936 #ifdef MEM_BREAK
937 if (z80->membrk[addr] & M_BREAKPOINT)
938 {
939 fprintf(stderr, "\r\nBreak at 0x%X\r\n", addr);
940 }
941 else if (z80->membrk[addr] & M_READ_PROTECT)
942 {
943 fprintf(stderr,
944 "\r\nAttempt to read protected memory at 0x%X\r\n",
945 addr);
946 }
947 else if (z80->membrk[addr] & M_MEM_MAPPED_IO)
948 {
949 fprintf(stderr,
950 "\r\nAttempt to perform mem-mapped input at 0x%X\r\n",
951 addr);
952 /* fake some sort of I/O here and return its value */
953 }
954
955 dumptrace(z80);
956 command(z80);
957 #endif /* MEM_BREAK */
958
959 return z80->mem[addr];
960 }
961
962 word
write_mem(z80info * z80,word addr,byte val)963 write_mem(z80info *z80, word addr, byte val)
964 {
965 #ifdef MEM_BREAK
966 if (z80->membrk[addr] & M_BREAKPOINT)
967 {
968 fprintf(stderr, "\r\nBreak at 0x%X\r\n", addr);
969 }
970 else if (z80->membrk[addr] & M_WRITE_PROTECT)
971 {
972 fprintf(stderr,
973 "\r\nAttempt to write to protected memory at 0x%X\r\n",
974 addr);
975 }
976 else if (z80->membrk[addr] & M_MEM_MAPPED_IO)
977 {
978 fprintf(stderr,
979 "\r\nAttempt to perform mem-mapped output at 0x%X\r\n",
980 addr);
981 /* fake some sort of I/O here and set mem to its value, */
982 /* then return */
983 }
984
985 dumptrace(z80);
986 command(z80);
987 #endif /* MEM_BREAK */
988
989 return z80->mem[addr] = val;
990 }
991
992 void
undefinstr(z80info * z80,byte instr)993 undefinstr(z80info *z80, byte instr)
994 {
995 printf("\r\nIllegal instruction 0x%.2X at PC=0x%.4X\r\n",
996 instr, PC - 1);
997 command(z80);
998 }
999
1000
1001
1002 /*-----------------------------------------------------------------------*\
1003 | quit -- terminate this program after cleaning up -- this it is |
1004 | intended to catch unused signals & not leave the terminal hosed |
1005 \*-----------------------------------------------------------------------*/
1006
1007 static void
quit(int sig)1008 quit(int sig)
1009 {
1010 printf("\r\nCaught signal %d.\r\n", sig);
1011 resetterm();
1012 exit(2);
1013 }
1014
1015
1016 /* this is needed by both interrupt() and main() */
1017 static z80info *z80 = NULL;
1018
1019
1020 /*-----------------------------------------------------------------------*\
1021 | interrupt -- this is called when we get a usable signal from Unix
1022 \*-----------------------------------------------------------------------*/
1023
1024 static void
interrupt(int s)1025 interrupt(int s)
1026 {
1027 /* we tell the z80 to stop when convenient, then reset & continue */
1028 if (z80 != NULL)
1029 {
1030 z80->event = TRUE;
1031 z80->halt = TRUE;
1032 z80->sig = s;
1033 }
1034
1035 signal(s, interrupt);
1036 }
1037
1038
1039 /*-----------------------------------------------------------------------*\
1040 | main -- set up the global vars & run the z80
1041 \*-----------------------------------------------------------------------*/
1042
1043 int
main(int argc,const char * argv[])1044 main(int argc, const char *argv[])
1045 {
1046 int x;
1047 char cmd[256];
1048 int help = 0;
1049
1050 cmd[0] = 0;
1051
1052 for (x = 1; argv[x]; ++x) {
1053 if (argv[x][0] == '-' && argv[x][1] == '-') {
1054 if (!strcmp(argv[x], "--help")) {
1055 help = 1;
1056 } else if (!strcmp(argv[x], "--nobdos")) {
1057 nobdos = 1;
1058 } else if (!strcmp(argv[x], "--trace_bdos")) {
1059 trace_bdos = 1;
1060 } else if (!strcmp(argv[x], "--strace")) {
1061 strace = 1;
1062 } else {
1063 fprintf(stderr, "Unknown option %s\n", argv[x]);
1064 exit(1);
1065 }
1066 } else {
1067 if (!cmd[0]) {
1068 strcpy(cmd, argv[x]);
1069 } else {
1070 strcat(cmd, " ");
1071 strcat(cmd, argv[x]);
1072 }
1073 }
1074 }
1075
1076 if (help) {
1077 fprintf(stderr, "\n%s [options] [CP/M command]\n", argv[0]);
1078 fprintf(stderr, "\n Options:\n\n");
1079 fprintf(stderr, " --help Show this help\n");
1080 fprintf(stderr, " --nobdos Do not emulate BDOS: only emulate BIOS\n");
1081 fprintf(stderr, " Real disk images will be used. \n");
1082 fprintf(stderr, " --trace_bdos Trace BDOS calls\n");
1083 fprintf(stderr, "\n");
1084 exit(0);
1085 }
1086
1087 if (cmd[0]) {
1088 stuff_cmd = cmd;
1089 }
1090
1091 z80 = new_z80info();
1092
1093 if (z80 == NULL)
1094 return -1;
1095
1096 initterm();
1097
1098 /* set up the signals */
1099 #ifdef SIGQUIT
1100 signal(SIGQUIT, quit);
1101 #endif
1102 #ifdef SIGHUP
1103 signal(SIGHUP, quit);
1104 #endif
1105 #ifdef SIGTERM
1106 signal(SIGTERM, quit);
1107 #endif
1108 #ifdef SIGINT
1109 signal(SIGINT, interrupt);
1110 #endif
1111
1112 setterm();
1113
1114 sysreset(z80);
1115
1116 while (1)
1117 {
1118 #ifdef macintosh
1119 EventRecord ev;
1120 WaitNextEvent(0, &ev, 0, nil);
1121 #endif
1122 z80_emulator(z80, 100000);
1123 }
1124 }
1125