*
* g return the value of the CPU registers hex data or ENN
* G set the value of the CPU registers OK or ENN
+ * P set the value of a single CPU register OK or ENN
*
* mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
* MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
*
* ? What was the last sigval ? SNN (signal NN)
*
- * bBB..BB Set baud rate to BB..BB OK or BNN, then sets
- * baud rate
- *
* All commands and responses are sent with a packet which includes a
* checksum. A packet consists of
*
#include <string.h>
#include <signal.h>
+#include <sparclite.h>
/************************************************************************
*
* external low-level support routines
*/
-extern putDebugChar(); /* write a single character */
-extern getDebugChar(); /* read and return a single char */
+extern void putDebugChar (int c); /* write a single character */
+extern int getDebugChar (void); /* read and return a single char */
/************************************************************************/
/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
static int initialized = 0; /* !0 means we've been initialized */
-extern void breakinst();
-static void hw_breakpoint();
-static void set_mem_fault_trap();
-static void get_in_break_mode();
+extern void breakinst ();
+static void set_mem_fault_trap (int enable);
+static void get_in_break_mode (void);
static const char hexchars[]="0123456789abcdef";
extern void trap_low();
+/* Create private copies of common functions used by the stub. This prevents
+ nasty interactions between app code and the stub (for instance if user steps
+ into strlen, etc..) */
+
+static char *
+strcpy (char *dst, const char *src)
+{
+ char *retval = dst;
+
+ while ((*dst++ = *src++) != '\000');
+
+ return retval;
+}
+
+static void *
+memcpy (void *vdst, const void *vsrc, int n)
+{
+ char *dst = vdst;
+ const char *src = vsrc;
+ char *retval = dst;
+
+ while (n-- > 0)
+ *dst++ = *src++;
+
+ return retval;
+}
+
asm("
.reserve trapstack, 1000 * 4, \"bss\", 8
! underflow) occurs. It makes sure that the invalid register window is still
! available before jumping into C code. It will also restore the world if you
! return from handle_exception.
+!
+! On entry, trap_low expects l1 and l2 to contain pc and npc respectivly.
+! Register usage throughout the routine is as follows:
+!
+! l0 - psr
+! l1 - pc
+! l2 - npc
+! l3 - wim
+! l4 - scratch and y reg
+! l5 - scratch and tbr
+! l6 - unused
+! l7 - unused
.globl _trap_low
_trap_low:
srl %l3, 1, %g1 ! Rotate wim right
tst %g1
bg good_wim ! Branch if new wim is non-zero
+ nop
! At this point, we need to bring a 1 into the high order bit of the wim.
! Since we don't want to make any assumptions about the number of register
std %i2, [%sp + (24 + 10) * 4]
std %i4, [%sp + (24 + 12) * 4]
std %i6, [%sp + (24 + 14) * 4]
- ! F0->F31 not implemented
+
mov %y, %l4
mov %tbr, %l5
st %l4, [%sp + (24 + 64) * 4] ! Y
st %l5, [%sp + (24 + 67) * 4] ! TBR
st %l1, [%sp + (24 + 68) * 4] ! PC
st %l2, [%sp + (24 + 69) * 4] ! NPC
- ! CPSR and FPSR not impl
- or %l0, 0xf20, %l4
- mov %l4, %psr ! Turn on traps, disable interrupts
- nop
- nop
- nop
- call _get_in_break_mode
- nop
- nop
- nop
- sethi %hi(0xff00), %l5
- or %l5, %lo(0xff00), %l5
-
- lda [%l5]0x1, %l4
- st %l4, [%sp + (24 + 72) * 4] ! DIA1, debug instr addr 1
- add %l5, 4, %l5
- lda [%l5]0x1, %l4
- st %l4, [%sp + (24 + 73) * 4] ! DIA2, debug instr addr 2
- add %l5, 4, %l5
- lda [%l5]0x1, %l4
- st %l4, [%sp + (24 + 74) * 4] ! DDA1, debug data addr 1
- add %l5, 4, %l5
- lda [%l5]0x1, %l4
- st %l4, [%sp + (24 + 75) * 4] ! DDA2, debug data addr 2
- add %l5, 4, %l5
- lda [%l5]0x1, %l4
- st %l4, [%sp + (24 + 76) * 4] ! DDV1, debug data val 1
- add %l5, 4, %l5
- lda [%l5]0x1, %l4
- st %l4, [%sp + (24 + 77) * 4] ! DDV2, debug data val 2
- add %l5, 4, %l5
- lda [%l5]0x1, %l4
- st %l4, [%sp + (24 + 78) * 4] ! DCR, debug control reg
- add %l5, 4, %l5
- lda [%l5]0x1, %l4
- st %l4, [%sp + (24 + 79) * 4] ! DSR, debug status reg
- nop
- nop
or %l0, 0xf20, %l4
mov %l4, %psr ! Turn on traps, disable interrupts
- nop
- nop
- nop
+
+ set 0x1000, %l1
+ btst %l1, %l0 ! FP enabled?
+ be no_fpstore
+ nop
+
+! Must save fsr first, to flush the FQ. This may cause a deferred fp trap, so
+! traps must be enabled to allow the trap handler to clean things up.
+
+ st %fsr, [%sp + (24 + 70) * 4]
+
+ std %f0, [%sp + (24 + 32) * 4]
+ std %f2, [%sp + (24 + 34) * 4]
+ std %f4, [%sp + (24 + 36) * 4]
+ std %f6, [%sp + (24 + 38) * 4]
+ std %f8, [%sp + (24 + 40) * 4]
+ std %f10, [%sp + (24 + 42) * 4]
+ std %f12, [%sp + (24 + 44) * 4]
+ std %f14, [%sp + (24 + 46) * 4]
+ std %f16, [%sp + (24 + 48) * 4]
+ std %f18, [%sp + (24 + 50) * 4]
+ std %f20, [%sp + (24 + 52) * 4]
+ std %f22, [%sp + (24 + 54) * 4]
+ std %f24, [%sp + (24 + 56) * 4]
+ std %f26, [%sp + (24 + 58) * 4]
+ std %f28, [%sp + (24 + 60) * 4]
+ std %f30, [%sp + (24 + 62) * 4]
+no_fpstore:
+
call _handle_exception
add %sp, 24 * 4, %o0 ! Pass address of registers
ldd [%sp + (24 + 12) * 4], %i4
ldd [%sp + (24 + 14) * 4], %i6
- sethi %hi(0xff00), %l2
- or %l2, %lo(0xff00), %l2
- ldd [%sp + (24 + 72) * 4], %l4 ! DIA1, debug instr addr 1
- stda %l4, [%l2]0x1
- nop
- nop
- nop
- nop
- ldd [%sp + (24 + 74) * 4], %l4 ! DDA1, debug data addr 1
- add %l2, 8, %l2
- stda %l4, [%l2]0x1
- nop
- nop
- nop
- nop
- ldd [%sp + (24 + 76) * 4], %l4 ! DDV1, debug data value 1
- add %l2, 8, %l2
- stda %l4, [%l2]0x1
- nop
- nop
- nop
- nop
- ld [%sp + (24 + 78) * 4], %l4 ! DCR, debug control reg
- ld [%sp + (24 + 79) * 4], %l5 ! DSR, debug control reg
- add %l2, 8, %l2
- or %l4, 0x200, %l4
- sta %l4, [%l2]0x1
- add %l2, 4, %l2
- sta %l5, [%l2]0x1
- nop
- nop
- nop
- nop
ldd [%sp + (24 + 64) * 4], %l0 ! Y & PSR
ldd [%sp + (24 + 68) * 4], %l2 ! PC & NPC
+ set 0x1000, %l5
+ btst %l5, %l1 ! FP enabled?
+ be no_fpreload
+ nop
+
+ ldd [%sp + (24 + 32) * 4], %f0
+ ldd [%sp + (24 + 34) * 4], %f2
+ ldd [%sp + (24 + 36) * 4], %f4
+ ldd [%sp + (24 + 38) * 4], %f6
+ ldd [%sp + (24 + 40) * 4], %f8
+ ldd [%sp + (24 + 42) * 4], %f10
+ ldd [%sp + (24 + 44) * 4], %f12
+ ldd [%sp + (24 + 46) * 4], %f14
+ ldd [%sp + (24 + 48) * 4], %f16
+ ldd [%sp + (24 + 50) * 4], %f18
+ ldd [%sp + (24 + 52) * 4], %f20
+ ldd [%sp + (24 + 54) * 4], %f22
+ ldd [%sp + (24 + 56) * 4], %f24
+ ldd [%sp + (24 + 58) * 4], %f26
+ ldd [%sp + (24 + 60) * 4], %f28
+ ldd [%sp + (24 + 62) * 4], %f30
+
+ ld [%sp + (24 + 70) * 4], %fsr
+no_fpreload:
+
restore ! Ensure that previous window is valid
save %g0, %g0, %g0 ! by causing a window_underflow trap
return -1;
}
+static char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+
/* scan for the sequence $<data>#<checksum> */
-static void
-getpacket(buffer)
- char *buffer;
+unsigned char *
+getpacket ()
{
+ unsigned char *buffer = &remcomInBuffer[0];
unsigned char checksum;
unsigned char xmitcsum;
- int i;
int count;
- unsigned char ch;
+ char ch;
- do
+ while (1)
{
/* wait around for the start character, ignore all other characters */
- while ((ch = getDebugChar()) != '$') ;
+ while ((ch = getDebugChar ()) != '$')
+ ;
+retry:
checksum = 0;
xmitcsum = -1;
-
count = 0;
/* now, read until a # or end of buffer is found */
while (count < BUFMAX)
{
- ch = getDebugChar();
+ ch = getDebugChar ();
+ if (ch == '$')
+ goto retry;
if (ch == '#')
break;
checksum = checksum + ch;
buffer[count] = ch;
count = count + 1;
}
-
- if (count >= BUFMAX)
- continue;
-
buffer[count] = 0;
if (ch == '#')
{
- xmitcsum = hex(getDebugChar()) << 4;
- xmitcsum |= hex(getDebugChar());
-#if 0
- /* Humans shouldn't have to figure out checksums to type to it. */
- putDebugChar ('+');
- return;
-#endif
+ ch = getDebugChar ();
+ xmitcsum = hex (ch) << 4;
+ ch = getDebugChar ();
+ xmitcsum += hex (ch);
+
if (checksum != xmitcsum)
- putDebugChar('-'); /* failed checksum */
+ {
+ putDebugChar ('-'); /* failed checksum */
+ }
else
{
- putDebugChar('+'); /* successful transfer */
+ putDebugChar ('+'); /* successful transfer */
+
/* if a sequence char is present, reply the sequence ID */
if (buffer[2] == ':')
{
- putDebugChar(buffer[0]);
- putDebugChar(buffer[1]);
- /* remove sequence chars from buffer */
- count = strlen(buffer);
- for (i=3; i <= count; i++)
- buffer[i-3] = buffer[i];
+ putDebugChar (buffer[0]);
+ putDebugChar (buffer[1]);
+
+ return &buffer[3];
}
+
+ return &buffer[0];
}
}
}
- while (checksum != xmitcsum);
}
/* send the packet in buffer. */
while (ch = buffer[count])
{
- if (! putDebugChar(ch))
- return;
+ putDebugChar (ch);
checksum += ch;
count += 1;
}
while (getDebugChar() != '+');
}
-static char remcomInBuffer[BUFMAX];
-static char remcomOutBuffer[BUFMAX];
-
/* Indicate to caller of mem2hex or hex2mem that there has been an
error. */
static volatile int mem_err = 0;
unsigned char tt; /* Trap type code for SPARClite */
unsigned char signo; /* Signal that we map this trap into */
} hard_trap_info[] = {
- {1, SIGSEGV}, /* instruction access error */
- {2, SIGILL}, /* privileged instruction */
- {3, SIGILL}, /* illegal instruction */
- {4, SIGEMT}, /* fp disabled */
- {36, SIGEMT}, /* cp disabled */
- {7, SIGBUS}, /* mem address not aligned */
- {9, SIGSEGV}, /* data access exception */
- {10, SIGEMT}, /* tag overflow */
- {128+1, SIGTRAP}, /* ta 1 - normal breakpoint instruction */
- {255, SIGTRAP}, /* hardware breakpoint */
+ {0x01, SIGSEGV}, /* instruction access error */
+ {0x02, SIGILL}, /* privileged instruction */
+ {0x03, SIGILL}, /* illegal instruction */
+ {0x04, SIGEMT}, /* fp disabled */
+ {0x07, SIGBUS}, /* mem address not aligned */
+ {0x09, SIGSEGV}, /* data access exception */
+ {0x0a, SIGEMT}, /* tag overflow */
+ {0x20, SIGBUS}, /* r register access error */
+ {0x21, SIGBUS}, /* instruction access error */
+ {0x24, SIGEMT}, /* cp disabled */
+ {0x29, SIGBUS}, /* data access error */
+ {0x2a, SIGFPE}, /* divide by zero */
+ {0x2b, SIGBUS}, /* data store error */
+ {0x80+1, SIGTRAP}, /* ta 1 - normal breakpoint instruction */
+ {0xff, SIGTRAP}, /* hardware breakpoint */
{0, 0} /* Must be last */
};
{
struct hard_trap_info *ht;
- for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
- exceptionHandler(ht->tt, trap_low);
-
- /* In case GDB is started before us, ack any packets (presumably
- "$?#xx") sitting there. */
+/* Only setup fp traps if the FP is disabled. */
- putDebugChar ('+');
+ for (ht = hard_trap_info;
+ ht->tt != 0 && ht->signo != 0;
+ ht++)
+ if (ht->tt != 4 || ! (read_psr () & 0x1000))
+ exceptionHandler(ht->tt, trap_low);
initialized = 1;
}
");
static void
-set_hw_breakpoint_trap(enable)
- int enable;
+get_in_break_mode()
{
extern void dummy_hw_breakpoint();
- if (enable)
- exceptionHandler(255, dummy_hw_breakpoint);
- else
- exceptionHandler(255, trap_low);
-}
-
-static void
-get_in_break_mode()
-{
- set_hw_breakpoint_trap(1);
+ exceptionHandler (255, dummy_hw_breakpoint);
- asm("
- sethi %hi(0xff10), %l4
- or %l4, %lo(0xff10), %l4
- sta %g0, [%l4]0x1
- nop
- nop
- nop
- ");
+ asm ("ta 255");
- set_hw_breakpoint_trap(0);
+ exceptionHandler (255, trap_low);
}
/* Convert the SPARC hardware trap type code to a unix signal number. */
* otherwise.
*/
-
static void
handle_exception (registers)
unsigned long *registers;
restore
");
+ get_in_break_mode (); /* Enable DSU register writes */
+
+ registers[DIA1] = read_asi (1, 0xff00);
+ registers[DIA2] = read_asi (1, 0xff04);
+ registers[DDA1] = read_asi (1, 0xff08);
+ registers[DDA2] = read_asi (1, 0xff0c);
+ registers[DDV1] = read_asi (1, 0xff10);
+ registers[DDV2] = read_asi (1, 0xff14);
+ registers[DCR] = read_asi (1, 0xff18);
+ registers[DSR] = read_asi (1, 0xff1c);
+
if (registers[PC] == (unsigned long)breakinst)
{
registers[PC] = registers[NPC];
dsr = (unsigned long)registers[DSR];
if (dsr & 0x3c)
- {
- tt = 255;
- }
+ tt = 255;
else
- {
- tt = (registers[TBR] >> 4) & 0xff;
- }
+ tt = (registers[TBR] >> 4) & 0xff;
/* reply to host that an exception has occurred */
sigval = computeSignal(tt);
{
remcomOutBuffer[0] = 0;
- getpacket(remcomInBuffer);
- switch (remcomInBuffer[0])
+ ptr = getpacket();
+ switch (*ptr++)
{
case '?':
remcomOutBuffer[0] = 'S';
break;
case 'g': /* return the value of the CPU registers */
- {
- ptr = remcomOutBuffer;
- ptr = mem2hex((char *)registers, ptr, 16 * 4, 0); /* G & O regs */
- ptr = mem2hex(sp + 0, ptr, 16 * 4, 0); /* L & I regs */
- memset(ptr, '0', 32 * 8); /* Floating point */
- ptr = mem2hex((char *)®isters[Y],
- ptr + 32 * 4 * 2,
- 8 * 4,
- 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
- mem2hex((char *)®isters[DIA1], ptr,
- 8 * 4, 0); /* DIA1, DIA2, DDA1, DDA2, DDV1, DDV2, DCR, DSR */
- }
+ memcpy (®isters[L0], sp, 16 * 4); /* Copy L & I regs from stack */
+ mem2hex ((char *)registers, remcomOutBuffer, NUMREGBYTES, 0);
break;
- case 'G': /* set the value of the CPU registers - return OK */
+ case 'G': /* Set the value of all registers */
+ case 'P': /* Set the value of one register */
{
unsigned long *newsp, psr;
psr = registers[PSR];
- ptr = &remcomInBuffer[1];
- hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */
- hex2mem(ptr + 16 * 4 * 2, sp + 0, 16 * 4, 0); /* L & I regs */
- hex2mem(ptr + 64 * 4 * 2, (char *)®isters[Y],
- 8 * 4, 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
- hex2mem(ptr + 72 * 4 * 2, (char *)®isters[DIA1],
- 8 * 4, 0); /* DIA1, DIA2, DDA1, DDA2, DDV1, DDV2, DCR, DSR */
+ if (ptr[-1] == 'P')
+ {
+ int regno;
+
+ if (hexToInt (&ptr, ®no)
+ && *ptr++ == '=')
+ if (regno >= L0 && regno <= I7)
+ hex2mem (ptr, sp + regno - L0, 4, 0);
+ else
+ hex2mem (ptr, (char *)®isters[regno], 4, 0);
+ else
+ {
+ strcpy (remcomOutBuffer, "E01");
+ break;
+ }
+ }
+ else
+ {
+ hex2mem (ptr, (char *)registers, NUMREGBYTES, 0);
+ memcpy (sp, ®isters[L0], 16 * 4); /* Copy L & I regs to stack */
+ }
/* See if the stack pointer has moved. If so, then copy the saved
locals and ins to the new location. This keeps the window
case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
/* Try to read %x,%x. */
- ptr = &remcomInBuffer[1];
-
if (hexToInt(&ptr, &addr)
&& *ptr++ == ','
&& hexToInt(&ptr, &length))
case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
/* Try to read '%x,%x:'. */
- ptr = &remcomInBuffer[1];
-
if (hexToInt(&ptr, &addr)
&& *ptr++ == ','
&& hexToInt(&ptr, &length)
case 'c': /* cAA..AA Continue at address AA..AA(optional) */
/* try to read optional parameter, pc unchanged if no parm */
-
- ptr = &remcomInBuffer[1];
if (hexToInt(&ptr, &addr))
{
registers[PC] = addr;
some location may have changed something that is in the instruction cache.
*/
- flush_i_cache();
+ flush_i_cache ();
+
+ if (!(registers[DSR] & 0x1) /* DSU enabled? */
+ && !(registers[DCR] & 0x200)) /* Are we in break state? */
+ { /* Yes, set the DSU regs */
+ write_asi (1, 0xff00, registers[DIA1]);
+ write_asi (1, 0xff04, registers[DIA2]);
+ write_asi (1, 0xff08, registers[DDA1]);
+ write_asi (1, 0xff0c, registers[DDA2]);
+ write_asi (1, 0xff10, registers[DDV1]);
+ write_asi (1, 0xff14, registers[DDV2]);
+ write_asi (1, 0xff1c, registers[DSR]);
+ write_asi (1, 0xff18, registers[DCR] | 0x200); /* Clear break */
+ }
+
return;
/* kill the program */
asm ("call 0
nop ");
break;
-
-#if 0
-Disabled until we can unscrew this properly
-
- case 'b': /* bBB... Set baud rate to BB... */
- {
- int baudrate;
- extern void set_timer_3();
-
- ptr = &remcomInBuffer[1];
- if (!hexToInt(&ptr, &baudrate))
- {
- strcpy(remcomOutBuffer,"B01");
- break;
- }
-
- /* Convert baud rate to uart clock divider */
- switch (baudrate)
- {
- case 38400:
- baudrate = 16;
- break;
- case 19200:
- baudrate = 33;
- break;
- case 9600:
- baudrate = 65;
- break;
- default:
- strcpy(remcomOutBuffer,"B02");
- goto x1;
- }
-
- putpacket("OK"); /* Ack before changing speed */
- set_timer_3(baudrate); /* Set it */
- }
-x1: break;
-#endif
} /* switch */
/* reply to the request */
_breakinst: ta 1
");
}
-
-static void
-hw_breakpoint()
-{
- asm("
- ta 127
- ");
-}