716 lines
15 KiB
C
716 lines
15 KiB
C
#ifndef lint
|
|
static char sccsid[] = "@(#)machdep.c 1.1 92/07/30";
|
|
#endif
|
|
|
|
/*
|
|
* Copyright (c) 1986 by Sun Microsystems, Inc.
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/vmmac.h>
|
|
#include <sun4/buserr.h>
|
|
#include <sun4/enable.h>
|
|
#include <sun4/mmu.h>
|
|
#include <sun4/cpu.h>
|
|
#include <sun4/pte.h>
|
|
#include <sun4/scb.h>
|
|
#include <sun4/psl.h>
|
|
#include <sun4/trap.h>
|
|
#include <sun4/clock.h>
|
|
#include <sun4/intreg.h>
|
|
#include "reg.h"
|
|
#include "../../debug/debug.h"
|
|
#include "../../debug/debugger.h"
|
|
#include "asm_linkage.h"
|
|
|
|
extern int errno;
|
|
#define DVMA 0xfff00000
|
|
|
|
int istrap = 0;
|
|
int scbsyncdone = 0;
|
|
|
|
int cpudelay = 0; /* old macros: shift right amount to scale (n << 4) */
|
|
int Cpudelay = 11; /* new macros: count down counter initial value */
|
|
int cpu;
|
|
|
|
int vac_linesize; /* number of bytes in a cache line */
|
|
int vac_pglines; /* number of cache lines in a page */
|
|
int vac_nlines; /* number of cache lines in cache */
|
|
|
|
int fake_bpt; /* place for a fake breakpoint at startup */
|
|
jmp_buf debugregs; /* context for debugger */
|
|
jmp_buf mainregs; /* context for debuggee */
|
|
jmp_buf_ptr curregs; /* pointer to saved context for each process */
|
|
int cache_on; /* cache is being used */
|
|
struct allregs regsave; /* temp save area */
|
|
|
|
int clock_type;
|
|
static int clock_peek = 0;
|
|
unsigned long old_clock0_pte, old_counter_pte; /* save old ptes */
|
|
extern char estack[], etext[];
|
|
|
|
/*
|
|
* Definitions for registers in jmp_buf
|
|
*/
|
|
#define JB_PC 0
|
|
#define JB_SP 1
|
|
|
|
static jmp_buf state; /* used for temporary games */
|
|
|
|
/*
|
|
* Startup code after relocation.
|
|
*/
|
|
startup()
|
|
{
|
|
register int i;
|
|
register int pg;
|
|
u_char intreg;
|
|
extern Setpgmap();
|
|
extern char start[], end[], etext[];
|
|
|
|
#ifndef SAS
|
|
set_clock_ptes();
|
|
#endif !SAS
|
|
Setpgmap((caddr_t)INTREG_ADDR,
|
|
PG_V|PG_KW|PGT_OBIO|btop(OBIO_INTREG_ADDR));
|
|
|
|
set_clock_type();
|
|
set_clk_mode(IR_ENA_CLK14, 0);
|
|
/*
|
|
* Fix up old scb.
|
|
*/
|
|
kadbscbsync();
|
|
spl13(); /* we can take nmi's now */
|
|
|
|
/*
|
|
* Now make text (and dvec) read only,
|
|
* this also sets a stack redzone
|
|
*/
|
|
for (i = (int)start; i < (int)etext; i += NBPG) {
|
|
pg = Getpgmap(i);
|
|
Setpgmap(i, (pg & ~PG_PROT) | PG_KR);
|
|
}
|
|
|
|
cpu = getmachinetype();
|
|
switch (cpu) {
|
|
case SUN4_ARCH: /* proto 1 */
|
|
case CPU_SUN4_260:
|
|
case CPU_SUN4_110:
|
|
case CPU_SUN4_330:
|
|
case CPU_SUN4_470:
|
|
break;
|
|
default:
|
|
printf("%s: UNKNOWN MACHINE TYPE IN ID PROM\n", myname);
|
|
printf("%s: DEFAULTING MACHINE TYPE TO SUN4_260\n",
|
|
myname);
|
|
cpu = CPU_SUN4_260;
|
|
break;
|
|
}
|
|
if (cpu != CPU_SUN4_110)
|
|
cache_on = getenablereg() & ENA_CACHE;
|
|
if (cache_on || (cpu == CPU_SUN4_110)) {
|
|
cpudelay = 1;
|
|
} else {
|
|
cpudelay = 4;
|
|
vac_init(); /* invalidate entire cache */
|
|
}
|
|
}
|
|
|
|
asm(" .align 4 ");
|
|
asm("_tcode: ");
|
|
asm(" sethi %hi(_trap), %l3 ");
|
|
asm(" or %l3, %lo(_trap), %l3 ");
|
|
asm(" jmp %l3 ");
|
|
asm(" mov %psr, %l0 ");
|
|
|
|
scbsync()
|
|
{
|
|
kadbscbsync();
|
|
scbsyncdone = 1;
|
|
}
|
|
|
|
kadbscbsync()
|
|
{
|
|
register struct scb *tbr;
|
|
register int otbr_pg;
|
|
extern trapvec tcodee;
|
|
extern trapvec tcode;
|
|
extern struct scb *gettbr();
|
|
|
|
tbr = gettbr();
|
|
otbr_pg = Getpgmap(tbr);
|
|
Setpgmap(tbr, (otbr_pg & ~PG_PROT) | PG_KW);
|
|
|
|
tbr->user_trap[TRAPBRKNO-1] = tcode;
|
|
tbr->user_trap[TRAPBRKNO] = tcode;
|
|
Setpgmap(tbr, otbr_pg);
|
|
if (scbstop) {
|
|
/*
|
|
* Set things up so that we call the debugger.
|
|
* Use _setjmp()/_longjmp() with some adjustments
|
|
* to pull this non-local goto off correctly.
|
|
*/
|
|
scbstop = 0;
|
|
#ifdef notdef
|
|
(void) _setjmp(state);
|
|
state[JB_PC] = DVEC-8; /* new pc value */
|
|
state[JB_SP] = *(int *)state[JB_SP]; /* new sp value */
|
|
_longjmp(state, 1);
|
|
/*NOTREACHED*/
|
|
#endif
|
|
asm(" t 126 /*TRAPBRKNO*/ -1 ");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Set and/or clear the desired clock bits in the interrupt
|
|
* register. We have to be extremely careful that we do it
|
|
* in such a manner that we don't get ourselves lost.
|
|
*/
|
|
set_clk_mode(on, off)
|
|
u_char on, off;
|
|
{
|
|
register u_char intreg, dummy;
|
|
register int s;
|
|
|
|
/* XXX - need SUNRAY support */
|
|
|
|
#ifndef SAS
|
|
/*
|
|
* make sure that we are only playing w/
|
|
* clock interrupt register bits
|
|
*/
|
|
on &= (IR_ENA_CLK14 | IR_ENA_CLK10);
|
|
off &= (IR_ENA_CLK14 | IR_ENA_CLK10);
|
|
|
|
s = splhi();
|
|
/*
|
|
* Get a copy of current interrupt register,
|
|
* turning off any undesired bits (aka `off')
|
|
*/
|
|
intreg = *INTREG & ~(off | IR_ENA_INT);
|
|
*INTREG &= ~IR_ENA_INT;
|
|
|
|
/*
|
|
* Next we turns off the CLK10 and CLK14 bits to clear
|
|
* the flip-flops, then we disable clock interrupts.
|
|
* Now we can read the clock's interrupt register
|
|
* to clear any pending signals there.
|
|
*/
|
|
*INTREG &= ~(IR_ENA_CLK14 | IR_ENA_CLK10);
|
|
if (clock_type == INTERSIL7170) {
|
|
CLOCK0->clk_cmd = (CLK_CMD_NORMAL & ~CLK_CMD_INTRENA);
|
|
dummy = CLOCK0->clk_intrreg; /* clear clock */
|
|
}
|
|
else {
|
|
dummy = COUNTER->limit10;
|
|
dummy = COUNTER->limit14;
|
|
}
|
|
|
|
#ifdef lint
|
|
dummy = dummy;
|
|
#endif
|
|
|
|
/*
|
|
* Now we set all the desired bits
|
|
* in the interrupt register, then
|
|
* we turn the clock back on and
|
|
* finally we can enable all interrupts.
|
|
*/
|
|
*INTREG |= (intreg | on); /* enable flip-flops */
|
|
if (clock_type == INTERSIL7170) {
|
|
CLOCK0->clk_cmd = CLK_CMD_NORMAL; /* enable clock intr */
|
|
}
|
|
*INTREG |= IR_ENA_INT; /* enable interrupts */
|
|
(void)splx(s);
|
|
#endif !SAS
|
|
}
|
|
|
|
/*
|
|
* Sys_trap trap handlers.
|
|
*/
|
|
|
|
/*
|
|
* level15 (memory error) interrupt.
|
|
*/
|
|
level15()
|
|
{
|
|
/*
|
|
* For now, the memory error regs are not mapped into the debugger,
|
|
* so we just print a message.
|
|
*/
|
|
printf("memory error\n");
|
|
}
|
|
|
|
/*
|
|
* Miscellanous fault error handler
|
|
*/
|
|
fault(trap, trappc, trapnpc)
|
|
register int trap;
|
|
register int trappc;
|
|
register int trapnpc;
|
|
{
|
|
register int ondebug_stack;
|
|
register u_int *pc;
|
|
register u_int realpc;
|
|
|
|
ondebug_stack = (getsp() > (int)etext && getsp() < (int)estack);
|
|
if (trap == T_DATA_FAULT && nofault && ondebug_stack) {
|
|
jmp_buf_ptr sav = nofault;
|
|
|
|
nofault = NULL;
|
|
_longjmp(sav, 1);
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
/*
|
|
showregs(ondebug_stack ? "unexpected fault" : "unexpected exception",
|
|
getsp());
|
|
*/
|
|
|
|
/*
|
|
* If we are on the debugger stack and
|
|
* abort_jmp is set, do a longjmp to it.
|
|
*/
|
|
if (abort_jmp && ondebug_stack) {
|
|
printf("abort jump\n");
|
|
_longjmp(abort_jmp, 1);
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
if (clock_peek) { /* we were peeking for clock type */
|
|
jmp_buf_ptr sav = nofault;
|
|
|
|
nofault = NULL;
|
|
_longjmp(sav, 1);
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
/*
|
|
* Ok, the user faulted while not in the
|
|
* debugger. Enter the main cmd loop
|
|
* so that the user can look around...
|
|
*/
|
|
/*
|
|
* There is a problem here since we really need to tell cmd()
|
|
* the current registers. We would like to call cmd() in locore
|
|
* but the interface is not really set up to handle this (yet?)
|
|
*/
|
|
|
|
printf("fault and call cmd %x %x %x %x\n",
|
|
trap,getsp(),trappc,trapnpc);
|
|
cmd(); /* error not resolved, ether debugger */
|
|
}
|
|
long trap_window[25];
|
|
|
|
showregs(str, locregs)
|
|
register char *str;
|
|
register struct allregs *locregs;
|
|
{
|
|
/* printf("g1-g7: %x, %x, %x, %x, %x, %x, %x\n",
|
|
rp->r_g1, rp->r_g2, rp->r_g3,
|
|
rp->r_g4, rp->r_g5, rp->r_g6, rp->r_g7);
|
|
printf("trap_window: wim=%x\n", trap_window[24]);
|
|
printf("o0-o7: %x, %x, %x, %x, %x, %x, %x, %x\n",
|
|
trap_window[0], trap_window[1], trap_window[2], trap_window[3],
|
|
trap_window[4], trap_window[5], trap_window[6], trap_window[7]);
|
|
printf("l0-l7: %x, %x, %x, %x, %x, %x, %x, %x\n",
|
|
trap_window[8], trap_window[9], trap_window[10], trap_window[11],
|
|
trap_window[12], trap_window[13], trap_window[14], trap_window[15]);
|
|
printf("i0-i7: %x, %x, %x, %x, %x, %x, %x, %x\n",
|
|
trap_window[16], trap_window[17], trap_window[18], trap_window[19],
|
|
trap_window[20], trap_window[21], trap_window[22], trap_window[23]);
|
|
|
|
#ifndef SAS
|
|
DELAY(2000000);
|
|
#endif
|
|
(void) splx(s);
|
|
*/
|
|
}
|
|
|
|
static jmp_buf_ptr saved_jb;
|
|
static jmp_buf jb;
|
|
extern int debugging;
|
|
|
|
|
|
/*
|
|
* Peekc is so named to avoid a naming conflict
|
|
* with adb which has a variable named peekc
|
|
*/
|
|
int
|
|
Peekc(addr)
|
|
char *addr;
|
|
{
|
|
u_char val;
|
|
|
|
saved_jb = nofault;
|
|
nofault = jb;
|
|
errno = 0;
|
|
if (!_setjmp(jb)) {
|
|
val = *addr;
|
|
/* if we get here, it worked */
|
|
nofault = saved_jb;
|
|
return ((int)val);
|
|
}
|
|
/* a fault occured */
|
|
nofault = saved_jb;
|
|
errno = EFAULT;
|
|
return (-1);
|
|
}
|
|
|
|
short
|
|
peek(addr)
|
|
short *addr;
|
|
{
|
|
short val;
|
|
|
|
saved_jb = nofault;
|
|
nofault = jb;
|
|
errno = 0;
|
|
if (!_setjmp(jb)) {
|
|
val = *addr;
|
|
/* if we get here, it worked */
|
|
nofault = saved_jb;
|
|
return (val);
|
|
}
|
|
/* a fault occured */
|
|
nofault = saved_jb;
|
|
errno = EFAULT;
|
|
return (-1);
|
|
}
|
|
long
|
|
peekl(addr)
|
|
long *addr;
|
|
{
|
|
long val;
|
|
|
|
saved_jb = nofault;
|
|
nofault = jb;
|
|
errno = 0;
|
|
if (!_setjmp(jb)) {
|
|
val = *addr;
|
|
/* if we get here, it worked */
|
|
nofault = saved_jb;
|
|
return (val);
|
|
}
|
|
/* a fault occured */
|
|
nofault = saved_jb;
|
|
errno = EFAULT;
|
|
return (-1);
|
|
}
|
|
|
|
int
|
|
pokec(addr, val)
|
|
char *addr;
|
|
char val;
|
|
{
|
|
|
|
saved_jb = nofault;
|
|
nofault = jb;
|
|
errno = 0;
|
|
if (!_setjmp(jb)) {
|
|
*addr = val;
|
|
/* if we get here, it worked */
|
|
nofault = saved_jb;
|
|
return (0);
|
|
}
|
|
/* a fault occured */
|
|
nofault = saved_jb;
|
|
errno = EFAULT;
|
|
return (-1);
|
|
}
|
|
|
|
int
|
|
pokel(addr, val)
|
|
long *addr;
|
|
long val;
|
|
{
|
|
|
|
saved_jb = nofault;
|
|
nofault = jb;
|
|
errno = 0;
|
|
if (!_setjmp(jb)) {
|
|
*addr = val;
|
|
/* if we get here, it worked */
|
|
nofault = saved_jb;
|
|
return (0);
|
|
}
|
|
/* a fault occured */
|
|
nofault = saved_jb;
|
|
errno = EFAULT;
|
|
return (-1);
|
|
}
|
|
|
|
poketext(addr, val)
|
|
int *addr;
|
|
int val;
|
|
{
|
|
int pg = 0, i;
|
|
|
|
pg = Getpgmap((int)addr);
|
|
if ((pg & PG_V) == 0) {
|
|
if (debugging > 2)
|
|
printf("poketext: invalid page map %X at %X\n",
|
|
pg, addr);
|
|
goto err;
|
|
}
|
|
if ((pg & PGT_MASK) != PGT_OBMEM) {
|
|
if (debugging > 2)
|
|
printf("poketext: incorrect page type %X at %X\n",
|
|
pg, addr);
|
|
goto err;
|
|
}
|
|
|
|
if ((cpu != CPU_SUN4_110) && !(pg&PG_NC)){
|
|
vac_pageflush(addr);
|
|
if (btop(addr + sizeof (int) - 1) != btop(addr))
|
|
vac_pageflush(addr + sizeof (int) - 1);
|
|
}
|
|
|
|
if ((pg & PG_PROT) == PG_KR)
|
|
Setpgmap(addr, (pg & ~PG_PROT) | PG_KW);
|
|
else if ((pg & PG_PROT) == PG_URKR)
|
|
Setpgmap(addr, (pg & ~PG_PROT) | PG_UW);
|
|
/* otherwise it is already writeable */
|
|
*addr = val; /* should be prepared to catch a fault here? */
|
|
/*
|
|
* Reset to page map to previous entry,
|
|
* but mark as modified
|
|
*/
|
|
if ((cpu != CPU_SUN4_110) && !(pg&PG_NC)){
|
|
vac_pageflush(addr);
|
|
if (btop(addr + sizeof (int) - 1) != btop(addr))
|
|
vac_pageflush(addr + sizeof (int) - 1);
|
|
}
|
|
Setpgmap(addr, pg | PG_M);
|
|
errno = 0;
|
|
return (0);
|
|
|
|
err:
|
|
errno = EFAULT;
|
|
return (-1);
|
|
}
|
|
|
|
scopy(from, to, count)
|
|
register char *from;
|
|
register char *to;
|
|
register int count;
|
|
{
|
|
register int val;
|
|
|
|
for (; count > 0; count--) {
|
|
if ((val = Peekc(from++)) == -1)
|
|
goto err;
|
|
if (pokec(to++, val) == -1)
|
|
goto err;
|
|
}
|
|
return (0);
|
|
err:
|
|
errno = EFAULT;
|
|
return (-1);
|
|
}
|
|
|
|
/*
|
|
* Setup a new context to run at routine using stack whose
|
|
* top (end) is at sp. Assumes that the current context
|
|
* is to be initialized for mainregs and new context is
|
|
* to be set up in debugregs.
|
|
*/
|
|
spawn(sp, routine)
|
|
char *sp;
|
|
func_t routine;
|
|
{
|
|
char *fp;
|
|
|
|
if (curregs != 0) {
|
|
printf("bad call to spawn\n");
|
|
exit(1);
|
|
}
|
|
if (!_setjmp(mainregs)) {
|
|
/*
|
|
* Setup top (null) window.
|
|
*/
|
|
sp -= WINDOWSIZE;
|
|
((struct rwindow *)sp)->rw_rtn = 0;
|
|
((struct rwindow *)sp)->rw_fp = 0;
|
|
/*
|
|
* Setup window for routine with return to exit.
|
|
*/
|
|
fp = sp;
|
|
sp -= WINDOWSIZE;
|
|
((struct rwindow *)sp)->rw_rtn = (int)exit - 8;
|
|
((struct rwindow *)sp)->rw_fp = (int)fp;
|
|
/*
|
|
* Setup new return window with routine return value.
|
|
*/
|
|
fp = sp;
|
|
sp -= WINDOWSIZE;
|
|
((struct rwindow *)sp)->rw_rtn = (int)routine - 8;
|
|
((struct rwindow *)sp)->rw_fp = (int)fp;
|
|
/* copy entire jump buffer to debugregs */
|
|
bcopy((caddr_t)mainregs, (caddr_t)debugregs, sizeof (jmp_buf));
|
|
debugregs[JB_SP] = (int)sp; /* set sp */
|
|
curregs = debugregs;
|
|
regsave.r_npc = (int)&fake_bpt;
|
|
_longjmp(debugregs, 1);/* jump to new context */
|
|
/*NOTREACHED*/
|
|
}
|
|
}
|
|
|
|
|
|
doswitch()
|
|
{
|
|
|
|
if (!_setjmp(curregs)) {
|
|
/*
|
|
* Switch curregs to other descriptor
|
|
*/
|
|
if (curregs == mainregs) {
|
|
curregs = debugregs;
|
|
} else /* curregs == debugregs */ {
|
|
curregs = mainregs;
|
|
}
|
|
_longjmp(curregs, 1);
|
|
/*NOTREACHED*/
|
|
}
|
|
/*
|
|
* else continue on in new context
|
|
*/
|
|
}
|
|
|
|
/*
|
|
* Main interpreter command loop.
|
|
*/
|
|
cmd()
|
|
{
|
|
int resetclk = 0;
|
|
u_char intreg;
|
|
int addr, t;
|
|
int i;
|
|
u_char interreg;
|
|
int s;
|
|
|
|
dorun = 0;
|
|
|
|
/*
|
|
* See if the sp says that we are already on the debugger stack
|
|
*/
|
|
reg = (struct regs *)®save;
|
|
addr = getsp();
|
|
if (addr > (int)etext && addr < (int)estack) {
|
|
printf("Already in debugger!\n");
|
|
return;
|
|
}
|
|
if (cpu == CPU_SUN4_260)
|
|
cache_on = getenablereg() & ENA_CACHE;
|
|
if (cache_on || (cpu == CPU_SUN4_110))
|
|
cpudelay = 1;
|
|
else
|
|
cpudelay = 4;
|
|
/*
|
|
* Set up for monitor's input routines to work. This
|
|
* requires that we call the monitor's nmi handler on level14
|
|
* clock interrupts and that interrupts and level14 clock
|
|
* interrupt are enabled.
|
|
*/
|
|
if ((*INTREG & (IR_ENA_INT | IR_ENA_CLK14)) !=
|
|
(IR_ENA_INT | IR_ENA_CLK14)) {
|
|
resetclk = 1;
|
|
interreg = *INTREG;
|
|
set_clk_mode(IR_ENA_CLK14, 0);
|
|
}
|
|
s = spl13();
|
|
do {
|
|
doswitch();
|
|
if (dorun == 0)
|
|
printf("cmd: nothing to do\n");
|
|
} while (dorun == 0);
|
|
if (resetclk) {
|
|
set_clk_mode(0, IR_ENA_CLK14);
|
|
*INTREG = interreg;
|
|
}
|
|
/* we don't need to splx since we are returning to the caller */
|
|
/* and will reset his/her state */
|
|
}
|
|
|
|
void
|
|
vac_init()
|
|
{
|
|
if (cpu == CPU_SUN4_470) {
|
|
vac_linesize = VAC_LINESIZE_SUNRAY;
|
|
} else {
|
|
vac_linesize = VAC_LINESIZE_SUNRISE;
|
|
}
|
|
vac_nlines = VAC_SIZE / vac_linesize;
|
|
vac_pglines = PAGESIZE / vac_linesize;
|
|
vac_tagsinit();
|
|
}
|
|
|
|
|
|
|
|
set_clock_type() {
|
|
|
|
clock_peek = 1;
|
|
if (Peekc((char *)&CLOCK0->clk_hsec) != -1) {
|
|
clock_type = INTERSIL7170; /* put back other old pte */
|
|
Setpgmap((caddr_t)COUNTER_ADDR, old_counter_pte);
|
|
}
|
|
else {
|
|
clock_type = MOSTEK48T02; /* put back other old pte */
|
|
Setpgmap((caddr_t)CLOCK0_ADDR, old_clock0_pte);
|
|
}
|
|
clock_peek = 0;
|
|
}
|
|
|
|
/*
|
|
* Return an available physical page number
|
|
*/
|
|
int
|
|
getapage()
|
|
{
|
|
extern int lastpg;
|
|
|
|
return (--lastpg);
|
|
}
|
|
|
|
#ifndef SAS
|
|
set_clock_ptes() {
|
|
|
|
caddr_t i;
|
|
int segm;
|
|
|
|
/* copy old ptes, put the unused page pte back to what it was */
|
|
|
|
old_clock0_pte = Getpgmap((caddr_t)CLOCK0_ADDR);
|
|
old_counter_pte = Getpgmap((caddr_t)COUNTER_ADDR);
|
|
|
|
i = (caddr_t) CLOCK0_ADDR;
|
|
|
|
/* KLUDGE
|
|
The last seg may not be mapped in by eporom. Only the sun4s
|
|
with intel ethernet chip have the last smeg mapped in.
|
|
For example, sun4_260 has the last smg mapped in while
|
|
sun4_330 does not (because 4_330 uses LANCE ethernet chip).
|
|
*/
|
|
if ((segm = Getsegmap(i)) == (npmgrps-1)) {
|
|
segm = --lastpm;
|
|
Setsegmap((caddr_t)CLOCK0_ADDR, segm);
|
|
}
|
|
|
|
Setpgmap((caddr_t)CLOCK0_ADDR, /* intersil clock */
|
|
PG_V|PG_KW|PGT_OBIO|btop(OBIO_CLOCK_ADDR));
|
|
|
|
Setpgmap((caddr_t)COUNTER_ADDR, /* mostek clock */
|
|
PG_V|PG_KW|PGT_OBIO|btop(OBIO_COUNTER_ADDR));
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Call into the monitor (hopefully)
|
|
*/
|
|
montrap()
|
|
{
|
|
(*romp->v_exit_to_mon)();
|
|
}
|