The current se_all*opcodes tests are very similar in how they work.
In preparation for adding more tests along these lines, unify the
common bits into a framework that others can include and build off
of easily.
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+2012-03-19 Mike Frysinger <vapier@gentoo.org>
+
+ * se_allopcodes.h: New framework for testing opcode regions.
+ * se_all16bitopcodes.S: Convert over to se_allopcodes.h.
+ * se_all32bitopcodes.S: Likewise.
+
2012-03-19 Stuart Henderson <stuart.henderson@analog.com>
* c_dsp32shiftim_amix.s: Check edge cases in shift behavior.
# sim: --environment operating
#include "test.h"
+#include "se_allopcodes.h"
.include "testutils.inc"
- 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 */
- .macro reset_regs
- 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
- reset_regs
-
- RTI;
-
- .align 4;
-_evx:
- /* Make sure exception reason is single step */
- R3 = SEQSTAT;
- R4 = 0x3f;
- R3 = R3 & R4;
-
- /* find a match */
- loadsym P5, _usr;
- loadsym P4, _location;
+.macro se_all_load_insn
R2 = W[P5];
- P1 = [P4];
R0 = R2;
-
-_match:
- P2 = P1;
+.endm
+.macro se_all_load_table
R7 = W[P1++];
R6 = W[P1++];
R5 = W[P1++];
+.endm
- /* is this the end of the table? */
- R4 = 0;
- CC = R4 == R7;
- 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:
- jump _legal_instruction;
-
- /* 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;
-
-.ifdef BFIN_JTAG_xxxxx
- R1 = R0;
- R0 = 0x4;
- call __emu_out;
- R0 = R1 << 16;
- R0 = R0 | R3;
- call __emu_out;
-.else
- loadsym P0, _next_location;
- P1 = [P0];
- W[P1++] = R0;
- W[P1++] = R3;
- [P0] = P1;
-.endif
-
- jump _next_instruction;
-
-_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:
+.macro se_all_next_insn
/* increment, and go again. */
R0 = R2;
IF CC JUMP pass_lvl;
W[P5] = R0;
+.endm
- /* Make sure the opcode isn't in a write buffer */
- SSYNC;
-
- R1 = P5;
- RETX = R1;
-
- /* set up pointers to valid data (32Meg), to reduce address violations */
- reset_regs
- RETS = r0;
- RETN = r0;
- RETE = r0;
- RETI = r0;
-
- RTX;
-
-pass_lvl:
- dbg_pass;
-fail_lvl:
- dbg_fail;
+.macro se_all_new_insn_stub
+ jump _legal_instruction;
+.endm
+.macro se_all_new_insn_log
+ se_all_new_16bit_insn_log
+.endm
- .section .text.usr
- .align 4
-_usr:
+.macro se_all_insn_init
.dw 0x0000;
- loadsym P0, fail_lvl;
- JUMP (P0);
-
+.endm
+.macro se_all_insn_table
/* this table must be sorted, and end with zero */
- .data
- .align 4;
-_last_excause:
- .dd 0xffff
-_next_location:
- .dd _table_end
-_location:
- .dd 0
-_table:
/* start end SEQSTAT */
.dw 0x0001, 0x000f, 0x21
.dw 0x0011, 0x0013, 0x2e
.dw 0x9ef0, 0x9eff, 0x21
.dw 0x9f70, 0x9f7f, 0x21
.dw 0x0000, 0x0000, 0x00
-_table_end:
+.endm
+
+ se_all_test
# xfail: too many invalid insns are decoded as valid
#include "test.h"
+#include "se_allopcodes.h"
.include "testutils.inc"
- 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 */
- .macro reset_regs
- 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
- reset_regs
-
- RTI;
-
- .align 4;
-_evx:
- /* Make sure exception reason is single step */
- R3 = SEQSTAT;
- R4 = 0x3f;
- R3 = R3 & R4;
-
- /* find a match */
- loadsym P5, _usr;
- loadsym P4, _location;
+.macro se_all_load_insn
R2 = [P5];
- P1 = [P4];
R0 = R2 << 16;
R1 = R2 >> 16;
R0 = R0 | R1;
-
-_match:
- P2 = P1;
+.endm
+.macro se_all_load_table
R7 = [P1++];
R6 = [P1++];
R5 = [P1++];
+.endm
- /* is this the end of the table? */
- R4 = 0;
- CC = R4 == R7;
- 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:
- jump fail_lvl;
-
- /* 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;
-
-.ifdef BFIN_JTAG_xxxxx
- R1 = R0;
- R0 = 0x8;
- call __emu_out;
- R0 = R1;
- call __emu_out;
- R0 = R3;
- call __emu_out;
-.else
- loadsym P0, _next_location;
- P1 = [P0];
- [P1++] = R0;
- [P1++] = R3;
- [P0] = P1;
-.endif
-
- jump _next_instruction;
-
-_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:
+.macro se_all_next_insn
/* increment, and go again. */
R0 = R2;
1:
[P5] = R0;
+.endm
- /* Make sure the opcode isn't in a write buffer */
- SSYNC;
-
- R1 = P5;
- RETX = R1;
-
- /* set up pointers to valid data (32Meg), to reduce address violations */
- reset_regs
- RETS = r0;
- RETN = r0;
- RETE = r0;
- RETI = r0;
-
- RTX;
-
-pass_lvl:
- dbg_pass;
-fail_lvl:
- dbg_fail;
+.macro se_all_new_insn_stub
+ jump fail_lvl;
+.endm
+.macro se_all_new_insn_log
+ se_all_new_32bit_insn_log
+.endm
- .section .text.usr
- .align 4
-_usr:
+.macro se_all_insn_init
.dw 0xc000;
.dw 0x0000;
- loadsym P0, fail_lvl;
- JUMP (P0);
-
+.endm
+.macro se_all_insn_table
/* this table must be sorted, and end with zero */
- .data
- .align 4;
-_last_excause:
- .dd 0xffff
-_next_location:
- .dd _table_end
-_location:
- .dd 0
-_table:
/* start end SEQSTAT */
.dw 0x1a00, 0xc000, 0x1fff, 0xc000, 0x21, 0
.dw 0x3a00, 0xc000, 0x3fff, 0xc000, 0x21, 0
.dw 0x0000, 0xe740, 0xffff, 0xe7ff, 0x21, 0
.dw 0x0000, 0xf001, 0xffff, 0xffff, 0x21, 0
.dw 0x0000, 0x0000, 0x0000, 0x0000, 0x00, 0
-_table_end:
+.endm
+
+ se_all_test
--- /dev/null
+/*
+ * 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
+
+/*
+ * 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? */
+ R4 = 0;
+ CC = R4 == R7;
+ 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:
+ 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
+
+ /* Make sure the opcode isn't in a write buffer */
+ SSYNC;
+
+ R1 = P5;
+ RETX = R1;
+
+ /* set up pointers to valid data (32Meg), to reduce address violations */
+ reset_dags
+ RETS = r0;
+ RETN = r0;
+ RETE = r0;
+ RETI = 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_new_16bit_insn_log
+.ifdef BFIN_JTAG_xxxxx
+ R1 = R0;
+ R0 = 0x4;
+ call __emu_out;
+ R0 = R1 << 16;
+ R0 = R0 | R3;
+ call __emu_out;
+.else
+ loadsym P0, _next_location;
+ P1 = [P0];
+ W[P1++] = R0;
+ W[P1++] = R3;
+ [P0] = P1;
+.endif
+.endm
+.macro se_all_new_32bit_insn_log
+.ifdef BFIN_JTAG_xxxxx
+ R1 = R0;
+ R0 = 0x8;
+ call __emu_out;
+ R0 = R1;
+ call __emu_out;
+ R0 = R3;
+ call __emu_out;
+.else
+ loadsym P0, _next_location;
+ P1 = [P0];
+ [P1++] = R0;
+ [P1++] = R3;
+ [P0] = P1;
+.endif
+.endm