/* * set up pointers to valid data (32Meg), to reduce address violations */ .macro reset_dags imm32 r0, 0x2000000; l0 = 0; l1 = 0; l2 = 0; l3 = 0; p0 = r0; p1 = r0; p2 = r0; p3 = r0; p4 = r0; p5 = r0; usp = r0; fp = r0; i0 = r0; i1 = r0; i2 = r0; i3 = r0; b0 = r0; b1 = r0; b2 = r0; b3 = r0; .endm #if SE_ALL_BITS == 32 # define LOAD_PFX #elif SE_ALL_BITS == 16 # define LOAD_PFX W #else # error "Please define SE_ALL_BITS" #endif /* * execute a test of an opcode space. host test * has to fill out a number of callbacks. * * se_all_insn_init * the first insn to start executing * se_all_insn_table * the table of insn ranges and expected seqstat * * se_all_load_insn * in: P5 * out: R0, R2 * scratch: R1 * load current user insn via register P5 into R0. * register R2 is available for caching with se_all_next_insn. * se_all_load_table * in: P1 * out: R7, R6, R5 * scratch: R1 * load insn range/seqstat entry from table via register P1 * R7: low range * R6: high range * R5: seqstat * * se_all_next_insn * in: P5, R2 * out: * scratch: all but P5 * advance current insn to next one for testing. register R2 * is retained from se_all_load_insn. write out new insn to * the location via register P5. * * se_all_new_insn_stub * se_all_new_insn_log * for handling of new insns ... generally not needed once done */ .macro se_all_test start /* Set up exception handler */ imm32 P4, EVT3; loadsym R1, _evx; [P4] = R1; /* set up the _location */ loadsym P0, _location loadsym P1, _table; [P0] = P1; /* Enable single stepping */ R0 = 1; SYSCFG = R0; /* Lower to the code we want to single step through */ loadsym P1, _usr; RETI = P1; /* set up pointers to valid data (32Meg), to reduce address violations */ reset_dags RTI; pass_lvl: dbg_pass; fail_lvl: dbg_fail; _evx: /* Make sure exception reason is as we expect */ R3 = SEQSTAT; R4 = 0x3f; R3 = R3 & R4; /* find a match */ loadsym P5, _usr; loadsym P4, _location; P1 = [P4]; se_all_load_insn _match: P2 = P1; se_all_load_table /* is this the end of the table? */ CC = R7 == 0; IF CC jump _new_instruction; /* is the opcode (R0) greater than the 2nd entry in the table (R6) */ /* if so look at the next line in the table */ CC = R6 < R0; if CC jump _match; /* is the opcode (R0) smaller than the first entry in the table (R7) */ /* this means it's somewhere between the two lines, and should be legal */ CC = R7 <= R0; if !CC jump _legal_instruction; /* is the current EXCAUSE (R3), the same as the table (R5) */ /* if not, fail */ CC = R3 == R5 if !CC jump fail_lvl; _match_done: /* back up, and store the location to search next */ [P4] = P2; /* it matches, so fall through */ jump _next_instruction; _new_instruction: /* The table is generated in memory and can be extracted: (gdb) dump binary memory bin &table next_location 16bit: $ od -j6 -x --width=4 bin | \ awk '{ s=last; e=strtonum("0x"$2); \ printf "\t.dw 0x%04x,\t0x%04x,\t\t0x%02x\n", \ s, e-1, strtonum("0x"seq); \ last=e; seq=$3}' 32bit: $ od -j12 -x --width=8 bin | \ awk '{ s=last; e=strtonum("0x"$3$2); \ printf "\t.dw 0x%04x, 0x%04x,\t0x%04x, 0x%04x,\t\t0x%02x, 0\n", \ and(s,0xffff), rshift(s,16), and(e-1,0xffff), rshift(e-1,16), \ strtonum("0x"seq); \ last=e; seq=$3}' This should be much faster than dumping over serial/jtag. */ se_all_new_insn_stub /* output the insn (R0) and excause (R3) if diff from last */ loadsym P0, _last_excause; R2 = [P0]; CC = R2 == R3; IF CC jump _next_instruction; [P0] = R3; se_all_new_insn_log _legal_instruction: R4 = 0x10; CC = R3 == R4; IF !CC JUMP fail_lvl; /* it wasn't in the list, and was a single step, so fall through */ _next_instruction: se_all_next_insn .ifdef BFIN_JTAG /* Make sure the opcode isn't in a write buffer */ SSYNC; .endif R1 = P5; RETX = R1; /* set up pointers to valid data (32Meg), to reduce address violations */ reset_dags RETS = r0; RTX; .section .text.usr .align 4 _usr: se_all_insn_init loadsym P0, fail_lvl; JUMP (P0); .data .align 4; _last_excause: .dd 0xffff _next_location: .dd _table_end _location: .dd 0 _table: se_all_insn_table _table_end: .endm .macro se_all_load_table R7 = LOAD_PFX[P1++]; R6 = LOAD_PFX[P1++]; R5 = LOAD_PFX[P1++]; .endm #ifndef SE_ALL_NEW_INSN_STUB .macro se_all_new_insn_stub jump fail_lvl; .endm #endif .macro se_all_new_insn_log .ifdef BFIN_JTAG_xxxxx R1 = R0; #if SE_ALL_BITS == 32 R0 = 0x8; call __emu_out; R0 = R1; call __emu_out; R0 = R3; #else R0 = 0x4; call __emu_out; R0 = R1 << 16; R0 = R0 | R3; #endif call __emu_out; .else loadsym P0, _next_location; P1 = [P0]; LOAD_PFX[P1++] = R0; LOAD_PFX[P1++] = R3; [P0] = P1; .endif .endm