📄 nios_gdb_stub.c
字号:
// File: nios_gdb_stub.c
// Date: 2000 June 20
// Author dvb \ Altera Santa Cruz
#include "nios.h"
#include "nios_gdb_stub.h"
#define na_debug_peripheral_irq 8
enum
{
na_BreakpointTrap = 3,
na_SingleStepTrap = 4,
na_StartGDBTrap = 5
};
// --------------------------------
// Local Prototypes
static void StringFit(char *s,int w);
// --------------------------------
// Debugging The Debugger
#if GDB_DEBUG_PRINT
void GDB_RawMessage(char *s)
{
StringFit(s,32);
nr_pio_lcdwritescreen(s);
}
#else
#define GDB_RawMessage(a,b,c) // define away to nothing
#endif
#if GDB_DEBUG_PRINT
void GDB_Print2(char *s,int n1,int n2)
{
char st[1000];
sprintf(st,s,n1,n2);
GDB_RawMessage(st);
}
#else
#define GDB_Print2(a,b,c) // define away to nothing
#endif
// If string is longer than w, cut out the middle.
#if GDB_DEBUG_PRINT
int StringLen(char *s)
{
int l = 0;
while(*s++)
l++;
return l;
}
void StringFit(char *s,int w)
{
if(StringLen(s) > w)
{
int i;
w = w / 2;
for(i = 0; i < w; i++)
{
s[i + w] = s[StringLen(s) - w + i];
}
s[w + w] = 0;
}
}
#endif
// ---------------------------------------------
// Generic routines for dealing with
// hex input, output, and parsing
// (Adapted from other stubs.)
NiosGDBGlobals gdb; // (starts life == 0) not static: the ISR uses it!
static char dHexChars[16] = "0123456789abcdef";
/*
* HexCharToValue -- convert a characters
* to its hex value, or -1 if not.
*/
char HexCharToValue(char c)
{
char result=0;
if(c >= '0' && c <= '9')
result = c - '0';
else if(c >= 'a' && c <= 'f')
result = c - 'a' + 10;
else if(c >= 'A' && c <= 'A')
result = c - 'A' + 10;
else
result = -1;
return result;
}
/*
* HexStringToValue -- convert a 2*byte_width string of characters
* to its little endian hex value,
* or -1 if not.
* This routine is for strings of hex values
*/
unsigned long HexStringToValue(char *c, int byte_width)
{
unsigned long result=0;
unsigned char a,b;
int i=0;
while (i < byte_width)
{
a = HexCharToValue(*c++);
if (a & 0x80) return a;
b = HexCharToValue(*c++);
if (b & 0x80) return b;
b = (a<<4) | (b&0x0f);
result |= ((unsigned long)b) << (i*8);
i++;
}
return result;
}
/*
* Hex2Value -- convert a non-hex char delimited string
* to its big endian hex value.
* This routine is for address and byte count values
*/
char *Hex2Value(char *hexIn, int *valueOut)
{
char c;
int digitValue;
int value = 0;
while(1)
{
c = *hexIn;
digitValue = HexCharToValue(c);
if(digitValue < 0)
{
*valueOut = value;
return hexIn;
}
hexIn++;
value = (value << 4) + digitValue;
}
}
/*
* HexToMem -- convert a string to a specified
* number of bytes in memory.
*
* JMB -- make this thing a bit smarter so
* that it selects the byte width to
* write based on the number of bytes
* and the destination address alignment.
* This is to support writes to non-byte enabled
* peripheral registers...I don't like it.
* Beware! there are cases where it wont work
*/
char *HexToMem(char *hexIn, char *memOut, int memByteCount)
{
int i;
unsigned long x;
short *memOutS = 0;
long *memOutL = 0;
int byte_width;
//determine maximum byte width
if (((memByteCount%2) != 0) || (((unsigned int)memOut%2) != 0))
byte_width = 1;
else if (((memByteCount % 4) != 0) || (((unsigned int)memOut % 4) != 0))
{
byte_width = 2;
memOutS = (short *)memOut;
}
else
{
byte_width = 4;
memOutL = (long *)memOut;
}
for(i = 0; i < memByteCount; i+=byte_width)
{
x = HexStringToValue(hexIn,byte_width);
hexIn += byte_width*2;
switch (byte_width)
{
case 1:
*memOut++ = (unsigned char) 0x000000ff & x;
break;
case 2:
*memOutS++ = (unsigned short) 0x0000ffff & x;
break;
case 4:
*memOutL++ = x;
break;
default:
//How could this ever happen???
break;
}
}
return hexIn;
}
char *MemToHex(char *memIn, char *hexOut, int memByteCount)
{
int i,j;
int byte_width;
unsigned long x = 0;
unsigned short *memInS = 0;
unsigned long *memInL = 0;
//determine maximum byte width
if (((memByteCount % 2) != 0) || (((unsigned int)memIn % 2) != 0))
byte_width = 1;
else if (((memByteCount % 4) != 0) || (((unsigned int)memIn % 4) != 0))
{
byte_width = 2;
memInS = (short *)memIn;
}
else
{
byte_width = 4;
memInL = (long *)memIn;
}
for(i = 0; i < memByteCount; i+=byte_width)
{
switch (byte_width)
{
case 1:
x = *memIn++;
break;
case 2:
x = *memInS++;
break;
case 4:
x = *memInL++;
break;
default:
//How would we get here?
break;
}
for (j=0; j<byte_width; j++)
{
*hexOut++ = dHexChars[(x&0x000000f0)>>4];
*hexOut++ = dHexChars[x&0x0000000f];
x = x>>8;
}
}
*hexOut = 0;
return hexOut;
}
//Send just the + or - to indicate
//ACK or NACK
void GDBPutAck (char ack)
{
if (gdb.comlink == ne_gdb_serial)
GDBPutChar (ack);
#ifdef ETHER_DEBUG
#ifdef ethernet_exists
else
{
if (gdb.host_ip_address != 0)
nr_plugs_send_to (gdb.gdb_eth_plug, &ack, 1, 0,
gdb.host_ip_address,
gdb.host_port_number);
}
#endif
#endif
}
/*
* Once a $ comes in, use GetGDBPacket to
* retrieve a full gdb packet, and verify
* checksum, and reply + or -.
*/
int GetGDBPacket(char *aBuffer)
{
int checksum = 0;
int length = 0;
char c;
int x = 0; // satisfy compiler
if (gdb.comlink == ne_gdb_serial)
{
while ((c = GDBGetChar ()) != '$') ;
startPacket:
while(((c = GDBGetChar()) != '#') && (length < kTextBufferSize))
{
if(c == '$')
goto startPacket;
checksum += c;
aBuffer[length++] = c;
aBuffer[length] = 0;
}
c = GDBGetChar();
x = HexCharToValue(c) << 4;
c = GDBGetChar();
x += HexCharToValue(c);
checksum &= 0xff;
GDB_Print2("GetPacket %d",length,0);
}
#ifdef ETHER_DEBUG
#ifdef ethernet_exists
else
{
int srcidx;
// wait till beginning of packet
while (gdb.textBuffer[0] != '$') nr_plugs_idle_exclusive(gdb.gdb_eth_plug);
startEPacket:
srcidx = 1;
//loop until packet terminator
//leave enough room for the checksum at the end
while (((c = gdb.textBuffer[srcidx++]) != '#') && (srcidx < kTextBufferSize-2))
{
if (c == '$')
goto startEPacket;
checksum += c;
aBuffer[length++] = c;
}
c = gdb.textBuffer[srcidx++];
x = HexCharToValue(c) << 4;
c = gdb.textBuffer[srcidx++];
x += HexCharToValue (c);
aBuffer[length++] = 0;
checksum &= 0xff;
GDB_Print2("GetPacket %d",length,0);
}
#endif
#endif
if(checksum != x)
{
GDBPutAck('-');
length = 0;
}
else
{
GDBPutAck('+');
}
return length;
}
//Wait for acknowledgement
//Should we have some way of timing out???
//return TRUE if ACK
//return FALSE if NACK
int GDBGetACK ()
{
char c;
if (gdb.comlink == ne_gdb_serial)
{
while (1)
{
c = GDBGetChar ();
if (c == '+') return (1);
else if (c == '-') return (0);
}
}
#ifdef ETHER_DEBUG
#ifdef ethernet_exists
else
{
gdb.ACKstatus = ne_gdb_ack_waiting;
while (1)
{
nr_plugs_idle_exclusive (gdb.gdb_eth_plug);
if (gdb.ACKstatus == ne_gdb_ack_acked)
{
gdb.ACKstatus = ne_gdb_ack_notwaiting;
return (1);
}
else if (gdb.ACKstatus == ne_gdb_ack_nacked)
{
gdb.ACKstatus = ne_gdb_ack_notwaiting;
return (0);
}
}
}
#endif
#endif
return 0; // satisfy compiler, never gets here
}
/*
* Send a packet, preceded by $,
* and followed by #checksum.
*/
void PutGDBPacket(char *aBuffer)
{
int checksum;
char c;
int cnt=0;
if (gdb.comlink == ne_gdb_serial)
{
startPutSerial:
GDBPutChar('$');
checksum = 0;
while((c = *aBuffer++) != 0)
{
checksum += c;
GDBPutChar(c);
}
GDBPutChar('#');
GDBPutChar(dHexChars[(checksum >> 4) & 15]);
GDBPutChar(dHexChars[checksum & 15]);
if (!GDBGetACK ())
{
if (++cnt < GDB_RETRY_CNT) goto startPutSerial;
}
}
#ifdef ETHER_DEBUG
#ifdef ethernet_exists
else
{
if (gdb.host_ip_address != 0)
{
int i;
int result;
char c1;
i = 0;
c = aBuffer[i];
if (c==0) return; //there is no data in packet, so why bother sending
aBuffer[i++] = '$';
checksum = 0;
do
{
checksum += c;
c1 = aBuffer[i];
aBuffer[i++] = c;
c = c1;
} while (c != 0);
aBuffer[i++] = '#';
aBuffer[i++] = dHexChars[(checksum >> 4) & 15];
aBuffer[i++] = dHexChars[checksum & 15];
aBuffer[i++] = 0;
startPutEth:
result = nr_plugs_send_to (gdb.gdb_eth_plug, aBuffer, i, 0,
gdb.host_ip_address,
gdb.host_port_number);
aBuffer[0] = 0; //clear packet to
if (!GDBGetACK ())
{
if (++cnt < GDB_RETRY_CNT) goto startPutEth;
}
}
}
#endif
#endif
}
int PutTracePacket(char *aBuffer, int size)
{
int checksum;
char c;
int i;
int cnt=0;
if (gdb.comlink == ne_gdb_serial)
{
startPutSerial:
GDBPutChar('$');
checksum = 0;
for (i=0; i<size; i++)
{
checksum += aBuffer[i];
GDBPutChar (aBuffer[i]);
}
GDBPutChar('#');
GDBPutChar(dHexChars[(checksum >> 4) & 15]);
GDBPutChar(dHexChars[checksum & 15]);
if (!GDBGetACK ())
{
if (++cnt < GDB_RETRY_CNT) goto startPutSerial;
}
}
#ifdef ETHER_DEBUG
#ifdef ethernet_exists
else
{
int result;
char c1;
checksum = 0;
c = '$';
for (i=0; i<size; i++)
{
checksum += aBuffer[i];
c1 = aBuffer[i];
aBuffer[i] = c;
c = c1;
}
aBuffer[i++] = c;
aBuffer[i++] = '#';
aBuffer[i++] = dHexChars[(checksum >> 4) & 15];
aBuffer[i++] = dHexChars[checksum & 15];
aBuffer[i++] = 0;
ethResend:
if (gdb.host_ip_address != 0)
{
result = nr_plugs_send_to (gdb.gdb_eth_plug, aBuffer, i, 0,
gdb.host_ip_address,
gdb.host_port_number);
aBuffer[0]=0;
}
if (!GDBGetACK ())
{
if (++cnt < GDB_RETRY_CNT) goto ethResend;
}
}
#endif
#endif
if (cnt < GDB_RETRY_CNT) return 1;
else return 0;
}
void PutGDBOKPacket(char *aBuffer)
{
aBuffer[0] = 'O';
aBuffer[1] = 'K';
aBuffer[2] = 0;
PutGDBPacket(aBuffer);
}
#if nasys_debug_core
//some defines used exclusively for TRACE data xfer
#define stepsize (2*sizeof(int) + sizeof (char))
#define MAX_TRACE_BYTES (((int)((2*MAX_DATA_SIZE-2)/stepsize))*stepsize)
int Trace_Read_Intercept (char *aBuffer)
{
int cnt=0;
unsigned int data;
unsigned char code;
int byteCount;
unsigned char *w;
unsigned short dataAccumulate;
int status;
w = aBuffer;
w++; //skip past the m
if (*w++ == 't') //see if this is a special "memory trace" packet
{
w = Hex2Value(w,&byteCount); //get the number of bytes to transfer
//turn byteCount to a multiple of stepsize
byteCount = ((int)(byteCount/stepsize))*stepsize;
//wait until fifo empties
nm_debug_get_reg(status, np_debug_write_status);
while (status&np_debug_write_status_writing_mask) nm_debug_get_reg(status,np_debug_write_status);
// loop through total size
while (byteCount > 0)
{
w=aBuffer; //reset w to beginning of buffer
//calculate the number of bytes in this packet
if (byteCount > MAX_TRACE_BYTES) dataAccumulate = MAX_TRACE_BYTES;
else dataAccumulate = byteCount;
//insert data size at beginning of packet
*w++ = 0x00ff & dataAccumulate;
*w++ = 0x00ff & (dataAccumulate >> 8);
byteCount -= dataAccumulate; //decrement byteCount
// accumulate a full buffer
for (cnt=0; cnt<dataAccumulate; cnt+=stepsize)
{
int valid;
nm_debug_set_reg (1, np_debug_read_sample); //begin transaction
//wait until data is ready
nm_debug_get_reg (valid, np_debug_data_valid);
while (!valid) nm_debug_get_reg(valid,np_debug_data_valid) ;
nm_debug_get_reg (data, np_debug_trace_address);
*w++ = (unsigned char) data & 0x000000ff;
*w++ = (unsigned char) (data>>8) & 0x000000ff;
#ifdef __nios32__
*w++ = (unsigned char) (data>>16) & 0x000000ff;
*w++ = (unsigned char) (data>>24) & 0x000000ff;
#endif
nm_debug_get_reg (data, np_debug_trace_data);
*w++ = (unsigned char) data & 0x000000ff;
*w++ = (unsigned char) (data>>8) & 0x000000ff;
#ifdef __nios32__
*w++ = (unsigned char) (data>>16) & 0x000000ff;
*w++ = (unsigned char) (data>>24) & 0x000000ff;
#endif
nm_debug_get_reg (*w++, np_debug_trace_code);
}
*w++ = 0;
//if one of our data packets doesn't make it, stop sending them
if (PutTracePacket (aBuffer,dataAccumulate+2) != 1) //+2 for size filed
byteCount = 0;
}
return 1;
}
return 0;
}
#undef stepsize
#undef MAX_TRACE_BYTES
#endif
void DoGDBCommand_m(char *aBuffer)
{
char *w;
int startAddr,byteCount;
#if nasys_debug_core
/* intercept some access to the dbg peripheral */
if (Trace_Read_Intercept (aBuffer)) return;
#endif
w = aBuffer;
w++; // past 'm'
w = Hex2Value(w,&startAddr);
w++; // past ','
w = Hex2Value(w,&byteCount);
if (byteCount > MAX_DATA_SIZE) byteCount = MAX_DATA_SIZE;
// mA,L -- request memory
w = aBuffer;
w = MemToHex((char *)startAddr,w,byteCount);
PutGDBPacket(aBuffer);
}
void DoGDBCommand_M(char *aBuffer)
{
char *w;
int startAddr,byteCount;
w = aBuffer;
w++; // past 'M'
w = Hex2Value(w,&startAddr);
w++; // past ','
w = Hex2Value(w,&byteCount);
w++; // past ':'
GDB_Print2("M from %x to %x",startAddr,byteCount);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -