I have been working on getting a software debugger up and running. I have the debug handler to operating. My tasks now are to (1)convince the JTAG to set the thread-under-inspection to single-step and (2) to read the CPU state, ie, the registers.
Working with henk over on the xlinkers forum, I have come up with the following code. However, it does not yield the correct registers.
Code: Select all
//sourced from pg 105 in xs1_en.pdf: 2009-10-19 release
//Each resource has a different type
#define RES_TYPE_FOR_THREAD 0x4
//This is for a given thread #
#define RES_FOR_THREAD(a) ((a << 24) | RES_TYPE_FOR_THREAD)
//C function called by the debug handler.
void load_cpu_state()
{
int i,j,k;
int cur_thread = 0;
int threadID;
int temp;
//what is the ID of our thread? - we're going to focus on thread 0 right now.
threadID = RES_FOR_THREAD(cur_thread);
//initialize our constants
//r0 is thread ID constant
asm("mov r0, %0" :: "r"(threadID) : "r0");
//r1 is address in the JTAG to set thread ID
asm("ldc r1, %0" :: "i"(RES_RID) : "r1");
//Set the JTAG to know what thread info we need.
//Set the JTAG[Thread ID] = CurrentThreadConstant
asm("set ps[r1], r0");
//Now we walk from r0 to r11.
for( i = 0; i < 12; i++)
{
temp = load_pushed_reg(i); //load_pushed_reg() goes out and grabs the registers.
say_num(temp); //Writes it out on the serial line.
cpu_state.r[i] = temp;
}
} //Exits back to the debug handler.
//Gets regnum
int load_pushed_reg(int regnum)
{
int ret;
//Using the mechanic of 'load settings', then GETREG, then mov the reg into a variable and return the variable.
//regnum is the register we want info about
asm("mov r1, %0" :: "r"(regnum) : "r1"); // writes r1
//r0 gets the DBG_T_REG number (0x14b)
asm("ldc r0, %0" :: "i"(0x140B));
//Set JTAG[Reg] = resource ID
asm("set ps[r0], r1");
//Pull the register value back from the JTAG
asm("dgetreg r2" ::: "r2");
//Save the register value into ret.
asm("mov %0, r2" : "=r"(ret));
return ret;
}