/*****************************************************************************/
/*									     */
/*									     */
/*	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"

/* run z80 a single instruction */

void z80step(int extracond) {	
    if (bdos_emulate && z80regs.pc == BDOS)
	check_BDOS_hook();
    else if (extracond && z80regs.pc >= BIOS) {
	if (!check_BIOS_hook())		/* perform any I/O? */
	    return;				/* invalid here! */
    }
    singlestep();	/* if bios: perform return. else: do a step */
}

struct breakpoint breakpoint[NBREAKS+1];
int break_at_BIOS = 0;

/* run z80 with breakpoints on */
/* a breakpoint or listpoint sets either docontinue of mustbreak */
/* another breaking reason is a BIOS trap. BIOS traps break only */
/* if there is a breakpoint at the same location */

void z80run(void) {	
    int i, docontinue, mustbreak;
    struct breakpoint *bp;

    /* special case to allow continuous pressing of 'b' */
    z80step(break_at_BIOS);

    do {
	if (bdos_emulate && z80regs.pc == BDOS)
	    check_BDOS_hook();
	else if (z80regs.pc >= BIOS) {
	    if (break_at_BIOS) {	/* run until next BIOS call? */
		break_at_BIOS = 0;
		return;
	    }
	    if (!check_BIOS_hook())		/* perform any I/O? */
		return;				/* invalid here! */
	}
	docontinue = 0;
	mustbreak = 0;
	singlestep();	/* step over possible breakpoint */
	bp = breakpoint;	/* insert breakpoints */
	for (i = 0; i <= NBREAKS; ++i, ++bp)
	    if (bp->action) {
		bp->where &= 0xffff;
		bp->byte = z80mem[bp->where];
		z80mem[bp->where] = 0x76;		/* HALT instruction */
	    }
	if (bdos_emulate)
	    z80mem[BDOS] = 0x76;
	emulate();		/* RUN! */
	
	bp = breakpoint;	/* remove breakpoints */
	for (i = 0; i <= NBREAKS; ++i, ++bp)
	    if (bp->action)
		z80mem[bp->where] = bp->byte;	/* restore */
	
	/* check for multi-breakpoints or different actions */
	bp = breakpoint;	/* remove breakpoints */
	for (i = 0; i <= NBREAKS; ++i, ++bp)
	    if (bp->action)
		if (z80regs.pc == bp->where)	/* here we are */
		    if (++bp->curcnt == bp->maxcnt) {
			bp->curcnt = 0;
			switch (bp->action) {
			case AC_BREAK:
			    mustbreak = 1;
			    if (i != NBREAKS)
				printf("\r\nStopped at breakpoint %d\n",
				   bp-breakpoint+1);
			    break;
			case AC_LIST:
			    dispregs(z80regs.pc);
			    docontinue = 1;
			    break;
			}
		    } else
			docontinue = 1;	/* count not reached */
	if (!docontinue && !mustbreak) {
	    /* reason code: TRAP or BIOS hook or BDOS hook */
	    if ((bdos_emulate && z80regs.pc == BDOS) || z80regs.pc >= BIOS)
		docontinue = 1;
	    else
		debug = 2;	/* TRAP */
	}
    } while (docontinue);
}
