Committed on the Free edition of March Hare Software CVSNT Server. Upgrade to CVS Suite for more features and support: http://march-hare.com/cvsnt/ git-svn-id: http://moon:8086/svn/vhdl/trunk@448 cc03376c-175c-47c8-b038-4cd826a8556b
344 lines
9.0 KiB
C
344 lines
9.0 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "irq.h"
|
|
#include "libsys.h"
|
|
#include "mipsdis.h"
|
|
|
|
#define MAX_USER_BP 16
|
|
#define BP_MASK_ID 0x00FFF
|
|
#define BP_MASK_TYPE 0xFF000
|
|
|
|
#define BP_GET_ID(bp) ((bp >> 6) & 0xFFF)
|
|
|
|
#define BP_USER_BASE 0x10000
|
|
#define BP_USER(id) (((BP_USER_BASE + id) << 6) | 0x0D)
|
|
|
|
#define BP_MGMT_BASE_SS 0x20000
|
|
#define BP_MGMT_SS(id) (((BP_MGMT_BASE_SS + id) << 6) | 0x0D)
|
|
|
|
#define BP_MGMT_BASE_RU 0x30000
|
|
#define BP_MGMT_RU(id) (((BP_MGMT_BASE_RU + id) << 6) | 0x0D)
|
|
|
|
static char g_buf[80];
|
|
|
|
typedef struct _sbp_t
|
|
{
|
|
UINT32 *pAddr;
|
|
UINT32 instr;
|
|
} bp_t;
|
|
|
|
static bp_t user_bp[MAX_USER_BP];
|
|
static bp_t mgmt_bp_ss[2];
|
|
static bp_t mgmt_bp_ru[2];
|
|
static int g_is_ss;
|
|
static int g_bp_index;
|
|
|
|
int IsBreak(UINT32 instr)
|
|
{
|
|
return ((instr & 0xFC00003F) == 0x0000000D);
|
|
}
|
|
|
|
UINT32 BreakGetType(UINT32 instr)
|
|
{
|
|
return (instr >> 6) & BP_MASK_TYPE;
|
|
}
|
|
|
|
void dbg_handler(struct xcptcontext * xcp)
|
|
{
|
|
|
|
UINT32 bp_addr, bp_index = 0, branch_addr, reg, result, bp_type;
|
|
int junk, i, leave_isr, is_branch_shadow, is_user_bp;
|
|
UINT32 volatile *pBtn = (UINT32*)sys_gpio0;
|
|
UINT32 volatile *pTim_stat = (UINT32*)sys_itim_stat;
|
|
UINT32 volatile *pTim_cnt = (UINT32*)sys_itim_cnt;
|
|
UINT32 volatile *pTim_cmp = (UINT32*)sys_itim_cmp;
|
|
UINT32 *pInstr, *pAddr_curr, *pAddr_prev, *pAddr_next;
|
|
|
|
sputs("\n");
|
|
PRINT_REG(" Status : ", xcp->sr);
|
|
PRINT_REG(" Cause : ", xcp->cr);
|
|
PRINT_REG(" EPC : ", xcp->epc);
|
|
PRINT_REG("BadAddr : ", xcp->baddr);
|
|
sputs("\n");
|
|
PRINT_REG(" MDLO : ", xcp->mdlo);
|
|
PRINT_REG(" MDHI : ", xcp->mdhi);
|
|
|
|
sputs("\n");
|
|
|
|
sputs("Registers:\n");
|
|
PRINT_REG(" 0 (ze) : ", xcp->regs[0]);
|
|
PRINT_REG(" 1 (at) : ", xcp->regs[1]);
|
|
PRINT_REG(" 2 (v0) : ", xcp->regs[2]);
|
|
PRINT_REG(" 3 (v1) : ", xcp->regs[3]);
|
|
sputs("\n");
|
|
PRINT_REG(" 4 (a0) : ", xcp->regs[4]);
|
|
PRINT_REG(" 5 (a1) : ", xcp->regs[5]);
|
|
PRINT_REG(" 6 (a2) : ", xcp->regs[6]);
|
|
PRINT_REG(" 7 (a3) : ", xcp->regs[7]);
|
|
sputs("\n");
|
|
PRINT_REG(" 8 (t0) : ", xcp->regs[8]);
|
|
PRINT_REG(" 9 (t1) : ", xcp->regs[9]);
|
|
PRINT_REG("10 (t2) : ", xcp->regs[10]);
|
|
PRINT_REG("11 (t3) : ", xcp->regs[11]);
|
|
sputs("\n");
|
|
PRINT_REG("12 (t4) : ", xcp->regs[12]);
|
|
PRINT_REG("13 (t5) : ", xcp->regs[13]);
|
|
PRINT_REG("14 (t6) : ", xcp->regs[14]);
|
|
PRINT_REG("15 (t7) : ", xcp->regs[15]);
|
|
sputs("\n");
|
|
PRINT_REG("16 (s0) : ", xcp->regs[16]);
|
|
PRINT_REG("17 (s1) : ", xcp->regs[17]);
|
|
PRINT_REG("18 (s2) : ", xcp->regs[18]);
|
|
PRINT_REG("19 (s3) : ", xcp->regs[19]);
|
|
sputs("\n");
|
|
PRINT_REG("20 (s4) : ", xcp->regs[20]);
|
|
PRINT_REG("21 (s5) : ", xcp->regs[21]);
|
|
PRINT_REG("22 (s6) : ", xcp->regs[22]);
|
|
PRINT_REG("23 (s7) : ", xcp->regs[23]);
|
|
sputs("\n");
|
|
PRINT_REG("24 (t8) : ", xcp->regs[24]);
|
|
PRINT_REG("25 (t9) : ", xcp->regs[25]);
|
|
PRINT_REG("26 (k0) : ", xcp->regs[26]);
|
|
PRINT_REG("27 (k1) : ", xcp->regs[27]);
|
|
sputs("\n");
|
|
PRINT_REG("28 (gp) : ", xcp->regs[28]);
|
|
PRINT_REG("29 (sp) : ", xcp->regs[29]);
|
|
PRINT_REG("30 (fp) : ", xcp->regs[30]);
|
|
PRINT_REG("31 (ra) : ", xcp->regs[31]);
|
|
sputs("\n");
|
|
sputs("\n");
|
|
|
|
is_user_bp = 0;
|
|
pAddr_curr = (UINT32*)xcp->epc;
|
|
is_branch_shadow = ((xcp->cr & 0x80000000) == 0x80000000);
|
|
if (is_branch_shadow)
|
|
pAddr_curr++;
|
|
|
|
pAddr_prev = pAddr_curr - 1;
|
|
pAddr_next = pAddr_curr + 1;
|
|
|
|
if (IsBreak(*pAddr_curr))
|
|
{
|
|
bp_type = BreakGetType(*pAddr_curr);
|
|
|
|
switch (bp_type)
|
|
{
|
|
case BP_MGMT_BASE_SS:
|
|
|
|
// Restore original instructions after single-step
|
|
sputs("1. Restore after single-step at ");print_word((long)mgmt_bp_ss[0].pAddr);sputs("\n");
|
|
*(mgmt_bp_ss[0].pAddr) = mgmt_bp_ss[0].instr;
|
|
ICACHE_invalidate_at(mgmt_bp_ss[0].pAddr);
|
|
if (mgmt_bp_ss[1].pAddr)
|
|
{
|
|
sputs("2. Restore after single-step at ");print_word((long)mgmt_bp_ss[1].pAddr);sputs("\n");
|
|
*(mgmt_bp_ss[1].pAddr) = mgmt_bp_ss[1].instr;
|
|
ICACHE_invalidate_at(mgmt_bp_ss[1].pAddr);
|
|
}
|
|
|
|
break;
|
|
|
|
case BP_MGMT_BASE_RU:
|
|
|
|
bp_index = BP_GET_ID(*pAddr_curr);
|
|
sputs("Restore user break at ");print_word((long)user_bp[bp_index].pAddr);sputs("\n");
|
|
|
|
*(user_bp[bp_index].pAddr) = BP_USER(bp_index);
|
|
ICACHE_invalidate_at(user_bp[bp_index].pAddr);
|
|
|
|
*(mgmt_bp_ru[0].pAddr) = mgmt_bp_ru[0].instr;
|
|
ICACHE_invalidate_at(mgmt_bp_ru[0].pAddr);
|
|
sputs("1. Restore after RU at ");print_word((long)mgmt_bp_ru[0].pAddr);sputs("\n");
|
|
if (mgmt_bp_ru[1].pAddr)
|
|
{
|
|
*(mgmt_bp_ru[1].pAddr) = mgmt_bp_ru[1].instr;
|
|
ICACHE_invalidate_at(mgmt_bp_ru[1].pAddr);
|
|
sputs("2. Restore after RU at ");print_word((long)mgmt_bp_ru[1].pAddr);sputs("\n");
|
|
}
|
|
if (!g_is_ss)
|
|
return;
|
|
|
|
break;
|
|
|
|
case BP_USER_BASE:
|
|
|
|
is_user_bp = 1;
|
|
bp_index = BP_GET_ID(*pAddr_curr);
|
|
sputs("Restore instruction at ");print_word((long)user_bp[bp_index].pAddr);sputs("\n");
|
|
*(user_bp[bp_index].pAddr) = user_bp[bp_index].instr;
|
|
ICACHE_invalidate_at(user_bp[bp_index].pAddr);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
pInstr = pAddr_prev;
|
|
// Disassemble instructions
|
|
for (i=0; i < 3; i++)
|
|
{
|
|
print_word((long)pInstr);
|
|
if (IsBreak(*pInstr) && (BreakGetType(*pInstr) == BP_USER_BASE))
|
|
{
|
|
tdisasm(g_buf, (long)user_bp[BP_GET_ID(*pInstr)].pAddr, user_bp[BP_GET_ID(*pInstr)].instr, 0, &junk, &junk, &junk);
|
|
sputs(": b ");
|
|
}
|
|
else
|
|
{
|
|
tdisasm(g_buf, (long)pInstr, *pInstr, 0, &junk, &junk, &junk);
|
|
if (pInstr == pAddr_curr)
|
|
if (is_user_bp == 1)
|
|
sputs(": b-> ");
|
|
else
|
|
sputs(": -> ");
|
|
else
|
|
sputs(": ");
|
|
}
|
|
sputs(g_buf);
|
|
sputs("\n");
|
|
pInstr++;
|
|
}
|
|
|
|
if (is_user_bp)
|
|
{
|
|
// Save original instruction
|
|
mgmt_bp_ru[0].pAddr = pAddr_next;
|
|
mgmt_bp_ru[0].instr = *(mgmt_bp_ru[0].pAddr);
|
|
// Replace instruction with managment breakpoint
|
|
*(mgmt_bp_ru[0].pAddr) = BP_MGMT_RU(bp_index);
|
|
ICACHE_invalidate_at(mgmt_bp_ru[0].pAddr);
|
|
mgmt_bp_ru[1].pAddr = NULL;
|
|
mgmt_bp_ru[1].pAddr = 0;
|
|
sputs("1. Insert RU-break at ");print_word((long)mgmt_bp_ru[0].pAddr);sputs("\n");
|
|
|
|
// We have two possible management breaks, if previous instruction was branch or jump
|
|
if (is_branch_shadow)
|
|
{
|
|
result = tdisasm(g_buf, (long)pAddr_prev, *pAddr_prev, 0, &junk, &branch_addr, ®);
|
|
// Is jump target stored in register
|
|
if (result == 3)
|
|
{
|
|
branch_addr = xcp->regs[reg&0x1F];
|
|
}
|
|
// Save original instruction
|
|
mgmt_bp_ru[1].pAddr = (UINT32*)branch_addr;
|
|
mgmt_bp_ru[1].instr = *(mgmt_bp_ru[1].pAddr);
|
|
// Replace instruction with managment breakpoint
|
|
*(mgmt_bp_ru[1].pAddr) = BP_MGMT_RU(bp_index);
|
|
ICACHE_invalidate_at(mgmt_bp_ru[1].pAddr);
|
|
sputs("2. Insert RU-break at ");print_word((long)mgmt_bp_ru[1].pAddr);sputs("\n");
|
|
}
|
|
}
|
|
|
|
do
|
|
{
|
|
leave_isr = 0;
|
|
switch(readchar())
|
|
{
|
|
case 'g':
|
|
leave_isr = 1;
|
|
g_is_ss = 0;
|
|
break;
|
|
|
|
case 'b':
|
|
printf("Enter breakpoint: ");
|
|
scanf("%x", &bp_addr);
|
|
printf("Insert breakpoint at %.8X\n", bp_addr);
|
|
user_bp[g_bp_index].pAddr = (UINT32*)bp_addr;
|
|
user_bp[g_bp_index].instr = *(user_bp[g_bp_index].pAddr);
|
|
*(user_bp[g_bp_index].pAddr) = BP_USER(g_bp_index);
|
|
|
|
tdisasm(g_buf, (long)user_bp[g_bp_index].pAddr, user_bp[g_bp_index].instr, 0, &junk, &junk, &junk);
|
|
print_word((long)user_bp[g_bp_index].pAddr);sputs(": b ");sputs(g_buf);sputs("\n");
|
|
g_bp_index++;
|
|
break;
|
|
|
|
case 's':
|
|
g_is_ss = 1;
|
|
leave_isr = 1;
|
|
// Don't overwrite RU breaks
|
|
if (is_user_bp)
|
|
break;
|
|
// Don't overwrite user breaks
|
|
if (IsBreak(*pInstr) && (BreakGetType(*pInstr) == BP_USER_BASE))
|
|
break;
|
|
|
|
// Save original instruction
|
|
mgmt_bp_ss[0].pAddr = pAddr_next;
|
|
mgmt_bp_ss[0].instr = *(mgmt_bp_ss[0].pAddr);
|
|
// Replace instruction with managment breakpoint
|
|
*(mgmt_bp_ss[0].pAddr) = BP_MGMT_SS(1);
|
|
ICACHE_invalidate_at(mgmt_bp_ss[0].pAddr);
|
|
mgmt_bp_ss[1].pAddr = NULL;
|
|
mgmt_bp_ss[1].pAddr = 0;
|
|
// We have two possible management breaks, if previous instruction was branch or jump
|
|
if (is_branch_shadow)
|
|
{
|
|
result = tdisasm(g_buf, (long)pAddr_prev, *pAddr_prev, 0, &junk, &branch_addr, ®);
|
|
// Is jump target stored in register
|
|
if (result == 3)
|
|
{
|
|
branch_addr = xcp->regs[reg&0x1F];
|
|
}
|
|
// Save original instruction
|
|
mgmt_bp_ss[1].pAddr = (UINT32*)branch_addr;
|
|
mgmt_bp_ss[1].instr = *(mgmt_bp_ss[1].pAddr);
|
|
// Replace instruction with managment breakpoint
|
|
*(mgmt_bp_ss[1].pAddr) = BP_MGMT_SS(2);
|
|
ICACHE_invalidate_at(mgmt_bp_ss[1].pAddr);
|
|
}
|
|
break;
|
|
|
|
case 'P':
|
|
g_is_ss = 1;
|
|
leave_isr = 1;
|
|
// Don't overwrite RU breaks
|
|
if (is_user_bp)
|
|
break;
|
|
// Don't overwrite user breaks
|
|
if (IsBreak(*pInstr) && (BreakGetType(*pInstr) == BP_USER_BASE))
|
|
break;
|
|
|
|
// Save original instruction
|
|
mgmt_bp_ss[0].pAddr = (UINT32*)xcp->regs[0x1F];
|
|
mgmt_bp_ss[0].instr = *(mgmt_bp_ss[0].pAddr);
|
|
// Replace instruction with managment breakpoint
|
|
*(mgmt_bp_ss[0].pAddr) = BP_MGMT_SS(1);
|
|
ICACHE_invalidate_at(mgmt_bp_ss[0].pAddr);
|
|
mgmt_bp_ss[1].pAddr = NULL;
|
|
mgmt_bp_ss[1].pAddr = 0;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
} while (!leave_isr);
|
|
|
|
}
|
|
|
|
void debug_int(struct xcptcontext * xcp)
|
|
{
|
|
dbg_handler(xcp);
|
|
|
|
}
|
|
|
|
int debug_break(struct xcptcontext * xcp)
|
|
{
|
|
dbg_handler(xcp);
|
|
return 0;
|
|
|
|
}
|
|
|
|
void dbg_init(void)
|
|
{
|
|
|
|
interrupt_register(2, debug_int);
|
|
interrupt_enable(2);
|
|
|
|
xcpt_register(Bp, debug_break);
|
|
}
|
|
|