home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************/
- /* */
- /* */
- /* CP/M emulator version 0.1 */
- /* */
- /* written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de) */
- /* June-1994 */
- /* */
- /* This file is distributed under the GNU COPYRIGHT */
- /* see COPYRIGHT.GNU for Copyright details */
- /* */
- /* */
- /*****************************************************************************/
- #include "cpmemu.h"
- #include <time.h>
- #include <sys/time.h>
-
- extern int slowdown, tickercnt;
-
- static void doint(void) {
- /* execute Z80-interrupt */
-
- unsigned char rembyte;
- unsigned oldpc;
- rembyte = z80mem[oldpc = --z80regs.pc];
- z80mem[oldpc] = 0xff; /* RST 38h */
- singlestep(); /* perform RST */
- z80mem[oldpc++] = rembyte; /* restore old byte */
- do {
- singlestep();
- if (z80mem[z80regs.pc] == 0x76 || z80regs.pc >= BDOS)
- break;
- } while (z80regs.pc != oldpc);
- }
-
- void run_at_2MHz(void) {
- if (slowdown) {
- struct timeval tv1;
- struct timezone tz;
- int ctr, icnt;
- ctr = icnt = 0;
- while (!(z80mem[z80regs.pc] == 0x76 && z80regs.pc < BDOS)) {
- z80step(1);
- ++*(char *)&z80regs.ir;
- if (++ctr == slowdown) {
- ctr = 0;
- if (tickercnt && ++icnt == tickercnt) {
- /* do an interrupt */
- icnt = 0;
- if (z80regs.pc > 0x100 && z80regs.pc < BDOS &&
- !z80regs.iff) {
- doint();
- }
- } else
- gettimeofday(&tv1, &tz);
- }
- }
- } else
- z80run(); /* full speed! */
- }
-
- void commandloop(void) {
- /* forever cycle in command loop or enter GO mode */
- static int lastkey = 0;
- long memcnt = 0, currmem = 0;
- struct z80regs mem[256];
- for (;;) {
- int c;
- unsigned num, addr;
- dispregs(z80regs.pc);
- nodisplay:
- if (prompt)
- printf("Z80> "); fflush(stdout);
- while (!(c = conin()))
- ; /* c is command character */
- if (prompt)
- putchar('\r');
- if (c == '\r' || c == '\n') {
- switch (lastkey) {
- case 'l': case 'u':
- disassem(&addr, 16);
- break;
- case 'd':
- memdump(addr+=0x80, 8);
- break;
- }
- } else
- lastkey = c;
-
- switch (c) {
- case '?':
- printf("Z80 debug quick help:\n"
- "B (n) (loc) set breakpoint (n) to (loc)\n"
- "L (n) (loc) set listpoint (n) to (loc)\n"
- "N (n) (cnt) set ignore count for break/listpoint (n)\n"
- "S estimate emulation speed\n"
- "R run (continue)\n"
- "x display Z80 registers\n"
- "l (loc) disassemble memory\n"
- "d (loc) dump memory\n"
- "g go (continue)\n"
- "j (loc) jump to (loc)\n"
- "e (loc) edit byte (loc)\n"
- "; (loc) run until (loc)\n"
- "t single step one statement\n"
- "c single step; but run through subroutines\n"
- "q exit cpm emulator\n"
- "b run until next BIOS call\n"
- "i info about breakpoints\n"
- "w (loc) watch memory cell (step until it changes)\n"
- "r step until SP is incremented (RET, POP)\n"
- "all data is hexadecimal; pressing ENTER at (loc) input\n"
- "will return current PC\n");
- break;
- case 'B': /* set Breakpoint (n) */
- printf("set breakpoint ");
- num = getdig('1') - '1';
- printf(" to address ");
- breakpoint[num].where = gethex();
- breakpoint[num].action = AC_BREAK;
- breakpoint[num].maxcnt = 1;
- breakpoint[num].curcnt = 0;
- break;
- case 'L': /* set listpoint (n) */
- printf("set listpoint ");
- num = getdig('1') - '1';
- printf(" to address ");
- breakpoint[num].where = gethex();
- breakpoint[num].action = AC_LIST;
- breakpoint[num].maxcnt = 1;
- breakpoint[num].curcnt = 0;
- break;
- case 'N': /* number break- or listpoint (n) */
- printf("Number break/listpoint ");
- num = getdig('1') - '1';
- printf(" to maxcount ");
- breakpoint[num].maxcnt = getdig(0);
- breakpoint[num].curcnt = 0;
- if (!breakpoint[num].maxcnt)
- breakpoint[num].action = AC_NONE;
- break;
- case 'S': /* measure speed */
- printf("Estimating speed... "); fflush(stdout);
- { struct z80regs saveregs;
- clock_t t;
- long cycles;
- static unsigned char benchmark[24] = {
- 0x1e, 0x06, /* ld e,6 */
- 0x01, 0x00, 0x00, /* ld bc,0 */
- 0x0a, /* 7T: ld a,(bc) */
- 0x65, /* 4T: ld h,l */
- 0x54, /* 4T: ld d,h */
- 0x21, 0x33, 0x33, /* 10T: ld hl,3333 */
- 0x0b, /* 6T: dec bc */
- 0x78, /* 4T: ld a,b */
- 0xb1, /* 4T: or c */
- 0x38, 0xef, /* 5T: jr false */
- 0xc2, 0x05, 0x01, /* 10T: jp true */
- 0x1d, /* dec e */
- 0x20, 0xec, /* jr nz,102 */
- 0x76 /* HALT */
- }, savemem[24];
- memcpy(savemem, z80mem+0x100, 24);
- memcpy(z80mem+0x100, benchmark, 24);
- saveregs = z80regs;
- z80regs.pc = 0x100;
- t = clock();
- z80run();
- t = clock() - t;
- cycles = 6L * 65536L * 54L;/* should be 54T on a genuine Z80 */
- #if 1
- z80regs = saveregs;
- memcpy(z80mem+0x100, savemem, 24);
- #endif
- printf("Your Z80 roams at %f MHz\n",
- (double)cycles * 1e-6 / t * CLOCKS_PER_SEC);
- }
- break;
- case 'R': /* run the program */
- z80run();
- break;
- case 'x':
- /* dispregs(z80regs.pc); */
- dispregs2();
- break;
- case 'l':
- printf("list from loc: ");
- addr = gethex();
- disassem(&addr, 16);
- goto nodisplay;
- case 'd':
- /* display memory */
- printf("dump memory at: ");
- addr = gethex();
- memdump(addr, 8);
- goto nodisplay;
- case 'g': /* GO */
- debug = 0;
- return;
- case 'j':
- printf("jump to: ");
- z80regs.pc = gethex();
- break;
- case 'e':
- printf("edit byte: "); /* abort with ctrl-@ */
- addr = gethex();
- for (;;) {
- printf("%04x %02x ", addr, z80mem[addr]);
- num = gethex();
- z80mem[addr++] = num;
- }
- /* never reaches this */
- case ';':
- printf("run until ");
- breakpoint[NBREAKS].where = gethex();
- xcall:
- breakpoint[NBREAKS].action = AC_BREAK;
- breakpoint[NBREAKS].maxcnt = 1;
- breakpoint[NBREAKS].curcnt = 0;
- z80run();
- breakpoint[NBREAKS].action = AC_NONE;
- break;
- case 'c': /* trace over CALLs and RSTs */
- switch (z80mem[z80regs.pc]) {
- case 0xcd:
- case 0xc4: case 0xcc: case 0xd4: case 0xdc:
- case 0xe4: case 0xec: case 0xf4: case 0xfc:
- breakpoint[NBREAKS].where = z80regs.pc + 3;
- goto xcall;
- case 0xf7: /* short BDOS call */
- breakpoint[NBREAKS].where = z80regs.pc + 2;
- goto xcall;
- case 0xc7: case 0xcf: case 0xd7: case 0xdf:
- case 0xe7: case 0xef: case 0xff:
- breakpoint[NBREAKS].where = z80regs.pc + 1;
- goto xcall;
- } /* else fall thru */
- case 't':
- z80step(1);
- break;
- case 'q':
- exit(0);
- case 'b':
- break_at_BIOS = 1;
- z80run();
- break;
- case 'i': /* info */
- { struct breakpoint *bp;
- int i;
- bp = breakpoint;
- for (i = 0; i < NBREAKS; ++i, ++bp)
- if (bp->action)
- printf("BP %d (count %d of %d) is set at %04x, type %s\n", i, bp->curcnt, bp->maxcnt, bp->where, bp->action == AC_BREAK ? "BREAK" : "LIST");
- printf("last location of 'c' breakpoint: %04x\n", bp->where);
- }
- break;
- case 'w':
- printf("watch mem cell: ");
- addr = gethex();
- num = z80mem[addr];
- do {
- unsigned oldpc;
- oldpc = z80regs.pc;
- z80step(1);
- if (z80regs.pc == oldpc && z80mem[z80regs.pc] != 0x10)
- break; /* break, but not on djnz $ */
- } while (z80mem[addr] == num);
- break;
- case 'r':
- printf("running...\n");
- addr = z80regs.sp + 2;
- do {
- z80step(1);
- if (z80mem[z80regs.pc] == 0x76 && z80regs.pc < BDOS)
- break;
- } while (z80regs.sp != addr);
- break;
- case 'T': /* trace... */
- printf("Trace until ");
- addr = gethex();
- do {
- dispregs(z80regs.pc);
- z80step(1);
- if (z80mem[z80regs.pc] == 0x76 && z80regs.pc < BDOS)
- break;
- } while (z80regs.pc != addr);
- break;
- case 'M': /* memorize... */
- printf("Memorize until: ");
- addr = gethex();
- memcnt = 0;
- do {
- mem[memcnt & 255] = z80regs;
- z80step(1);
- if (z80mem[z80regs.pc] == 0x76 && z80regs.pc < BDOS)
- break;
- ++memcnt;
- } while (z80regs.pc != addr);
- currmem = memcnt & 255;
- break;
- case 'U': /* memorize... */
- printf("Watch: ");
- memcnt = 0;
- do {
- mem[memcnt & 255] = z80regs;
- z80step(1);
- if (z80mem[z80regs.pc] == 0x76 && z80regs.pc < BDOS)
- break;
- ++memcnt;
- } while (z80mem[0x4d04] != 0xee && z80mem[0x4d04] != 0xbc);
- currmem = memcnt & 255;
- break;
- case '+':
- z80regs = mem[currmem = (currmem+1) & 255];
- printf("die - %ld:\n", (memcnt-currmem+256) & 255);
- break;
- case '-':
- z80regs = mem[currmem = (currmem+255) & 255];
- printf("die - %ld:\n", (memcnt-currmem+256) & 255);
- break;
- case '2': /* run at 2 MHz */
- printf("running at 2 MHz\n");
- run_at_2MHz();
- break;
- default:
- goto nodisplay;
- }
- }
- }
-