blob: 796d5c4e62b467410172bcafeebf42694032a14d [file] [log] [blame]
/*
* 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: <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? */
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