2012-03-19 13:34:30 +08:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
|
2012-04-09 11:42:43 +08:00
|
|
|
#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
|
|
|
|
|
2012-03-19 13:34:30 +08:00
|
|
|
/*
|
|
|
|
* 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: <nothing>
|
|
|
|
* 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? */
|
2013-06-24 09:44:55 +08:00
|
|
|
CC = R7 == 0;
|
2012-03-19 13:34:30 +08:00
|
|
|
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:
|
2013-06-17 12:47:26 +08:00
|
|
|
/* 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. */
|
2012-03-19 13:34:30 +08:00
|
|
|
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
|
|
|
|
|
2013-06-24 09:44:55 +08:00
|
|
|
.ifdef BFIN_JTAG
|
2012-03-19 13:34:30 +08:00
|
|
|
/* Make sure the opcode isn't in a write buffer */
|
|
|
|
SSYNC;
|
2013-06-24 09:44:55 +08:00
|
|
|
.endif
|
2012-03-19 13:34:30 +08:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2012-04-09 11:42:43 +08:00
|
|
|
.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;
|
2012-03-19 13:34:30 +08:00
|
|
|
.endm
|
2012-04-09 11:42:43 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
.macro se_all_new_insn_log
|
2012-03-19 13:34:30 +08:00
|
|
|
.ifdef BFIN_JTAG_xxxxx
|
|
|
|
R1 = R0;
|
2012-04-09 11:42:43 +08:00
|
|
|
#if SE_ALL_BITS == 32
|
2012-03-19 13:34:30 +08:00
|
|
|
R0 = 0x8;
|
|
|
|
call __emu_out;
|
|
|
|
R0 = R1;
|
|
|
|
call __emu_out;
|
|
|
|
R0 = R3;
|
2012-04-09 11:42:43 +08:00
|
|
|
#else
|
|
|
|
R0 = 0x4;
|
|
|
|
call __emu_out;
|
|
|
|
R0 = R1 << 16;
|
|
|
|
R0 = R0 | R3;
|
|
|
|
#endif
|
2012-03-19 13:34:30 +08:00
|
|
|
call __emu_out;
|
|
|
|
.else
|
|
|
|
loadsym P0, _next_location;
|
|
|
|
P1 = [P0];
|
2012-04-09 11:42:43 +08:00
|
|
|
LOAD_PFX[P1++] = R0;
|
|
|
|
LOAD_PFX[P1++] = R3;
|
2012-03-19 13:34:30 +08:00
|
|
|
[P0] = P1;
|
|
|
|
.endif
|
|
|
|
.endm
|