V9/jtools/src/pi/m68kcore.c

Compare this file to the similar file:
Show the results in this format:

#include "process.pub"
#include "frame.pri"
#include "symtab.pri"
#include "symbol.h"
#include "m68kcore.h"
#include "asm.pri"
#include "format.pub"
#include "bpts.pri"
#include "master.pri"
SRCFILE("m68kcore.c")

char *M68kCore::read(long l,char *b,int n)	{ return readwrite(l,b,n,0); }
char *M68kCore::write(long l,char *b,int n)	{ return readwrite(l,b,0,n); }
char *M68kCore::pokedbl(long l,double d,int n)	{ return write(l,(char*)&d,n);}
int M68kCore::REG_AP()				{ return 0; }
int M68kCore::REG_FP()				{ return 14; }
int M68kCore::REG_SP()				{ return 15; }
int M68kCore::REG_PS()				{ return 16; }
int M68kCore::REG_PC()				{ return 17; }
char *M68kCore::readwrite(long, char*,int,int)	{ return "readwrite"; }
int M68kCore::instack(long, long)		{ return 1; }
int M68kCore::fpvalid(long)			{ return 1; }
Behavs M68kCore::behavetype()			{ return 0; }
char *M68kCore::dostep(long, long, int)		{ return "dostep"; }
long M68kCore::scratchaddr()			{ return 0; }
int M68kCore::nregs()				{ return 18; }
long M68kCore::regaddr()			{ return 0; }

char *M68kCore::poke(long l,long d,int n)
{
	switch (n) {
	case 1:
		return write(l, 3 + (char*)&d,n);
	case 2:
		return write(l, 2 + (char*)&d,n);
	case 4:
		return write(l,(char*)&d,n);
	default:
		return "M68kCore poke error";
	}
}

char *M68kCore::liftbpt(Trap *t)	
{
	if( behavs() == ERRORED ) return 0;
	return poke(t->stmt->range.lo, t->saved, 2);
}

#define REGBIT(r) (1 << r)
long M68kCore::saved(Frame *f, int r, int)	/* ignore size */
{
	if( r > 15 )
		return 0;
	if( !(f->regsave & REGBIT(r)) )
		return 0;
	long loc = f->regbase;
	while( --r >= 0 )
		if( f->regsave & REGBIT(r) ) loc += 4;
	return loc;
}

Asm *M68kCore::newAsm()	{ return new M68kAsm(this); }

char *M68kCore::regname(int r)
{
	static char *regnames[] = { "d0", "d1", "d2", "d3", "d4", "d5",
				   "d6", "d7", "a0", "a1", "a2", "a3",
				   "a4", "a5", "fp", "sp", "ps", "pc",
				   "usp", "isp", "vbr", "sfc", "dfc",
				   "msp", "cacr", "caar" };
	if (r < nregs())
		return regnames[r];
	else
		return 0;
}

long M68kCore::regloc(int r, int sz)
{
	if (r >= 0 && r < nregs()) {
		long ret = 4 * r + regaddr();
		if (sz && sz < 4)
			ret += 4 - sz;
		return ret;
	}
	return 0;
}


#define CYCLE 4
Cslfd *M68kCore::peek(long loc, Cslfd *fail)
{
	static i;
	static Cslfd *c;
	UCslfd u;

	if( read(loc, (char*)&u, 8) )
		return Core::peek(loc, fail);
	if( !c ) c = new Cslfd[CYCLE];
	Cslfd *p = c+(i++,i%=CYCLE);
	p->chr = u.chr;
	p->sht = u.sht;
	p->lng = u.lng;
	p->flterr = 0;
	p->flt = u.flt;
	p->dbl = u.dbl;
	return p;
}

char *M68kCore::peekstring(long loc, char *fail)
{
	static char buf[256];
	char *error = read(loc, buf, 250);
	if( error )
		return fail ? fail : strcpy(buf,error);
	return buf;
}

CallStk *M68kCore::callstack()	// do we have to peek everything twice?
{
	trace( "%d.callstack()", this );	OK(0);
	long size;
	long _fp = fp();
	if( !fpvalid(_fp))
		return (CallStk *)0;
	for( size = 1; size<1000; ++size ){
		long __fp = peek(_fp)->lng;
		if( !instack(__fp, _fp) )
			break;
		_fp = __fp;
	}
	CallStk *c = new CallStk(size, this);
	_fp = fp();
	long _pc = pc();
	for( long i = 0; i < size; ++i ){
		c->fpf[i].fp = _fp;
		c->fpf[i].func = (Func*) _symtab->loctosym(U_FUNC, _pc);
		_pc = peek(_fp+4)->lng;
		_fp = peek(_fp)->lng;
	}
	return c;
}

const short LINKA6=0x4E56, ADDLSP=0xDFFC, MOVEMLSP=0x48D7;
Frame M68kCore::frameabove(long _fp)
{
	Frame f(this);
	if( _fp ){
		f.pc = peek(_fp+4)->lng;
		f.fp = peek(_fp)->lng;
	} else {
		f.pc = pc();
		f.fp = fp();
	}
	f.ap = f.fp;
	int callpc = peek(f.fp+4)->lng;
	int inst = peek(callpc)->sht;
	f.regbase = f.fp;
	Func *funcp = (Func*)_symtab->loctosym(U_FUNC, f.pc);
	if (funcp) {
		int faddr = funcp->range.lo;
		if (peek(faddr)->sht == LINKA6) {
			f.regbase += peek(faddr+2)->sht;
			faddr += 4;
		}
		if (peek(faddr)->sht == ADDLSP) {
			f.regbase += peek(faddr+2)->lng;
			faddr += 6;
		}
		if (peek(faddr)->sht == MOVEMLSP)
			f.regsave = peek(faddr+2)->sht;
	}
	return f;
}

const short M68K_TRAP0=0x4E40, M68K_RTS = 0x4E75, M68K_UNLNKA6 = 0x4E5E;
char *M68kCore::popcallstack()
{
	long regaddr, savepc;
	char *error = 0;
	int i;
	short saveinst;
	Cslfd *c;

	if( behavetype() == ACTIVE )
		return "pop callstack: process not stopped";
	savepc = pc();
	if( peek(savepc-2)->sht == M68K_TRAP0 )
		return "pop callstack: process in system call";
	c = peek(savepc, 0);
	if( !c ) return "cannot pop callstack";
	saveinst = c->sht;
	// Must be careful if we are in the middle of the call sequence
	switch (saveinst) {
	case M68K_RTS:
		return step();
	case LINKA6:
		goto rts;
	case MOVEMLSP:
		goto unlink;
	}
	// Sometimes the space is added after the link
	if( peek(savepc-2)->sht == LINKA6 )
		goto rts;
	// Restore the registers, except the frame pointer and sp
	{ // This is here because C++ bitches about gotos if it isn't
	Frame f = frameabove(0);
	for (i = 0; i < 14; i++)
		if (regaddr = saved(&f, i, 4))
			regpoke(i, peek(regaddr)->lng);
	}
	// Pop the frame
unlink:	if( !error ) error = poke(savepc, M68K_UNLNKA6, 2);
	if( !error ) error = step();
	if( !error ) regpoke(REG_PC(), savepc);
	// Return from the subroutine
rts:	if( !error ) error = poke(savepc, M68K_RTS, 2);
	if( !error ) error = step();
	// Restore the instruction
	poke(savepc, saveinst, 2);
	return error;
}

char *M68kCore::step(long lo, long hi)
{
	return dostep(lo,hi,1);
}

const short M68K_BSR = 0x6100, M68K_JSR = 0x4e80;
const short M68K_BSR_MSK = 0xff00, M68K_JSR_MSK = 0xffc0;
char *M68kCore::stepoverM68KJSB()
{
	char *error = 0;
	static Trap *t;
	short inst;
	long fp0, offset;

	if(!t)
		t = new Trap(new Stmt(0,0,0),0);
	inst = peek(pc())->sht;
	/*
	 * Determine where to put the breakpoint depending on the
	 * addressing mode of the instruction.
	 */
	if ((inst & M68K_BSR_MSK) == M68K_BSR) {
		inst &= 0xff;
		if (inst == 0)
			offset = 4;
		else if (inst == 0xff)
			offset = 6;
		else
			offset = 2;
	} else {			/* Its a JSR */
		short reg, mode;
		reg = inst & 07;
		mode = (inst >> 3) & 0x7;
		if (mode == 7) {
			if (reg == 1)
				offset = 6;
			else if (reg == 0 || reg == 2)
				offset = 4;
			else
				goto indexed;
		} else if (mode == 2)
			offset = 2;
		else if (mode == 5)
			offset = 4;
		else {
indexed:
			inst = peek(pc()+2)->sht;
			offset = 4;
			/* Full format extension */
			if (inst & 0x0100) {
				/* Base Displacement */
				if (inst & 0x0020) {
					if (inst & 0x0010)
						offset += 4;
					else
						offset += 2;
				}
				/* Outer Displacement */
				if (inst & 0x0002) {
					if (inst & 0x0001)
						offset += 4;
					else
						offset += 2;
				}
			}
		}

	}
	t->stmt->range.lo = pc()+offset;
	fp0 = fp();
	if(error = laybpt(t))
		return error;
	for(;;) {
		error = dostep(0,0,0);
		if (error || fp() >= fp0)
			break;
		if( error = liftbpt(t) ) return error;
		if( error = dostep(0,0,1) ) return error;
		if( error = laybpt(t) ) return error;
	}
	if( !error )
		error = liftbpt(t);
	else
		liftbpt(t);
	return error;
}

int M68kCore::isM68KJSB(int inst)
{
	return (inst & M68K_BSR_MSK) == M68K_BSR ||
	       (inst & M68K_JSR_MSK) == M68K_JSR;
}

char *M68kCore::stepprolog()
{
	Func *f = (Func*)_symtab->loctosym(U_FUNC, pc());
	if (f) {
		// Only step again if we are in the function prolog
		Stmt *s = f->stmt(pc());
		if (s && s->range.lo == f->range.lo)
			process()->stmtstep(1);
	}
	return 0;
}

char *M68kCore::docall(long addr, int numarg)
{
	const int CALL_SIZE=12, JSR=0x4eb9, ADDSP=0xdffc;
	char save[CALL_SIZE], *error;
	int i;

	if( behavetype() == ACTIVE )
		return "process not stopped";
	if( !online() )
		return "cannot restart dump";
	int callstart = scratchaddr();
	for( i = 0; i < CALL_SIZE; ++i )
		save[i] = peek(callstart+i)->chr;
	if( ( error = poke(callstart+0, JSR, 2) )
	 || ( error = poke(callstart+2, addr, 4) )
	 || ( error = poke(callstart+6, ADDSP, 2) )
	 || ( error = poke(callstart+8, numarg * 4, 4) ) )
		return error;
	if( ( error = regpoke(REG_PC(), callstart) )
	 || ( error = step( callstart, callstart+CALL_SIZE) ) )
		return error;
	for( i = 0; i < CALL_SIZE; ++i )
		if( error = poke(callstart+i, save[i], 1 ) )
			return error;
	return 0;
}

long M68kCore::apforcall(int argbytes)
{
	regpoke(REG_SP(), sp() - argbytes);
	return sp() - 8;
}

long M68kCore::returnregloc()
{
	return regloc(0);
}

Context* M68kCore::newContext()
{
	M68kContext *cc = new M68kContext;
	cc->error = 0;
	cc->core = this;
	if( behavetype() == ACTIVE )
		cc->error = "context save: process not stopped";
	if( !cc->error )
		cc->error = read(regaddr(),(char*)cc->regs,sizeof(cc->regs));
	return cc;
}

void M68kContext::restore()
{
	error = core->write(core->regaddr(), (char*)regs, sizeof(regs));
}