123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- /*
- * 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
|