summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/cpu/drcuml.c
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2008-05-19 00:58:16 +0000
committer Aaron Giles <aaron@aarongiles.com>2008-05-19 00:58:16 +0000
commit969a70550887ef35c309056bd45e9f2bf5f3fd15 (patch)
tree10b5f202d433b4f1e67c10200e3e5a15b5a4c6ad /src/emu/cpu/drcuml.c
parent383c7daf6212aebe58e9d6976045e544cd5b1e9b (diff)
Added back-end validation mechanism, and a handful of tests as examples.
This will be expanded in the future. Added two new opcodes: SAVE and RESTORE to save and restore the entire virtual machine state for examination/setup. Added new back-end function get_info() which returns information from the back-end about how many actual registers will be mapped. Fixed a bug that mapped the high a low parts of registers to the same address. This should help the C back-end run better on big-endian architectures.
Diffstat (limited to 'src/emu/cpu/drcuml.c')
-rw-r--r--src/emu/cpu/drcuml.c786
1 files changed, 669 insertions, 117 deletions
diff --git a/src/emu/cpu/drcuml.c b/src/emu/cpu/drcuml.c
index df62b75d897..05a7426d479 100644
--- a/src/emu/cpu/drcuml.c
+++ b/src/emu/cpu/drcuml.c
@@ -32,10 +32,6 @@
- RECALL handle
change code at caller to call handle in the future
- * Add interface for getting hints from the backend:
- - number of direct-mapped integer registers
- - number of direct-mapped floating point registers
-
***************************************************************************/
#include "drcuml.h"
@@ -48,27 +44,54 @@
/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define VALIDATE_BACKEND (0)
+
+
+
+/***************************************************************************
CONSTANTS
***************************************************************************/
/* opcode validation condition/flag valid bitmasks */
#define OV_CONDFLAG_NONE 0x00
#define OV_CONDFLAG_COND 0x80
+#define OV_CONDFLAG_SZ (DRCUML_FLAG_S | DRCUML_FLAG_Z)
+#define OV_CONDFLAG_SZC (DRCUML_FLAG_S | DRCUML_FLAG_Z | DRCUML_FLAG_C)
+#define OV_CONDFLAG_SZVC (DRCUML_FLAG_S | DRCUML_FLAG_Z | DRCUML_FLAG_V | DRCUML_FLAG_C)
+#define OV_CONDFLAG_UZC (DRCUML_FLAG_U | DRCUML_FLAG_Z | DRCUML_FLAG_C)
#define OV_CONDFLAG_FLAGS 0x1f
-/* opcode validation parameter valid bitmasks */
+/* bitmasks of valid parameter types and flags */
#define OV_PARAM_ALLOWED_NONE (1 << DRCUML_PTYPE_NONE)
#define OV_PARAM_ALLOWED_IMM (1 << DRCUML_PTYPE_IMMEDIATE)
#define OV_PARAM_ALLOWED_IREG (1 << DRCUML_PTYPE_INT_REGISTER)
#define OV_PARAM_ALLOWED_FREG (1 << DRCUML_PTYPE_FLOAT_REGISTER)
#define OV_PARAM_ALLOWED_MVAR (1 << DRCUML_PTYPE_MAPVAR)
#define OV_PARAM_ALLOWED_MEM (1 << DRCUML_PTYPE_MEMORY)
-#define OV_PARAM_ALLOWED_NCMEM (OV_PARAM_ALLOWED_MEM | 0x80)
+#define OV_PARAM_FLAG_ANYMEM 0x100
+#define OV_PARAM_FLAG_FIXED4 0x200
+#define OV_PARAM_FLAG_FIXED8 0x400
+
+/* opcode validation parameter valid bitmasks */
+#define OV_PARAM_ALLOWED_ANYMEM (OV_PARAM_ALLOWED_MEM | OV_PARAM_FLAG_ANYMEM)
#define OV_PARAM_ALLOWED_IMV (OV_PARAM_ALLOWED_IMM | OV_PARAM_ALLOWED_MVAR)
+#define OV_PARAM_ALLOWED_IMV4 (OV_PARAM_ALLOWED_IMM | OV_PARAM_ALLOWED_MVAR | OV_PARAM_FLAG_FIXED4)
+#define OV_PARAM_ALLOWED_IMV8 (OV_PARAM_ALLOWED_IMM | OV_PARAM_ALLOWED_MVAR | OV_PARAM_FLAG_FIXED8)
#define OV_PARAM_ALLOWED_IRM (OV_PARAM_ALLOWED_IREG | OV_PARAM_ALLOWED_MEM)
+#define OV_PARAM_ALLOWED_IRM4 (OV_PARAM_ALLOWED_IREG | OV_PARAM_ALLOWED_MEM | OV_PARAM_FLAG_FIXED4)
+#define OV_PARAM_ALLOWED_IRM8 (OV_PARAM_ALLOWED_IREG | OV_PARAM_ALLOWED_MEM | OV_PARAM_FLAG_FIXED8)
#define OV_PARAM_ALLOWED_FRM (OV_PARAM_ALLOWED_FREG | OV_PARAM_ALLOWED_MEM)
+#define OV_PARAM_ALLOWED_FRM4 (OV_PARAM_ALLOWED_FREG | OV_PARAM_ALLOWED_MEM | OV_PARAM_FLAG_FIXED4)
+#define OV_PARAM_ALLOWED_FRM8 (OV_PARAM_ALLOWED_FREG | OV_PARAM_ALLOWED_MEM | OV_PARAM_FLAG_FIXED8)
#define OV_PARAM_ALLOWED_IANY (OV_PARAM_ALLOWED_IRM | OV_PARAM_ALLOWED_IMV)
+#define OV_PARAM_ALLOWED_IANY4 (OV_PARAM_ALLOWED_IRM | OV_PARAM_ALLOWED_IMV | OV_PARAM_FLAG_FIXED4)
+#define OV_PARAM_ALLOWED_IANY8 (OV_PARAM_ALLOWED_IRM | OV_PARAM_ALLOWED_IMV | OV_PARAM_FLAG_FIXED8)
#define OV_PARAM_ALLOWED_FANY (OV_PARAM_ALLOWED_FRM)
+#define OV_PARAM_ALLOWED_FANY4 (OV_PARAM_ALLOWED_FRM | OV_PARAM_FLAG_FIXED4)
+#define OV_PARAM_ALLOWED_FANY8 (OV_PARAM_ALLOWED_FRM | OV_PARAM_FLAG_FIXED8)
@@ -121,10 +144,20 @@ struct _drcuml_opcode_valid
drcuml_opcode opcode; /* the opcode itself */
UINT8 sizes; /* allowed sizes */
UINT8 condflags; /* allowed conditions/flags */
- UINT8 p0types; /* allowed types for parameter 0 */
- UINT8 p1types; /* allowed types for parameter 1 */
- UINT8 p2types; /* allowed types for parameter 2 */
- UINT8 p3types; /* allowed types for parameter 3 */
+ UINT16 ptypes[4]; /* allowed types for parameters */
+};
+
+
+/* structure describing back-end validation test */
+typedef struct _bevalidate_test bevalidate_test;
+struct _bevalidate_test
+{
+ drcuml_opcode opcode;
+ UINT8 size;
+ UINT8 destmask;
+ UINT8 iflags;
+ UINT8 flags;
+ UINT64 param[4];
};
@@ -134,11 +167,11 @@ struct _drcuml_opcode_valid
***************************************************************************/
/* macro to simplify the table */
-#define OPVALID_ENTRY_0(op,sizes,condflag) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE },
-#define OPVALID_ENTRY_1(op,sizes,condflag,p0) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, OV_PARAM_ALLOWED_##p0, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE },
-#define OPVALID_ENTRY_2(op,sizes,condflag,p0,p1) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, OV_PARAM_ALLOWED_##p0, OV_PARAM_ALLOWED_##p1, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE },
-#define OPVALID_ENTRY_3(op,sizes,condflag,p0,p1,p2) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, OV_PARAM_ALLOWED_##p0, OV_PARAM_ALLOWED_##p1, OV_PARAM_ALLOWED_##p2, OV_PARAM_ALLOWED_NONE },
-#define OPVALID_ENTRY_4(op,sizes,condflag,p0,p1,p2,p3) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, OV_PARAM_ALLOWED_##p0, OV_PARAM_ALLOWED_##p1, OV_PARAM_ALLOWED_##p2, OV_PARAM_ALLOWED_##p3 },
+#define OPVALID_ENTRY_0(op,sizes,condflag) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, { OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE } },
+#define OPVALID_ENTRY_1(op,sizes,condflag,p0) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, { OV_PARAM_ALLOWED_##p0, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE } },
+#define OPVALID_ENTRY_2(op,sizes,condflag,p0,p1) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, { OV_PARAM_ALLOWED_##p0, OV_PARAM_ALLOWED_##p1, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE } },
+#define OPVALID_ENTRY_3(op,sizes,condflag,p0,p1,p2) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, { OV_PARAM_ALLOWED_##p0, OV_PARAM_ALLOWED_##p1, OV_PARAM_ALLOWED_##p2, OV_PARAM_ALLOWED_NONE } },
+#define OPVALID_ENTRY_4(op,sizes,condflag,p0,p1,p2,p3) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, { OV_PARAM_ALLOWED_##p0, OV_PARAM_ALLOWED_##p1, OV_PARAM_ALLOWED_##p2, OV_PARAM_ALLOWED_##p3 } },
/* opcode validation table */
static const drcuml_opcode_valid opcode_valid_list[] =
@@ -147,7 +180,7 @@ static const drcuml_opcode_valid opcode_valid_list[] =
OPVALID_ENTRY_1(HANDLE, 4, NONE, MEM)
OPVALID_ENTRY_2(HASH, 4, NONE, IMV, IMV)
OPVALID_ENTRY_1(LABEL, 4, NONE, IMV)
- OPVALID_ENTRY_1(COMMENT, 4, NONE, NCMEM)
+ OPVALID_ENTRY_1(COMMENT, 4, NONE, ANYMEM)
OPVALID_ENTRY_2(MAPVAR, 4, NONE, MVAR, IMV)
/* Control Flow Operations */
@@ -159,102 +192,104 @@ static const drcuml_opcode_valid opcode_valid_list[] =
OPVALID_ENTRY_2(EXH, 4, COND, MEM, IANY)
OPVALID_ENTRY_1(CALLH, 4, COND, MEM)
OPVALID_ENTRY_0(RET, 4, COND)
- OPVALID_ENTRY_2(CALLC, 4, COND, NCMEM,NCMEM)
+ OPVALID_ENTRY_2(CALLC, 4, COND, ANYMEM,ANYMEM)
OPVALID_ENTRY_2(RECOVER, 4, NONE, IRM, MVAR)
/* Internal Register Operations */
OPVALID_ENTRY_1(SETFMOD, 4, NONE, IANY)
OPVALID_ENTRY_1(GETFMOD, 4, NONE, IRM)
OPVALID_ENTRY_1(GETEXP, 4, NONE, IRM)
+ OPVALID_ENTRY_1(SAVE, 4, NONE, ANYMEM)
+ OPVALID_ENTRY_1(RESTORE, 4, NONE, ANYMEM)
/* Integer Operations */
- OPVALID_ENTRY_3(LOAD1U, 4|8, NONE, IRM, NCMEM,IANY)
- OPVALID_ENTRY_3(LOAD1S, 4|8, NONE, IRM, NCMEM,IANY)
- OPVALID_ENTRY_3(LOAD2U, 4|8, NONE, IRM, NCMEM,IANY)
- OPVALID_ENTRY_3(LOAD2S, 4|8, NONE, IRM, NCMEM,IANY)
- OPVALID_ENTRY_3(LOAD4U, 4|8, NONE, IRM, NCMEM,IANY)
- OPVALID_ENTRY_3(LOAD4S, 8, NONE, IRM, NCMEM,IANY)
- OPVALID_ENTRY_3(LOAD8U, 8, NONE, IRM, NCMEM,IANY)
- OPVALID_ENTRY_3(STORE1, 4|8, NONE, NCMEM,IANY, IANY)
- OPVALID_ENTRY_3(STORE2, 4|8, NONE, NCMEM,IANY, IANY)
- OPVALID_ENTRY_3(STORE4, 4|8, NONE, NCMEM,IANY, IANY)
- OPVALID_ENTRY_3(STORE8, 8, NONE, NCMEM,IANY, IANY)
- OPVALID_ENTRY_3(READ1U, 4|8, NONE, IRM, IMV, IANY)
- OPVALID_ENTRY_3(READ1S, 4|8, NONE, IRM, IMV, IANY)
- OPVALID_ENTRY_3(READ2U, 4|8, NONE, IRM, IMV, IANY)
- OPVALID_ENTRY_3(READ2S, 4|8, NONE, IRM, IMV, IANY)
- OPVALID_ENTRY_4(READ2M, 4|8, NONE, IRM, IMV, IANY, IANY)
- OPVALID_ENTRY_3(READ4U, 4|8, NONE, IRM, IMV, IANY)
- OPVALID_ENTRY_3(READ4S, 8, NONE, IRM, IMV, IANY)
- OPVALID_ENTRY_4(READ4M, 4|8, NONE, IRM, IMV, IANY, IANY)
- OPVALID_ENTRY_3(READ8U, 8, NONE, IRM, IMV, IANY)
- OPVALID_ENTRY_4(READ8M, 8, NONE, IRM, IMV, IANY, IANY)
- OPVALID_ENTRY_3(WRITE1, 4|8, NONE, IMV, IANY, IANY)
- OPVALID_ENTRY_3(WRITE2, 4|8, NONE, IMV, IANY, IANY)
- OPVALID_ENTRY_4(WRIT2M, 4|8, NONE, IMV, IANY, IANY, IANY)
- OPVALID_ENTRY_3(WRITE4, 4|8, NONE, IMV, IANY, IANY)
- OPVALID_ENTRY_4(WRIT4M, 4|8, NONE, IMV, IANY, IANY, IANY)
- OPVALID_ENTRY_3(WRITE8, 8, NONE, IMV, IANY, IANY)
- OPVALID_ENTRY_4(WRIT8M, 8, NONE, IMV, IANY, IANY, IANY)
- OPVALID_ENTRY_3(FLAGS, 4|8, NONE, IRM, IMV, MEM)
- OPVALID_ENTRY_2(MOV, 4|8, COND, IRM, IANY)
- OPVALID_ENTRY_2(ZEXT1, 4|8, NONE, IRM, IANY)
- OPVALID_ENTRY_2(ZEXT2, 4|8, NONE, IRM, IANY)
- OPVALID_ENTRY_2(ZEXT4, 8, NONE, IRM, IANY)
- OPVALID_ENTRY_2(SEXT1, 4|8, NONE, IRM, IANY)
- OPVALID_ENTRY_2(SEXT2, 4|8, NONE, IRM, IANY)
- OPVALID_ENTRY_2(SEXT4, 8, NONE, IRM, IANY)
- OPVALID_ENTRY_3(ADD, 4|8, FLAGS, IRM, IANY, IANY)
- OPVALID_ENTRY_3(ADDC, 4|8, FLAGS, IRM, IANY, IANY)
- OPVALID_ENTRY_3(SUB, 4|8, FLAGS, IRM, IANY, IANY)
- OPVALID_ENTRY_3(SUBB, 4|8, FLAGS, IRM, IANY, IANY)
- OPVALID_ENTRY_2(CMP, 4|8, FLAGS, IANY, IANY)
- OPVALID_ENTRY_4(MULU, 4|8, FLAGS, IRM, IRM, IANY, IANY)
- OPVALID_ENTRY_4(MULS, 4|8, FLAGS, IRM, IRM, IANY, IANY)
- OPVALID_ENTRY_4(DIVU, 4|8, FLAGS, IRM, IRM, IANY, IANY)
- OPVALID_ENTRY_4(DIVS, 4|8, FLAGS, IRM, IRM, IANY, IANY)
- OPVALID_ENTRY_3(AND, 4|8, FLAGS, IRM, IANY, IANY)
- OPVALID_ENTRY_2(TEST, 4|8, FLAGS, IANY, IANY)
- OPVALID_ENTRY_3(OR, 4|8, FLAGS, IRM, IANY, IANY)
- OPVALID_ENTRY_3(XOR, 4|8, FLAGS, IRM, IANY, IANY)
- OPVALID_ENTRY_3(SHL, 4|8, FLAGS, IRM, IANY, IANY)
- OPVALID_ENTRY_3(SHR, 4|8, FLAGS, IRM, IANY, IANY)
- OPVALID_ENTRY_3(SAR, 4|8, FLAGS, IRM, IANY, IANY)
- OPVALID_ENTRY_3(ROL, 4|8, FLAGS, IRM, IANY, IANY)
- OPVALID_ENTRY_3(ROLC, 4|8, FLAGS, IRM, IANY, IANY)
- OPVALID_ENTRY_3(ROR, 4|8, FLAGS, IRM, IANY, IANY)
- OPVALID_ENTRY_3(RORC, 4|8, FLAGS, IRM, IANY, IANY)
+ OPVALID_ENTRY_3(LOAD1U, 4|8, NONE, IRM, ANYMEM,IANY4)
+ OPVALID_ENTRY_3(LOAD1S, 4|8, NONE, IRM, ANYMEM,IANY4)
+ OPVALID_ENTRY_3(LOAD2U, 4|8, NONE, IRM, ANYMEM,IANY4)
+ OPVALID_ENTRY_3(LOAD2S, 4|8, NONE, IRM, ANYMEM,IANY4)
+ OPVALID_ENTRY_3(LOAD4U, 4|8, NONE, IRM, ANYMEM,IANY4)
+ OPVALID_ENTRY_3(LOAD4S, 8, NONE, IRM, ANYMEM,IANY4)
+ OPVALID_ENTRY_3(LOAD8U, 8, NONE, IRM, ANYMEM,IANY4)
+ OPVALID_ENTRY_3(STORE1, 4|8, NONE, ANYMEM,IANY4, IANY)
+ OPVALID_ENTRY_3(STORE2, 4|8, NONE, ANYMEM,IANY4, IANY)
+ OPVALID_ENTRY_3(STORE4, 4|8, NONE, ANYMEM,IANY4, IANY)
+ OPVALID_ENTRY_3(STORE8, 8, NONE, ANYMEM,IANY4, IANY)
+ OPVALID_ENTRY_3(READ1U, 4|8, NONE, IRM, IMV4, IANY4)
+ OPVALID_ENTRY_3(READ1S, 4|8, NONE, IRM, IMV4, IANY4)
+ OPVALID_ENTRY_3(READ2U, 4|8, NONE, IRM, IMV4, IANY4)
+ OPVALID_ENTRY_3(READ2S, 4|8, NONE, IRM, IMV4, IANY4)
+ OPVALID_ENTRY_4(READ2M, 4|8, NONE, IRM, IMV4, IANY4, IANY)
+ OPVALID_ENTRY_3(READ4U, 4|8, NONE, IRM, IMV4, IANY4)
+ OPVALID_ENTRY_3(READ4S, 8, NONE, IRM, IMV4, IANY4)
+ OPVALID_ENTRY_4(READ4M, 4|8, NONE, IRM, IMV4, IANY4, IANY)
+ OPVALID_ENTRY_3(READ8U, 8, NONE, IRM, IMV4, IANY4)
+ OPVALID_ENTRY_4(READ8M, 8, NONE, IRM, IMV4, IANY4, IANY)
+ OPVALID_ENTRY_3(WRITE1, 4|8, NONE, IMV4, IANY4, IANY)
+ OPVALID_ENTRY_3(WRITE2, 4|8, NONE, IMV4, IANY4, IANY)
+ OPVALID_ENTRY_4(WRIT2M, 4|8, NONE, IMV4, IANY4, IANY, IANY)
+ OPVALID_ENTRY_3(WRITE4, 4|8, NONE, IMV4, IANY4, IANY)
+ OPVALID_ENTRY_4(WRIT4M, 4|8, NONE, IMV4, IANY4, IANY, IANY)
+ OPVALID_ENTRY_3(WRITE8, 8, NONE, IMV4, IANY4, IANY)
+ OPVALID_ENTRY_4(WRIT8M, 8, NONE, IMV4, IANY4, IANY, IANY)
+ OPVALID_ENTRY_3(FLAGS, 4|8, NONE, IRM, IMV, MEM)
+ OPVALID_ENTRY_2(MOV, 4|8, COND, IRM, IANY)
+ OPVALID_ENTRY_2(ZEXT1, 4|8, NONE, IRM, IANY4)
+ OPVALID_ENTRY_2(ZEXT2, 4|8, NONE, IRM, IANY4)
+ OPVALID_ENTRY_2(ZEXT4, 8, NONE, IRM, IANY4)
+ OPVALID_ENTRY_2(SEXT1, 4|8, NONE, IRM, IANY4)
+ OPVALID_ENTRY_2(SEXT2, 4|8, NONE, IRM, IANY4)
+ OPVALID_ENTRY_2(SEXT4, 8, NONE, IRM, IANY4)
+ OPVALID_ENTRY_3(ADD, 4|8, SZVC, IRM, IANY, IANY)
+ OPVALID_ENTRY_3(ADDC, 4|8, SZVC, IRM, IANY, IANY)
+ OPVALID_ENTRY_3(SUB, 4|8, SZVC, IRM, IANY, IANY)
+ OPVALID_ENTRY_3(SUBB, 4|8, SZVC, IRM, IANY, IANY)
+ OPVALID_ENTRY_2(CMP, 4|8, SZVC, IANY, IANY)
+ OPVALID_ENTRY_4(MULU, 4|8, SZ, IRM, IRM, IANY, IANY)
+ OPVALID_ENTRY_4(MULS, 4|8, SZ, IRM, IRM, IANY, IANY)
+ OPVALID_ENTRY_4(DIVU, 4|8, SZ, IRM, IRM, IANY, IANY)
+ OPVALID_ENTRY_4(DIVS, 4|8, SZ, IRM, IRM, IANY, IANY)
+ OPVALID_ENTRY_3(AND, 4|8, SZ, IRM, IANY, IANY)
+ OPVALID_ENTRY_2(TEST, 4|8, SZ, IANY, IANY)
+ OPVALID_ENTRY_3(OR, 4|8, SZ, IRM, IANY, IANY)
+ OPVALID_ENTRY_3(XOR, 4|8, SZ, IRM, IANY, IANY)
+ OPVALID_ENTRY_3(SHL, 4|8, SZC, IRM, IANY, IANY)
+ OPVALID_ENTRY_3(SHR, 4|8, SZC, IRM, IANY, IANY)
+ OPVALID_ENTRY_3(SAR, 4|8, SZC, IRM, IANY, IANY)
+ OPVALID_ENTRY_3(ROL, 4|8, SZC, IRM, IANY, IANY)
+ OPVALID_ENTRY_3(ROLC, 4|8, SZC, IRM, IANY, IANY)
+ OPVALID_ENTRY_3(ROR, 4|8, SZC, IRM, IANY, IANY)
+ OPVALID_ENTRY_3(RORC, 4|8, SZC, IRM, IANY, IANY)
/* Floating Point Operations */
- OPVALID_ENTRY_3(FLOAD, 4|8, NONE, FRM, NCMEM,IANY)
- OPVALID_ENTRY_3(FSTORE, 4|8, NONE, NCMEM,IANY, FANY)
- OPVALID_ENTRY_3(FREAD, 4|8, NONE, FRM, IMV, IANY)
- OPVALID_ENTRY_3(FWRITE, 4|8, NONE, IMV, IANY, FANY)
- OPVALID_ENTRY_2(FMOV, 4|8, COND, FRM, FANY)
- OPVALID_ENTRY_2(FTOI4, 4|8, NONE, IRM, FANY)
- OPVALID_ENTRY_2(FTOI4T, 4|8, NONE, IRM, FANY)
- OPVALID_ENTRY_2(FTOI4R, 4|8, NONE, IRM, FANY)
- OPVALID_ENTRY_2(FTOI4F, 4|8, NONE, IRM, FANY)
- OPVALID_ENTRY_2(FTOI4C, 4|8, NONE, IRM, FANY)
- OPVALID_ENTRY_2(FTOI8, 4|8, NONE, IRM, FANY)
- OPVALID_ENTRY_2(FTOI8T, 4|8, NONE, IRM, FANY)
- OPVALID_ENTRY_2(FTOI8R, 4|8, NONE, IRM, FANY)
- OPVALID_ENTRY_2(FTOI8F, 4|8, NONE, IRM, FANY)
- OPVALID_ENTRY_2(FTOI8C, 4|8, NONE, IRM, FANY)
- OPVALID_ENTRY_2(FFRFS, 8, NONE, FRM, FANY)
- OPVALID_ENTRY_2(FFRFD, 4 , NONE, FRM, FANY)
- OPVALID_ENTRY_2(FFRI4, 4|8, NONE, FRM, IANY)
- OPVALID_ENTRY_2(FFRI8, 4|8, NONE, FRM, IANY)
- OPVALID_ENTRY_3(FADD, 4|8, FLAGS, FRM, FANY, FANY)
- OPVALID_ENTRY_3(FSUB, 4|8, FLAGS, FRM, FANY, FANY)
- OPVALID_ENTRY_2(FCMP, 4|8, FLAGS, FANY, FANY)
- OPVALID_ENTRY_3(FMUL, 4|8, FLAGS, FRM, FANY, FANY)
- OPVALID_ENTRY_3(FDIV, 4|8, FLAGS, FRM, FANY, FANY)
- OPVALID_ENTRY_2(FNEG, 4|8, FLAGS, FRM, FANY)
- OPVALID_ENTRY_2(FABS, 4|8, FLAGS, FRM, FANY)
- OPVALID_ENTRY_2(FSQRT, 4|8, FLAGS, FRM, FANY)
- OPVALID_ENTRY_2(FRECIP, 4|8, NONE, FRM, FANY)
- OPVALID_ENTRY_2(FRSQRT, 4|8, NONE, FRM, FANY)
+ OPVALID_ENTRY_3(FLOAD, 4|8, NONE, FRM, ANYMEM,IANY4)
+ OPVALID_ENTRY_3(FSTORE, 4|8, NONE, ANYMEM,IANY4, FANY)
+ OPVALID_ENTRY_3(FREAD, 4|8, NONE, FRM, IMV4, IANY4)
+ OPVALID_ENTRY_3(FWRITE, 4|8, NONE, IMV4, IANY4, FANY)
+ OPVALID_ENTRY_2(FMOV, 4|8, COND, FRM, FANY)
+ OPVALID_ENTRY_2(FTOI4, 4|8, NONE, IRM4, FANY)
+ OPVALID_ENTRY_2(FTOI4T, 4|8, NONE, IRM4, FANY)
+ OPVALID_ENTRY_2(FTOI4R, 4|8, NONE, IRM4, FANY)
+ OPVALID_ENTRY_2(FTOI4F, 4|8, NONE, IRM4, FANY)
+ OPVALID_ENTRY_2(FTOI4C, 4|8, NONE, IRM4, FANY)
+ OPVALID_ENTRY_2(FTOI8, 4|8, NONE, IRM8, FANY)
+ OPVALID_ENTRY_2(FTOI8T, 4|8, NONE, IRM8, FANY)
+ OPVALID_ENTRY_2(FTOI8R, 4|8, NONE, IRM8, FANY)
+ OPVALID_ENTRY_2(FTOI8F, 4|8, NONE, IRM8, FANY)
+ OPVALID_ENTRY_2(FTOI8C, 4|8, NONE, IRM8, FANY)
+ OPVALID_ENTRY_2(FFRFS, 8, NONE, FRM, FANY4)
+ OPVALID_ENTRY_2(FFRFD, 4 , NONE, FRM, FANY8)
+ OPVALID_ENTRY_2(FFRI4, 4|8, NONE, FRM, IANY4)
+ OPVALID_ENTRY_2(FFRI8, 4|8, NONE, FRM, IANY8)
+ OPVALID_ENTRY_3(FADD, 4|8, NONE, FRM, FANY, FANY)
+ OPVALID_ENTRY_3(FSUB, 4|8, NONE, FRM, FANY, FANY)
+ OPVALID_ENTRY_2(FCMP, 4|8, UZC, FANY, FANY)
+ OPVALID_ENTRY_3(FMUL, 4|8, NONE, FRM, FANY, FANY)
+ OPVALID_ENTRY_3(FDIV, 4|8, NONE, FRM, FANY, FANY)
+ OPVALID_ENTRY_2(FNEG, 4|8, NONE, FRM, FANY)
+ OPVALID_ENTRY_2(FABS, 4|8, NONE, FRM, FANY)
+ OPVALID_ENTRY_2(FSQRT, 4|8, NONE, FRM, FANY)
+ OPVALID_ENTRY_2(FRECIP, 4|8, NONE, FRM, FANY)
+ OPVALID_ENTRY_2(FRSQRT, 4|8, NONE, FRM, FANY)
};
@@ -282,11 +317,53 @@ static drcuml_opcode_valid opcode_valid_table[DRCUML_OP_MAX];
FUNCTION PROTOTYPES
***************************************************************************/
-#ifdef MAME_DEBUG
static void validate_instruction(drcuml_block *block, const drcuml_instruction *inst);
-#else
-#define validate_instruction(block, inst) do { } while (0)
-#endif
+static void validate_backend(drcuml_state *drcuml);
+static void bevalidate_iterate_over_params(drcuml_state *drcuml, drcuml_codehandle **handles, const bevalidate_test *test, drcuml_parameter *paramlist, int pnum);
+static void bevalidate_iterate_over_flags(drcuml_state *drcuml, drcuml_codehandle **handles, const bevalidate_test *test, drcuml_parameter *paramlist);
+static void bevalidate_execute(drcuml_state *drcuml, drcuml_codehandle **handles, const bevalidate_test *test, const drcuml_parameter *paramlist, UINT8 flagmask);
+static void bevalidate_initialize_random_state(drcuml_block *block, drcuml_machine_state *state);
+static int bevalidate_populate_state(drcuml_block *block, drcuml_machine_state *state, const bevalidate_test *test, const drcuml_parameter *paramlist, drcuml_parameter *params, UINT64 *parammem);
+static int bevalidate_verify_state(drcuml_state *drcuml, const drcuml_machine_state *istate, drcuml_machine_state *state, const bevalidate_test *test, const drcuml_parameter *params, const drcuml_instruction *testinst, drccodeptr codestart, drccodeptr codeend, UINT8 flagmask);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ size_for_param - given a set of parameter
+ flags and the instruction size, return the
+ size of the parameter
+-------------------------------------------------*/
+
+INLINE int size_for_param(int instsize, UINT16 flags)
+{
+ if (flags & OV_PARAM_FLAG_FIXED4)
+ return 4;
+ else if (flags & OV_PARAM_FLAG_FIXED8)
+ return 8;
+ else
+ return instsize;
+}
+
+
+/*-------------------------------------------------
+ mask_for_param - given a set of parameter
+ flags and the instruction size, return a
+ mask of valid bits for that parameter
+-------------------------------------------------*/
+
+INLINE UINT64 mask_for_param(int instsize, UINT16 flags)
+{
+ switch (size_for_param(instsize, flags))
+ {
+ case 4: return U64(0x00000000ffffffff);
+ case 8: return U64(0xffffffffffffffff);
+ }
+ return 0;
+}
@@ -335,6 +412,17 @@ drcuml_state *drcuml_alloc(drccache *cache, UINT32 flags, int modes, int addrbit
/*-------------------------------------------------
+ drcuml_get_backend_info - return information
+ about the back-end
+-------------------------------------------------*/
+
+void drcuml_get_backend_info(drcuml_state *drcuml, drcbe_info *info)
+{
+ (*drcuml->beintf->be_get_info)(drcuml->bestate, info);
+}
+
+
+/*-------------------------------------------------
drcuml_reset - reset the state completely,
flushing the cache and all information
-------------------------------------------------*/
@@ -343,7 +431,7 @@ void drcuml_reset(drcuml_state *drcuml)
{
drcuml_codehandle *handle;
jmp_buf errorbuf;
-
+
/* flush the cache */
drccache_flush(drcuml->cache);
@@ -357,6 +445,17 @@ void drcuml_reset(drcuml_state *drcuml)
/* call the backend to reset */
(*drcuml->beintf->be_reset)(drcuml->bestate);
+
+ /* do a one-time validation if requested */
+ if (VALIDATE_BACKEND)
+ {
+ static int validated = FALSE;
+ if (!validated)
+ {
+ validated = TRUE;
+ validate_backend(drcuml);
+ }
+ }
}
@@ -817,7 +916,6 @@ void drcuml_add_comment(drcuml_block *block, const char *format, ...)
instruction created meets all requirements
-------------------------------------------------*/
-#ifdef MAME_DEBUG
static void validate_instruction(drcuml_block *block, const drcuml_instruction *inst)
{
const drcuml_opcode_valid *opvalid = &opcode_valid_table[inst->opcode];
@@ -829,30 +927,484 @@ static void validate_instruction(drcuml_block *block, const drcuml_instruction *
if (inst->numparams > 0)
{
assert(inst->param[0].type > DRCUML_PTYPE_NONE && inst->param[0].type < DRCUML_PTYPE_MAX);
- assert(((opvalid->p0types >> inst->param[0].type) & 1) != 0);
- if (inst->param[0].type == DRCUML_PTYPE_MEMORY && !(opvalid->p0types & 0x80))
+ assert(((opvalid->ptypes[0] >> inst->param[0].type) & 1) != 0);
+ if (inst->param[0].type == DRCUML_PTYPE_MEMORY && !(opvalid->ptypes[0] & OV_PARAM_FLAG_ANYMEM))
assert_in_near_cache(block->drcuml->cache, (void *)(FPTR)inst->param[0].value);
}
if (inst->numparams > 1)
{
assert(inst->param[1].type > DRCUML_PTYPE_NONE && inst->param[1].type < DRCUML_PTYPE_MAX);
- assert(((opvalid->p1types >> inst->param[1].type) & 1) != 0);
- if (inst->param[1].type == DRCUML_PTYPE_MEMORY && !(opvalid->p1types & 0x80))
+ assert(((opvalid->ptypes[1] >> inst->param[1].type) & 1) != 0);
+ if (inst->param[1].type == DRCUML_PTYPE_MEMORY && !(opvalid->ptypes[1] & OV_PARAM_FLAG_ANYMEM))
assert_in_near_cache(block->drcuml->cache, (void *)(FPTR)inst->param[1].value);
}
if (inst->numparams > 2)
{
assert(inst->param[2].type > DRCUML_PTYPE_NONE && inst->param[2].type < DRCUML_PTYPE_MAX);
- assert(((opvalid->p2types >> inst->param[2].type) & 1) != 0);
- if (inst->param[2].type == DRCUML_PTYPE_MEMORY && !(opvalid->p2types & 0x80))
+ assert(((opvalid->ptypes[2] >> inst->param[2].type) & 1) != 0);
+ if (inst->param[2].type == DRCUML_PTYPE_MEMORY && !(opvalid->ptypes[2] & OV_PARAM_FLAG_ANYMEM))
assert_in_near_cache(block->drcuml->cache, (void *)(FPTR)inst->param[2].value);
}
if (inst->numparams > 3)
{
assert(inst->param[3].type > DRCUML_PTYPE_NONE && inst->param[3].type < DRCUML_PTYPE_MAX);
- assert(((opvalid->p3types >> inst->param[3].type) & 1) != 0);
- if (inst->param[3].type == DRCUML_PTYPE_MEMORY && !(opvalid->p3types & 0x80))
+ assert(((opvalid->ptypes[3] >> inst->param[3].type) & 1) != 0);
+ if (inst->param[3].type == DRCUML_PTYPE_MEMORY && !(opvalid->ptypes[3] & OV_PARAM_FLAG_ANYMEM))
assert_in_near_cache(block->drcuml->cache, (void *)(FPTR)inst->param[3].value);
}
}
-#endif
+
+
+
+/***************************************************************************
+ BACK-END VALIDATION
+***************************************************************************/
+
+#define TEST_ENTRY_DSS(op, size, p1, p2, p3, flags) { DRCUML_OP_##op, size, 0x01, 0, flags, { U64(p1), U64(p2), U64(p3) } },
+#define TEST_ENTRY_DSSI(op, size, p1, p2, p3, iflags, flags) { DRCUML_OP_##op, size, 0x01, iflags, flags, { U64(p1), U64(p2), U64(p3) } },
+
+static const bevalidate_test bevalidate_test_list[] =
+{
+ TEST_ENTRY_DSS(ADD, 4, 0x7fffffff, 0x12345678, 0x6dcba987, 0)
+ TEST_ENTRY_DSS(ADD, 4, 0x80000000, 0x12345678, 0x6dcba988, FLAGS_V | FLAGS_S)
+ TEST_ENTRY_DSS(ADD, 4, 0xffffffff, 0x92345678, 0x6dcba987, FLAGS_S)
+ TEST_ENTRY_DSS(ADD, 4, 0x00000000, 0x92345678, 0x6dcba988, FLAGS_C | FLAGS_Z)
+
+ TEST_ENTRY_DSS(ADD, 8, 0x7fffffffffffffff, 0x0123456789abcdef, 0x7edcba9876543210, 0)
+ TEST_ENTRY_DSS(ADD, 8, 0x8000000000000000, 0x0123456789abcdef, 0x7edcba9876543211, FLAGS_V | FLAGS_S)
+ TEST_ENTRY_DSS(ADD, 8, 0xffffffffffffffff, 0x8123456789abcdef, 0x7edcba9876543210, FLAGS_S)
+ TEST_ENTRY_DSS(ADD, 8, 0x0000000000000000, 0x8123456789abcdef, 0x7edcba9876543211, FLAGS_C | FLAGS_Z)
+
+ TEST_ENTRY_DSSI(ADDC, 4, 0x7fffffff, 0x12345678, 0x6dcba987, 0, 0)
+ TEST_ENTRY_DSSI(ADDC, 4, 0x7fffffff, 0x12345678, 0x6dcba986, FLAGS_C, 0)
+ TEST_ENTRY_DSSI(ADDC, 4, 0x80000000, 0x12345678, 0x6dcba988, 0, FLAGS_V | FLAGS_S)
+ TEST_ENTRY_DSSI(ADDC, 4, 0x80000000, 0x12345678, 0x6dcba987, FLAGS_C, FLAGS_V | FLAGS_S)
+ TEST_ENTRY_DSSI(ADDC, 4, 0xffffffff, 0x92345678, 0x6dcba987, 0, FLAGS_S)
+ TEST_ENTRY_DSSI(ADDC, 4, 0xffffffff, 0x92345678, 0x6dcba986, FLAGS_C, FLAGS_S)
+ TEST_ENTRY_DSSI(ADDC, 4, 0x00000000, 0x92345678, 0x6dcba988, 0, FLAGS_C | FLAGS_Z)
+ TEST_ENTRY_DSSI(ADDC, 4, 0x00000000, 0x92345678, 0x6dcba987, FLAGS_C, FLAGS_C | FLAGS_Z)
+ TEST_ENTRY_DSSI(ADDC, 4, 0x12345678, 0x12345678, 0xffffffff, FLAGS_C, FLAGS_C)
+
+ TEST_ENTRY_DSSI(ADDC, 8, 0x7fffffffffffffff, 0x0123456789abcdef, 0x7edcba9876543210, 0, 0)
+ TEST_ENTRY_DSSI(ADDC, 8, 0x7fffffffffffffff, 0x0123456789abcdef, 0x7edcba987654320f, FLAGS_C, 0)
+ TEST_ENTRY_DSSI(ADDC, 8, 0x8000000000000000, 0x0123456789abcdef, 0x7edcba9876543211, 0, FLAGS_V | FLAGS_S)
+ TEST_ENTRY_DSSI(ADDC, 8, 0x8000000000000000, 0x0123456789abcdef, 0x7edcba9876543210, FLAGS_C, FLAGS_V | FLAGS_S)
+ TEST_ENTRY_DSSI(ADDC, 8, 0xffffffffffffffff, 0x8123456789abcdef, 0x7edcba9876543210, 0, FLAGS_S)
+ TEST_ENTRY_DSSI(ADDC, 8, 0xffffffffffffffff, 0x8123456789abcdef, 0x7edcba987654320f, FLAGS_C, FLAGS_S)
+ TEST_ENTRY_DSSI(ADDC, 8, 0x0000000000000000, 0x8123456789abcdef, 0x7edcba9876543211, 0, FLAGS_C | FLAGS_Z)
+ TEST_ENTRY_DSSI(ADDC, 8, 0x0000000000000000, 0x8123456789abcdef, 0x7edcba9876543210, FLAGS_C, FLAGS_C | FLAGS_Z)
+ TEST_ENTRY_DSSI(ADDC, 8, 0x123456789abcdef0, 0x123456789abcdef0, 0xffffffffffffffff, FLAGS_C, FLAGS_C)
+};
+
+
+/*-------------------------------------------------
+ validate_backend - execute a number of
+ generic tests on the backend code generator
+-------------------------------------------------*/
+
+static void validate_backend(drcuml_state *drcuml)
+{
+ drcuml_codehandle *handles[3];
+ int tnum;
+
+ /* allocate handles for the code */
+ handles[0] = drcuml_handle_alloc(drcuml, "test_entry");
+ handles[1] = drcuml_handle_alloc(drcuml, "code_start");
+ handles[2] = drcuml_handle_alloc(drcuml, "code_end");
+
+ /* iterate over test entries */
+ printf("Backend validation....\n");
+ for (tnum = 0; tnum < ARRAY_LENGTH(bevalidate_test_list); tnum++)
+ {
+ const bevalidate_test *test = &bevalidate_test_list[tnum];
+ drcuml_parameter param[ARRAY_LENGTH(test->param)];
+
+ /* reset parameter list and iterate */
+ memset(param, 0, sizeof(param));
+ printf("Executing test %d/%d", tnum + 1, ARRAY_LENGTH(bevalidate_test_list));
+ bevalidate_iterate_over_params(drcuml, handles, test, param, 0);
+ printf("\n");
+ }
+ fatalerror("All tests passed!");
+}
+
+
+/*-------------------------------------------------
+ bevalidate_iterate_over_params - iterate over
+ all supported types and values of a parameter
+ and recursively hand off to the next parameter,
+ or else move on to iterate over the flags
+-------------------------------------------------*/
+
+static void bevalidate_iterate_over_params(drcuml_state *drcuml, drcuml_codehandle **handles, const bevalidate_test *test, drcuml_parameter *paramlist, int pnum)
+{
+ const drcuml_opcode_valid *opvalid = &opcode_valid_table[test->opcode];
+
+ /* if no parameters, execute now */
+ if (pnum >= ARRAY_LENGTH(opvalid->ptypes) || opvalid->ptypes[pnum] == OV_PARAM_ALLOWED_NONE)
+ {
+ bevalidate_iterate_over_flags(drcuml, handles, test, paramlist);
+ return;
+ }
+
+ /* iterate over valid parameter types */
+ for (paramlist[pnum].type = DRCUML_PTYPE_IMMEDIATE; paramlist[pnum].type < DRCUML_PTYPE_MAX; paramlist[pnum].type++)
+ if (opvalid->ptypes[pnum] & (1 << paramlist[pnum].type))
+ {
+ int pindex, pcount;
+
+ /* mapvars can only do 32-bit tests */
+ if (paramlist[pnum].type == DRCUML_PTYPE_MAPVAR && size_for_param(test->size, opvalid->ptypes[pnum]) == 8)
+ continue;
+
+ /* for some parameter types, we wish to iterate over all possibilities */
+ switch (paramlist[pnum].type)
+ {
+ case DRCUML_PTYPE_INT_REGISTER: pcount = DRCUML_REG_I_END - DRCUML_REG_I0; break;
+ case DRCUML_PTYPE_FLOAT_REGISTER: pcount = DRCUML_REG_F_END - DRCUML_REG_F0; break;
+ case DRCUML_PTYPE_MAPVAR: pcount = DRCUML_MAPVAR_END - DRCUML_MAPVAR_M0; break;
+ default: pcount = 1; break;
+ }
+
+ /* iterate over possibilities */
+ for (pindex = 0; pindex < pcount; pindex++)
+ {
+ int skip = FALSE;
+ int pscannum;
+
+ /* for param 0, print a dot */
+ if (pnum == 0)
+ printf(".");
+
+ /* can't duplicate multiple source parameters unless they are immediates */
+ if (paramlist[pnum].type != DRCUML_PTYPE_IMMEDIATE && ((test->destmask >> pnum) & 1) == 0)
+
+ /* loop over all parameters we've done before; if the parameter is a source and matches us, skip this case */
+ for (pscannum = 0; pscannum < pnum; pscannum++)
+ if (((test->destmask >> pscannum) & 1) == 0 && paramlist[pnum].type == paramlist[pscannum].type && pindex == paramlist[pscannum].value)
+ skip = TRUE;
+
+ /* iterate over the next parameter in line */
+ if (!skip)
+ {
+ paramlist[pnum].value = pindex;
+ bevalidate_iterate_over_params(drcuml, handles, test, paramlist, pnum + 1);
+ }
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ bevalidate_iterate_over_flags - iterate over
+ all supported flag masks
+-------------------------------------------------*/
+
+static void bevalidate_iterate_over_flags(drcuml_state *drcuml, drcuml_codehandle **handles, const bevalidate_test *test, drcuml_parameter *paramlist)
+{
+ const drcuml_opcode_valid *opvalid = &opcode_valid_table[test->opcode];
+ UINT8 flagmask = opvalid->condflags & 0x1f;
+ UINT8 curmask;
+
+ /* iterate over all possible flag combinations */
+ for (curmask = 0; curmask <= flagmask; curmask++)
+ if ((curmask & flagmask) == curmask)
+ bevalidate_execute(drcuml, handles, test, paramlist, curmask);
+}
+
+
+/*-------------------------------------------------
+ bevalidate_execute - execute a single instance
+ of a test, generating code and verifying the
+ results
+-------------------------------------------------*/
+
+static void bevalidate_execute(drcuml_state *drcuml, drcuml_codehandle **handles, const bevalidate_test *test, const drcuml_parameter *paramlist, UINT8 flagmask)
+{
+ drcuml_parameter params[ARRAY_LENGTH(test->param)];
+ drcuml_machine_state istate, fstate;
+ drcuml_instruction testinst;
+ drcuml_block *block;
+ UINT64 *parammem;
+ int numparams;
+
+ /* allocate memory for parameters */
+ parammem = drccache_memory_alloc_near(drcuml->cache, sizeof(UINT64) * ARRAY_LENGTH(test->param));
+
+ /* flush the cache */
+ drcuml_reset(drcuml);
+
+ /* start a new block */
+ block = drcuml_block_begin(drcuml, 30, NULL);
+ UML_HANDLE(block, handles[0]);
+
+ /* set up a random initial state */
+ bevalidate_initialize_random_state(block, &istate);
+
+ /* then populate the state with the parameters */
+ numparams = bevalidate_populate_state(block, &istate, test, paramlist, params, parammem);
+
+ /* generate the code */
+ UML_RESTORE(block, &istate);
+ UML_HANDLE(block, handles[1]);
+ switch (numparams)
+ {
+ case 0:
+ drcuml_block_append_0(block, test->opcode, test->size, flagmask);
+ break;
+
+ case 1:
+ drcuml_block_append_1(block, test->opcode, test->size, flagmask, params[0].type, params[0].value);
+ break;
+
+ case 2:
+ drcuml_block_append_2(block, test->opcode, test->size, flagmask, params[0].type, params[0].value, params[1].type, params[1].value);
+ break;
+
+ case 3:
+ drcuml_block_append_3(block, test->opcode, test->size, flagmask, params[0].type, params[0].value, params[1].type, params[1].value, params[2].type, params[2].value);
+ break;
+
+ case 4:
+ drcuml_block_append_4(block, test->opcode, test->size, flagmask, params[0].type, params[0].value, params[1].type, params[1].value, params[2].type, params[2].value, params[3].type, params[3].value);
+ break;
+ }
+ testinst = block->inst[block->nextinst - 1];
+ UML_HANDLE(block, handles[2]);
+ UML_SAVE(block, &fstate);
+ UML_EXIT(block, IMM(0));
+
+ /* end the block */
+ drcuml_block_end(block);
+
+ /* execute */
+ drcuml_execute(drcuml, handles[0]);
+
+ /* verify the results */
+ bevalidate_verify_state(drcuml, &istate, &fstate, test, params, &testinst, handles[1]->code, handles[2]->code, flagmask);
+
+ /* free memory */
+ drccache_memory_free(drcuml->cache, parammem, sizeof(UINT64) * ARRAY_LENGTH(test->param));
+}
+
+
+/*-------------------------------------------------
+ bevalidate_initialize_random_state -
+ initialize the machine state to randomness
+-------------------------------------------------*/
+
+static void bevalidate_initialize_random_state(drcuml_block *block, drcuml_machine_state *state)
+{
+ int regnum;
+
+ /* initialize core state to random values */
+ state->fmod = mame_rand(Machine) & 0x03;
+ state->flags = mame_rand(Machine) & 0x1f;
+ state->exp = mame_rand(Machine);
+
+ /* initialize integer registers to random values */
+ for (regnum = 0; regnum < ARRAY_LENGTH(state->r); regnum++)
+ {
+ state->r[regnum].w.h = mame_rand(Machine);
+ state->r[regnum].w.l = mame_rand(Machine);
+ }
+
+ /* initialize float registers to random values */
+ for (regnum = 0; regnum < ARRAY_LENGTH(state->f); regnum++)
+ {
+ *(UINT32 *)&state->f[regnum].s.h = mame_rand(Machine);
+ *(UINT32 *)&state->f[regnum].s.l = mame_rand(Machine);
+ }
+
+ /* initialize map variables to random values */
+ for (regnum = 0; regnum < DRCUML_MAPVAR_END - DRCUML_MAPVAR_M0; regnum++)
+ UML_MAPVAR(block, MVAR(regnum), mame_rand(Machine));
+}
+
+
+/*-------------------------------------------------
+ bevalidate_populate_state - populate the
+ machine state with the proper values prior
+ to executing a test
+-------------------------------------------------*/
+
+static int bevalidate_populate_state(drcuml_block *block, drcuml_machine_state *state, const bevalidate_test *test, const drcuml_parameter *paramlist, drcuml_parameter *params, UINT64 *parammem)
+{
+ const drcuml_opcode_valid *opvalid = &opcode_valid_table[test->opcode];
+ int numparams = ARRAY_LENGTH(test->param);
+ int pnum;
+
+ /* copy flags as-is */
+ state->flags = test->iflags;
+
+ /* iterate over parameters */
+ for (pnum = 0; pnum < ARRAY_LENGTH(test->param); pnum++)
+ {
+ int psize = size_for_param(test->size, opvalid->ptypes[pnum]);
+ drcuml_parameter *curparam = &params[pnum];
+
+ /* start with a copy of the parameter from the list */
+ *curparam = paramlist[pnum];
+
+ /* switch off the type */
+ switch (curparam->type)
+ {
+ /* immediate parameters: take the value from the test entry */
+ case DRCUML_PTYPE_IMMEDIATE:
+ curparam->value = test->param[pnum];
+ break;
+
+ /* register parameters: set the register value in the state and set the parameter value to the register index */
+ case DRCUML_PTYPE_INT_REGISTER:
+ state->r[curparam->value].d = test->param[pnum];
+ curparam->value += DRCUML_REG_I0;
+ break;
+
+ /* register parameters: set the register value in the state and set the parameter value to the register index */
+ case DRCUML_PTYPE_FLOAT_REGISTER:
+ state->f[curparam->value].d = test->param[pnum];
+ curparam->value += DRCUML_REG_F0;
+ break;
+
+ /* memory parameters: set the memory value in the parameter space and set the parameter value to point to it */
+ case DRCUML_PTYPE_MEMORY:
+ curparam->value = (FPTR)&parammem[pnum];
+ if (psize == 4)
+ *(UINT32 *)(FPTR)curparam->value = test->param[pnum];
+ else
+ *(UINT64 *)(FPTR)curparam->value = test->param[pnum];
+ break;
+
+ /* map variables: issue a MAPVAR instruction to set the value and set the parameter value to the mapvar index */
+ case DRCUML_PTYPE_MAPVAR:
+ UML_MAPVAR(block, MVAR(curparam->value), test->param[pnum]);
+ curparam->value += DRCUML_MAPVAR_M0;
+ break;
+
+ /* use anything else to count the number of parameters */
+ default:
+ numparams = MIN(numparams, pnum);
+ break;
+ }
+ }
+
+ /* return the total number of parameters */
+ return numparams;
+}
+
+
+/*-------------------------------------------------
+ bevalidate_verify_state - verify the final
+ state after executing a test, and report any
+ discrepancies
+-------------------------------------------------*/
+
+static int bevalidate_verify_state(drcuml_state *drcuml, const drcuml_machine_state *istate, drcuml_machine_state *state, const bevalidate_test *test, const drcuml_parameter *params, const drcuml_instruction *testinst, drccodeptr codestart, drccodeptr codeend, UINT8 flagmask)
+{
+ const drcuml_opcode_valid *opvalid = &opcode_valid_table[test->opcode];
+ UINT8 ireg[DRCUML_REG_I_END - DRCUML_REG_I0] = { 0 };
+ UINT8 freg[DRCUML_REG_F_END - DRCUML_REG_F0] = { 0 };
+ char errorbuf[1024];
+ char *errend = errorbuf;
+ int pnum, regnum;
+
+ *errend = 0;
+
+ /* check flags */
+ if ((state->flags & flagmask) != (test->flags & flagmask))
+ {
+ errend += sprintf(errend, " Flags ... result:%c%c%c%c%c expected:%c%c%c%c%c\n",
+ (flagmask & DRCUML_FLAG_U) ? ((state->flags & DRCUML_FLAG_U) ? 'U' : '.') : '-',
+ (flagmask & DRCUML_FLAG_S) ? ((state->flags & DRCUML_FLAG_S) ? 'S' : '.') : '-',
+ (flagmask & DRCUML_FLAG_Z) ? ((state->flags & DRCUML_FLAG_Z) ? 'Z' : '.') : '-',
+ (flagmask & DRCUML_FLAG_V) ? ((state->flags & DRCUML_FLAG_V) ? 'V' : '.') : '-',
+ (flagmask & DRCUML_FLAG_C) ? ((state->flags & DRCUML_FLAG_C) ? 'C' : '.') : '-',
+ (flagmask & DRCUML_FLAG_U) ? ((test->flags & DRCUML_FLAG_U) ? 'U' : '.') : '-',
+ (flagmask & DRCUML_FLAG_S) ? ((test->flags & DRCUML_FLAG_S) ? 'S' : '.') : '-',
+ (flagmask & DRCUML_FLAG_Z) ? ((test->flags & DRCUML_FLAG_Z) ? 'Z' : '.') : '-',
+ (flagmask & DRCUML_FLAG_V) ? ((test->flags & DRCUML_FLAG_V) ? 'V' : '.') : '-',
+ (flagmask & DRCUML_FLAG_C) ? ((test->flags & DRCUML_FLAG_C) ? 'C' : '.') : '-');
+ }
+
+ /* check destination parameters */
+ for (pnum = 0; pnum < ARRAY_LENGTH(test->param); pnum++)
+ if (test->destmask & (1 << pnum))
+ {
+ UINT64 mask = mask_for_param(test->size, opvalid->ptypes[pnum]);
+ int psize = size_for_param(test->size, opvalid->ptypes[pnum]);
+ UINT64 result = 0;
+
+ /* fetch the result from the parameters */
+ switch (params[pnum].type)
+ {
+ /* integer registers fetch from the state */
+ case DRCUML_PTYPE_INT_REGISTER:
+ ireg[params[pnum].value - DRCUML_REG_I0] = 1;
+ result = state->r[params[pnum].value - DRCUML_REG_I0].d;
+ break;
+
+ /* float registers fetch from the state */
+ case DRCUML_PTYPE_FLOAT_REGISTER:
+ freg[params[pnum].value - DRCUML_REG_I0] = 1;
+ result = state->f[params[pnum].value - DRCUML_REG_F0].d;
+ break;
+
+ /* memory registers fetch from the memory address */
+ case DRCUML_PTYPE_MEMORY:
+ if (psize == 4)
+ result = *(UINT32 *)(FPTR)params[pnum].value;
+ else
+ result = *(UINT64 *)(FPTR)params[pnum].value;
+ break;
+
+ default:
+ break;
+ }
+
+ /* check against the mask */
+ if ((result & mask) != (test->param[pnum] & mask))
+ {
+ if ((UINT32)mask == mask)
+ errend += sprintf(errend, " Parameter %d ... result:%08X expected:%08X\n", pnum,
+ (UINT32)(result & mask), (UINT32)(test->param[pnum] & mask));
+ else
+ errend += sprintf(errend, " Parameter %d ... result:%08X%08X expected:%08X%08X\n", pnum,
+ (UINT32)((result & mask) >> 32), (UINT32)(result & mask),
+ (UINT32)((test->param[pnum] & mask) >> 32), (UINT32)(test->param[pnum] & mask));
+ }
+ }
+
+ /* check source integer parameters for unexpected alterations */
+ for (regnum = 0; regnum < ARRAY_LENGTH(state->r); regnum++)
+ if (ireg[regnum] == 0 && istate->r[regnum].d != state->r[regnum].d)
+ errend += sprintf(errend, " Register i%d ... result:%08X%08X originally:%08X%08X\n", regnum,
+ (UINT32)(state->r[regnum].d >> 32), (UINT32)state->r[regnum].d,
+ (UINT32)(istate->r[regnum].d >> 32), (UINT32)istate->r[regnum].d);
+
+ /* check source float parameters for unexpected alterations */
+ for (regnum = 0; regnum < ARRAY_LENGTH(state->f); regnum++)
+ if (freg[regnum] == 0 && *(UINT64 *)&istate->f[regnum].d != *(UINT64 *)&state->f[regnum].d)
+ errend += sprintf(errend, " Register f%d ... result:%08X%08X originally:%08X%08X\n", regnum,
+ (UINT32)(*(UINT64 *)&state->f[regnum].d >> 32), (UINT32)*(UINT64 *)&state->f[regnum].d,
+ (UINT32)(*(UINT64 *)&istate->f[regnum].d >> 32), (UINT32)*(UINT64 *)&istate->f[regnum].d);
+
+ /* output the error if we have one */
+ if (errend != errorbuf)
+ {
+ char disasm[100];
+
+ /* disassemble the test instruction */
+ drcuml_disasm(testinst, disasm);
+
+ /* output a description of what went wrong */
+ printf("\n");
+ printf("----------------------------------------------\n");
+ printf("Backend validation error:\n");
+ printf(" %s\n", disasm);
+ printf("\n");
+ printf("Errors:\n");
+ printf("%s\n", errorbuf);
+ fatalerror("Error during validation");
+ }
+ return errend != errorbuf;
+}