]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
CPU tester improved FPU support, can continue after failed test, 68000 bus/address...
authorToni Wilen <twilen@winuae.net>
Sat, 9 May 2020 17:05:23 +0000 (20:05 +0300)
committerToni Wilen <twilen@winuae.net>
Sat, 9 May 2020 17:05:23 +0000 (20:05 +0300)
cputest.cpp
cputest/asm.S
cputest/cputest_defines.h
cputest/cputestgen.ini
cputest/main.c
cputest/readme.txt

index d045774d41ae125cbd1f6b44794afc1d5afb656f..21242367959849d4b6e692bf40762ec6928b5b60 100644 (file)
 static floatx80 fpuregisters[8];
 static uae_u32 fpu_fpiar, fpu_fpcr, fpu_fpsr;
 
+struct regtype
+{
+       const TCHAR *name;
+       uae_u8 type;
+};
+struct regdata
+{
+       uae_u32 data[3];
+       uae_u8 type;
+};
+
 const int areg_byteinc[] = { 1, 1, 1, 1, 1, 1, 1, 2 };
 const int imm8_table[] = { 8, 1, 2, 3, 4, 5, 6, 7 };
 
@@ -69,6 +80,9 @@ static int target_ea_src_max, target_ea_dst_max, target_ea_opcode_max;
 static uae_u32 target_ea[3];
 static int maincpu[6];
 static uae_u8 exceptionenabletable[256];
+#define MAX_REGDATAS 32
+static int regdatacnt;
+static struct regdata regdatas[MAX_REGDATAS];
 
 #define HIGH_MEMORY_START (addressing_mask == 0xffffffff ? 0xffff8000 : 0x00ff8000)
 
@@ -146,7 +160,7 @@ static int low_memory_accessed;
 static int high_memory_accessed;
 static int test_memory_accessed;
 static uae_u16 extra_or, extra_and;
-static uae_u32 cur_registers[MAX_REGISTERS];
+static struct regstruct cur_regs;
 static uae_u16 read_buffer_prev;
 static int interrupt_count;
 
@@ -166,6 +180,27 @@ static int noaccesshistory = 0;
 #define MAX_ACCESSHIST 16000
 static struct accesshistory ahist[MAX_ACCESSHIST];
 
+static void pw(uae_u8 *p, uae_u16 v)
+{
+       p[0] = v >> 8;
+       p[1] = v >> 0;
+}
+static void pl(uae_u8 *p, uae_u32 v)
+{
+       p[0] = v >> 24;
+       p[1] = v >> 16;
+       p[2] = v >> 8;
+       p[3] = v >> 0;
+}
+static uae_u32 gl(uae_u8 *p)
+{
+       return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
+}
+static uae_u32 gw(uae_u8 *p)
+{
+       return (p[0] << 8) | (p[1] << 0);
+}
+
 void cputester_fault(void)
 {
        test_exception = -1;
@@ -1051,6 +1086,8 @@ static void doexcstack(void)
        regs.sr &= ~0x8000;
        MakeFromSR();
 
+       regs.pc = original_exception * 4;
+
        int flags = 0;
        if (cpu_lvl == 1) {
                // IF = 1
@@ -1124,6 +1161,14 @@ uae_u32 REGPARAM2 op_illg(uae_u32 opcode)
        return op_illg_1(opcode);
 }
 
+static void exception3_pc_inc(void)
+{
+       if (currprefs.cpu_model == 68000) {
+               m68k_incpci(2);
+       }
+}
+
+
 static void exception2_fetch_common(uae_u32 opcode, int offset)
 {
        test_exception = 2;
@@ -1270,7 +1315,6 @@ void exception3_read_prefetch_only(uae_u32 opcode, uae_u32 addr)
        } else {
                add_memory_cycles(1);
        }
-
        test_exception = 3;
        test_exception_3_w = 0;
        test_exception_addr = addr;
@@ -1289,6 +1333,7 @@ void exception3_read_prefetch(uae_u32 opcode, uae_u32 addr)
        } else {
                add_memory_cycles(1);
        }
+       exception3_pc_inc();
 
        test_exception = 3;
        test_exception_3_w = 0;
@@ -1322,7 +1367,6 @@ void exception3_write_access(uae_u32 opcode, uae_u32 addr, int size, uae_u32 val
 {
        add_memory_cycles(1);
        exception3_write(opcode, addr, size, val, fc);
-
 }
 
 uae_u16 exception3_word_read(uaecptr addr)
@@ -1506,12 +1550,22 @@ static int regcnts[16];
 static int fpuregcnts[8];
 static float_status fpustatus;
 
-static bool fpuregchange(int reg, floatx80 *regs)
+static bool fpuregchange(int reg, fpdata *regs)
 {
        int regcnt = fpuregcnts[reg];
-       floatx80 v = regs[reg];
+       floatx80 v = regs[reg].fpx;
        floatx80 add;
 
+       // don't unnecessarily modify static forced register
+       for (int i = 0; i < regdatacnt; i++) {
+               struct regdata *rd = &regdatas[i];
+               int mode = rd->type & CT_DATA_MASK;
+               int size = rd->type & CT_SIZE_MASK;
+               if (size == CT_SIZE_FPU && mode == CT_DREG + reg) {
+                       return false;
+               }
+       }
+
        switch(reg)
        {
        case 0: // positive
@@ -1568,7 +1622,7 @@ static bool fpuregchange(int reg, floatx80 *regs)
                break;
        }
        fpuregcnts[reg]++;
-       regs[reg] = v;
+       regs[reg].fpx = v;
        return true;
 }
 
@@ -1580,6 +1634,16 @@ static bool regchange(int reg, uae_u32 *regs)
        if (generate_address_mode && reg >= 8)
                return false;
 
+       // don't unnecessarily modify static forced register
+       for (int i = 0; i < regdatacnt; i++) {
+               struct regdata *rd = &regdatas[i];
+               int mode = rd->type & CT_DATA_MASK;
+               int size = rd->type & CT_SIZE_MASK;
+               if (size != CT_SIZE_FPU && mode == CT_DREG + reg) {
+                       return false;
+               }
+       }
+
        switch (reg)
        {
        case 0:
@@ -1730,6 +1794,74 @@ static void save_memory(const TCHAR *path, const TCHAR *name, uae_u8 *p, int siz
        compressfile(fname, 2);
 }
 
+static uae_u8 *modify_reg(uae_u8 *dst, struct regstruct *regs, uae_u8 type, uae_u32 *valp)
+{
+       int mode = type & CT_DATA_MASK;
+       int size = type & CT_SIZE_MASK;
+       uae_u32 val = valp[0];
+       if (size != CT_SIZE_FPU && mode >= CT_DREG && mode < CT_DREG + 8) {
+               if (regs->regs[mode - CT_DREG] == val)
+                       return dst;
+               regs->regs[mode - CT_DREG] = val;
+       } else if (size != CT_SIZE_FPU && mode >= CT_AREG && mode < CT_AREG + 8) {
+               if (regs->regs[mode - CT_AREG + 8] == val)
+                       return dst;
+               regs->regs[mode - CT_AREG + 8] = val;
+       } else if (size == CT_SIZE_FPU && mode >= CT_DREG && mode < CT_DREG + 7) {
+               fpdata *fpd = &regs->fp[mode - CT_DREG];
+               uae_u64 v = ((uae_u64)valp[1] << 32) | valp[2];
+               if (fpd->fpx.high == val && fpd->fpx.low == v)
+                       return dst;
+               fpd->fpx.high = val;
+               fpd->fpx.low = v;
+       } else if (mode == CT_SR) {
+               if (size == CT_SIZE_BYTE) {
+                       if ((regs->sr & 0xff) == (val & 0xff))
+                               return dst;
+                       regs->sr &= 0xff00;
+                       regs->sr |= val & 0xff;
+               } else {
+                       if (regs->sr == val)
+                               return dst;
+                       regs->sr = val;
+               }
+       } else if (mode == CT_FPSR) {
+               if (regs->fpsr == val)
+                       return dst;
+               regs->fpsr = val;
+       } else if (mode == CT_FPCR) {
+               if (regs->fpcr == val)
+                       return dst;
+               regs->fpcr = val;
+       } else if (mode == CT_FPIAR) {
+               if (regs->fpiar == val)
+                       return dst;
+               regs->fpiar = val;
+       }
+       if (dst) {
+               *dst++ = CT_OVERRIDE_REG;
+               *dst++ = type;
+               if (size == CT_SIZE_BYTE) {
+                       *dst = (uae_u8)val;
+                       dst += 1;
+               } else if (size == CT_SIZE_WORD) {
+                       pw(dst, (uae_u16)val);
+                       dst += 2;
+               } else if (size == CT_SIZE_LONG) {
+                       pl(dst, val);
+                       dst += 4;
+               } else if (size == CT_SIZE_FPU) {
+                       pl(dst, val);
+                       dst += 4;
+                       pl(dst, valp[1]);
+                       dst += 4;
+                       pl(dst, valp[2]);
+                       dst += 4;
+               }
+       }
+       return dst;
+}
+
 static uae_u8 *store_rel(uae_u8 *dst, uae_u8 mode, uae_u32 s, uae_u32 d, int ordered)
 {
        int diff = (uae_s32)d - (uae_s32)s;
@@ -1764,19 +1896,93 @@ static uae_u8 *store_rel(uae_u8 *dst, uae_u8 mode, uae_u32 s, uae_u32 d, int ord
        return dst;
 }
 
-static uae_u8 *store_fpureg(uae_u8 *dst, uae_u8 mode, floatx80 d)
-{
+static uae_u8 *store_fpureg(uae_u8 *dst, uae_u8 mode, floatx80 *s, floatx80 d, int forced)
+{
+       if (forced || s == NULL) {
+               *dst++ = mode | CT_SIZE_FPU;
+               *dst++ = 0xff;
+               *dst++ = (d.high >> 8) & 0xff;
+               *dst++ = (d.high >> 0) & 0xff;
+               *dst++ = (d.low >> 56) & 0xff;
+               *dst++ = (d.low >> 48) & 0xff;
+               *dst++ = (d.low >> 40) & 0xff;
+               *dst++ = (d.low >> 32) & 0xff;
+               *dst++ = (d.low >> 24) & 0xff;
+               *dst++ = (d.low >> 16) & 0xff;
+               *dst++ = (d.low >> 8) & 0xff;
+               *dst++ = (d.low >> 0) & 0xff;
+               return dst;
+       }
+       if (s->high == d.high && s->low == d.low) {
+               return dst;
+       }
+       uae_u8 fs[10], fd[10];
+       fs[0] = s->high >> 8;
+       fs[1] = s->high;
+       fs[2] = s->low >> 56;
+       fs[3] = s->low >> 48;
+       fs[4] = s->low >> 40;
+       fs[5] = s->low >> 32;
+       fs[6] = s->low >> 24;
+       fs[7] = s->low >> 16;
+       fs[8] = s->low >> 8;
+       fs[9] = s->low >> 0;
+       fd[0] = d.high >> 8;
+       fd[1] = d.high;
+       fd[2] = d.low >> 56;
+       fd[3] = d.low >> 48;
+       fd[4] = d.low >> 40;
+       fd[5] = d.low >> 32;
+       fd[6] = d.low >> 24;
+       fd[7] = d.low >> 16;
+       fd[8] = d.low >> 8;
+       fd[9] = d.low >> 0;
        *dst++ = mode | CT_SIZE_FPU;
-       *dst++ = (d.high >> 8) & 0xff;
-       *dst++ = (d.high >> 0) & 0xff;
-       *dst++ = (d.low >> 56) & 0xff;
-       *dst++ = (d.low >> 48) & 0xff;
-       *dst++ = (d.low >> 40) & 0xff;
-       *dst++ = (d.low >> 32) & 0xff;
-       *dst++ = (d.low >> 24) & 0xff;
-       *dst++ = (d.low >> 16) & 0xff;
-       *dst++ = (d.low >>  8) & 0xff;
-       *dst++ = (d.low >>  0) & 0xff;
+       if (fs[4] != fd[4] || fs[5] != fd[5]) {
+               *dst++ = 0xff;
+               *dst++ = (d.high >> 8) & 0xff;
+               *dst++ = (d.high >> 0) & 0xff;
+               *dst++ = (d.low >> 56) & 0xff;
+               *dst++ = (d.low >> 48) & 0xff;
+               *dst++ = (d.low >> 40) & 0xff;
+               *dst++ = (d.low >> 32) & 0xff;
+               *dst++ = (d.low >> 24) & 0xff;
+               *dst++ = (d.low >> 16) & 0xff;
+               *dst++ = (d.low >> 8) & 0xff;
+               *dst++ = (d.low >> 0) & 0xff;
+               return dst;
+       }
+       uae_u8 *flagp = dst;
+       *flagp = 0;
+       dst++;
+       if ((fs[0] != fd[0] || fs[1] != fd[1] || fs[2] != fd[2] || fs[3] != fd[3]) && fs[4] == fd[4]) {
+               uae_u8 cnt = 4;
+               for (int i = 3; i >= 0; i--) {
+                       if (fs[i] != fd[i])
+                               break;
+                       cnt--;
+               }
+               if (cnt > 0) {
+                       *flagp |= cnt << 4;
+                       for (int i = 0; i < cnt; i++) {
+                               *dst++ = fd[i];
+                       }
+               }
+       }
+       if ((fs[9] != fd[9] || fs[8] != fd[8] || fs[7] != fd[7] || fs[6] != fd[6]) && fs[5] == fd[5]) {
+               uae_u8 cnt = 4;
+               for (int i = 6; i <= 9; i++) {
+                       if (fs[i] != fd[i])
+                               break;
+                       cnt--;
+               }
+               if (cnt > 0) {
+                       *flagp |= cnt;
+                       for (int i = 0; i < cnt; i++) {
+                               *dst++ = fd[9 - i];
+                       }
+               }
+       }
        return dst;
 }
 
@@ -1903,22 +2109,6 @@ static uae_u8 *store_mem_writes(uae_u8 *dst, int storealways)
        return dst;
 }
 
-static void pl(uae_u8 *p, uae_u32 v)
-{
-       p[0] = v >> 24;
-       p[1] = v >> 16;
-       p[2] = v >> 8;
-       p[3] = v >> 0;
-}
-static uae_u32 gl(uae_u8 *p)
-{
-       return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
-}
-static uae_u32 gw(uae_u8 *p)
-{
-       return (p[0] << 8) | (p[1] << 0);
-}
-
 static bool load_file(const TCHAR *path, const TCHAR *file, uae_u8 *p, int size, int offset)
 {
        TCHAR fname[1000];
@@ -2238,14 +2428,14 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str
        case Aind:
        case Aipi:
                *regused = reg + 8;
-               *eap = cur_registers[reg + 8];
+               *eap = cur_regs.regs[reg + 8];
                break;
        case Apdi:
                *regused = reg + 8;
                if (fpuopsize < 0) {
-                       *eap = cur_registers[reg + 8] - (1 << dp->size);
+                       *eap = cur_regs.regs[reg + 8] - (1 << dp->size);
                } else {
-                       *eap = cur_registers[reg + 8] - bytesizes[fpuopsize];
+                       *eap = cur_regs.regs[reg + 8] - bytesizes[fpuopsize];
                }
                break;
        case Ad16:
@@ -2255,7 +2445,7 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str
                int maxcnt = 1000;
                for (;;) {
                        v = rand16();
-                       addr = cur_registers[reg + 8] + (uae_s16)v;
+                       addr = cur_regs.regs[reg + 8] + (uae_s16)v;
                        *regused = reg + 8;
                        if (fpuopsize >= 0) {
                                if (check_valid_addr(addr, bytesizes[fpuopsize], 2))
@@ -2326,9 +2516,9 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str
                                v = rand16();
                                if (currprefs.cpu_model >= 68020)
                                        v &= ~0x100;
-                               addr = mode == PC8r ? pc + 2 - 2 : cur_registers[reg + 8];
+                               addr = mode == PC8r ? pc + 2 - 2 : cur_regs.regs[reg + 8];
                                *regused = v >> 12;
-                               add = cur_registers[v >> 12];
+                               add = cur_regs.regs[v >> 12];
                                if (currprefs.cpu_model >= 68020) {
                                        add <<= (v >> 9) & 3; // SCALE
                                }
@@ -2710,7 +2900,7 @@ static int create_ea_exact(uae_u16 *opcodep, uaecptr pc, int mode, int reg, stru
        case Aind:
        case Aipi:
        {
-               if (cur_registers[reg + 8] == target) {
+               if (cur_regs.regs[reg + 8] == target) {
                        *eap = target;
                        *regused = reg + 8;
                        return  0;
@@ -2719,7 +2909,7 @@ static int create_ea_exact(uae_u16 *opcodep, uaecptr pc, int mode, int reg, stru
        }
        case Apdi:
        {
-               if (cur_registers[reg + 8] == target + (1 << dp->size)) {
+               if (cur_regs.regs[reg + 8] == target + (1 << dp->size)) {
                        *eap = target;
                        *regused = reg + 8;
                        return  0;
@@ -2728,7 +2918,7 @@ static int create_ea_exact(uae_u16 *opcodep, uaecptr pc, int mode, int reg, stru
        }
        case Ad16:
        {
-               uae_u32 v = cur_registers[reg + 8];
+               uae_u32 v = cur_regs.regs[reg + 8];
                if (target <= v + 0x7ffe && (target >= v - 0x8000 || v < 0x8000)) {
                        put_word_test(pc, target - v);
                        *eap = target;
@@ -2750,11 +2940,11 @@ static int create_ea_exact(uae_u16 *opcodep, uaecptr pc, int mode, int reg, stru
        case Ad8r:
        {
                for (int r = 0; r < 16; r++) {
-                       uae_u32 aval = cur_registers[reg + 8];
+                       uae_u32 aval = cur_regs.regs[reg + 8];
                        int rn = ((ea_exact_cnt >> 1) + r) & 15;
                        for (int i = 0; i < 2; i++) {
                                if ((ea_exact_cnt & 1) == 0 || i == 1) {
-                                       uae_s32 val32 = cur_registers[rn];
+                                       uae_s32 val32 = cur_regs.regs[rn];
                                        uae_u32 addr = aval + val32;
                                        if (target <= addr + 0x7f && target >= addr - 0x80) {
                                                put_word_test(pc, (rn << 12) | 0x0800 | ((target - addr) & 0xff));
@@ -2763,7 +2953,7 @@ static int create_ea_exact(uae_u16 *opcodep, uaecptr pc, int mode, int reg, stru
                                                return 2;
                                        }
                                } else {
-                                       uae_s16 val16 = (uae_s16)cur_registers[rn];
+                                       uae_s16 val16 = (uae_s16)cur_regs.regs[rn];
                                        uae_u32 addr = aval + val16;
                                        if (target <= addr + 0x7f && target >= addr - 0x80) {
                                                put_word_test(pc, (rn << 12) | 0x0000 | ((target - addr) & 0xff));
@@ -2783,7 +2973,7 @@ static int create_ea_exact(uae_u16 *opcodep, uaecptr pc, int mode, int reg, stru
                        int rn = ((ea_exact_cnt >> 1) + r) & 15;
                        for (int i = 0; i < 2; i++) {
                                if ((ea_exact_cnt & 1) == 0 || i == 1) {
-                                       uae_s32 val32 = cur_registers[rn];
+                                       uae_s32 val32 = cur_regs.regs[rn];
                                        uae_u32 addr = aval + val32;
                                        if (target <= addr + 0x7f && target >= addr - 0x80) {
                                                put_word_test(pc, (rn << 12) | 0x0800 | ((target - addr) & 0xff));
@@ -2792,7 +2982,7 @@ static int create_ea_exact(uae_u16 *opcodep, uaecptr pc, int mode, int reg, stru
                                                return 2;
                                        }
                                } else {
-                                       uae_s16 val16 = (uae_s16)cur_registers[rn];
+                                       uae_s16 val16 = (uae_s16)cur_regs.regs[rn];
                                        uae_u32 addr = aval + val16;
                                        if (target <= addr + 0x7f && target >= addr - 0x80) {
                                                put_word_test(pc, (rn << 12) | 0x0000 | ((target - addr) & 0xff));
@@ -3361,8 +3551,8 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp)
        uae_u16 opc = regs.ir;
        uae_u16 opw1 = (opcode_memory[2] << 8) | (opcode_memory[3] << 0);
        uae_u16 opw2 = (opcode_memory[4] << 8) | (opcode_memory[5] << 0);
-       if (opc == 0xf200
-               && opw1 == 0x6c12
+       if (opc == 0xf202
+               && opw1 == 0x5225
                //&& opw2 == 0x4afc
                )
                printf("");
@@ -3656,6 +3846,8 @@ static uae_u8 *save_exception(uae_u8 *p, struct instr *dp)
                                }
                                // access address
                                p = store_rel(p, 0, opcode_memory_start, gl(sf + 2), 1);
+                               // program counter
+                               p = store_rel(p, 0, opcode_memory_start, gl(sf + 10), 1);
                        }
                } else if (cpu_lvl > 0) {
                        uae_u8 ccrmask = 0;
@@ -3966,15 +4158,15 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi
        }
 
        for (int i = 0; i < MAX_REGISTERS; i++) {
-               cur_registers[i] = registers[i];
+               cur_regs.regs[i] = registers[i];
        }
-       floatx80 cur_fpuregisters[8];
        for (int i = 0; i < 8; i++) {
-               cur_fpuregisters[i] = fpuregisters[i];
+               cur_regs.fp[i].fpx = fpuregisters[i];
        }
+       cur_regs.fpiar = 0xffffffff;
 
        if (target_address != 0xffffffff) {
-               generate_target_registers(target_address, cur_registers);
+               generate_target_registers(target_address, cur_regs.regs);
        }
 
        dst = storage_buffer;
@@ -4017,23 +4209,28 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi
                if (quick)
                        break;
 
+               // overrides
+               for (int i = 0; i < regdatacnt; i++) {
+                       struct regdata *rd = &regdatas[i];
+                       uae_u8 v = rd->type & CT_DATA_MASK;
+                       modify_reg(NULL, &cur_regs, rd->type, rd->data);
+               }
+
                if (feature_loop_mode) {
-                       regs.regs[feature_loop_mode_register] &= 0xffff0000;
-                       regs.regs[feature_loop_mode_register] |= feature_loop_mode - 1;
-                       cur_registers[feature_loop_mode_register] = regs.regs[feature_loop_mode_register];
+                       cur_regs.regs[feature_loop_mode_register] &= 0xffff0000;
+                       cur_regs.regs[feature_loop_mode_register] |= feature_loop_mode - 1;
                }
 
                for (int i = 0; i < MAX_REGISTERS; i++) {
-                       dst = store_reg(dst, CT_DREG + i, 0, cur_registers[i], -1);
-                       regs.regs[i] = cur_registers[i];
+                       dst = store_reg(dst, CT_DREG + i, 0, cur_regs.regs[i], -1);
                }
                for (int i = 0; i < 8; i++) {
                        if (fpumode) {
-                               dst = store_fpureg(dst, CT_FPREG + i, cur_fpuregisters[i]);
+                               dst = store_fpureg(dst, CT_FPREG + i, NULL, cur_regs.fp[i].fpx, 1);
                        }
-                       regs.fp[i].fpx = cur_fpuregisters[i];
+                       dst = store_reg(dst, CT_FPIAR, 0, cur_regs.fpiar, -1);
                }
-               regs.sr = feature_min_interrupt_mask << 8;
+               cur_regs.sr = feature_min_interrupt_mask << 8;
 
                uae_u32 srcaddr_old = 0xffffffff;
                uae_u32 dstaddr_old = 0xffffffff;
@@ -4173,10 +4370,11 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi
                                        target_opcode_address = target_opcode_address_bak;
 
                                        if (target_usp_address != 0xffffffff) {
-                                               cur_registers[15] = target_usp_address;
-                                               regs.regs[15] = target_usp_address;
+                                               cur_regs.regs[15] = target_usp_address;
                                        }
 
+                                       memcpy(&regs, &cur_regs, sizeof(cur_regs));
+
                                        regs.usp = regs.regs[15];
                                        regs.isp = super_stack_memory - 0x80;
 
@@ -4410,12 +4608,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi
                                        TCHAR out[256];
                                        memset(out, 0, sizeof(out));
                                        // disassemble and output generated instruction
-                                       for (int i = 0; i < MAX_REGISTERS; i++) {
-                                               regs.regs[i] = cur_registers[i];
-                                       }
-                                       for (int i = 0; i < 8; i++) {
-                                               regs.fp[i].fpx = cur_fpuregisters[i];
-                                       }
+                                       memcpy(&regs, &cur_regs, sizeof(cur_regs));
 
                                        uaecptr nextpc;
                                        srcaddr = 0xffffffff;
@@ -4491,7 +4684,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi
                                                        srcaddr = get_long_test(regs.regs[15] + stackoffset);
                                                }
                                                // branch target is not accessible? skip.
-                                               if ((((srcaddr & addressing_mask) >= cur_registers[15] - 16 && (srcaddr & addressing_mask) <= cur_registers[15] + 16) && dp->mnemo != i_RTE) || ((srcaddr & 1) && !feature_exception3_instruction && feature_usp < 2)) {
+                                               if ((((srcaddr & addressing_mask) >= cur_regs.regs[15] - 16 && (srcaddr & addressing_mask) <= cur_regs.regs[15] + 16) && dp->mnemo != i_RTE) || ((srcaddr & 1) && !feature_exception3_instruction && feature_usp < 2)) {
                                                        // lets not jump directly to stack..
                                                        if (verbose) {
                                                                if (srcaddr & 1)
@@ -4588,14 +4781,8 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi
                                        int ok = 0;
                                        int cnt_stopped = 0;
 
-                                       uae_u32 last_sr = 0;
-                                       uae_u32 last_pc = 0;
                                        uae_u32 last_cpu_cycles = 0;
-                                       uae_u32 last_registers[MAX_REGISTERS];
-                                       floatx80 last_fpuregisters[8];
-                                       uae_u32 last_fpiar = 0;
-                                       uae_u32 last_fpsr = 0;
-                                       uae_u32 last_fpcr = 0;
+                                       regstruct last_regs;
 
                                        int ccr_done = 0;
                                        int prev_s_cnt = 0;
@@ -4614,7 +4801,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi
                                                int maxflag;
                                                int flagmode = 0;
                                                if (fpumode) {
-                                                       if (fpuopcode == FPUOPP_ILLEGAL) {
+                                                       if (fpuopcode == FPUOPP_ILLEGAL || feature_flag_mode > 1) {
                                                                // Illegal FPU instruction: all on/all off only (*2)
                                                                maxflag = 2;
                                                        } else if (dp->mnemo == i_FDBcc || dp->mnemo == i_FScc || dp->mnemo == i_FTRAPcc || dp->mnemo == i_FBcc) {
@@ -4668,6 +4855,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi
                                                        // swap end opcode illegal/nop
                                                        noaccesshistory++;
                                                        endopcode = (endopcode >> 16) | (endopcode << 16);
+                                                       int extraopcodeendsize = ((endopcode >> 16) == 0x4e71) ? 2 : 0;
                                                        int endopcodesize = 0;
                                                        if (!is_nowrite_address(pc - 4, 4)) {
                                                                put_long_test(pc - 4, endopcode);
@@ -4715,13 +4903,13 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi
 
                                                        // set up registers
                                                        for (int i = 0; i < MAX_REGISTERS; i++) {
-                                                               regs.regs[i] = cur_registers[i];
+                                                               regs.regs[i] = cur_regs.regs[i];
                                                        }
                                                        if (fpumode) {
                                                                for (int i = 0; i < 8; i++) {
-                                                                       regs.fp[i].fpx = cur_fpuregisters[i];
+                                                                       regs.fp[i].fpx = cur_regs.fp[i].fpx;
                                                                }
-                                                               regs.fpiar = regs.pc;
+                                                               regs.fpiar = cur_regs.fpiar;
                                                                uae_u32 fpsr = 0, fpcr = 0;
                                                                if (maxflag == 16) {
                                                                        if (flagmode) {
@@ -4734,12 +4922,30 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi
                                                                        fpsr = ((ccr & 1) ? 15 : 0) << 24;
                                                                        fpcr = ((ccr & 1) ? 15 : 0) << 4;
                                                                }
+                                                               // override special register values
+                                                               for (int i = 0; i < regdatacnt; i++) {
+                                                                       struct regdata *rd = &regdatas[i];
+                                                                       uae_u8 v = rd->type & CT_DATA_MASK;
+                                                                       if (v == CT_FPSR || v == CT_FPCR || v == CT_FPIAR) {
+                                                                               if (v == CT_FPSR) {
+                                                                                       regs.fpsr = fpsr;
+                                                                               } else if (v == CT_FPCR) {
+                                                                                       regs.fpcr = fpcr;
+                                                                               }
+                                                                               dst = modify_reg(dst, &regs, rd->type, rd->data);
+                                                                               if (v == CT_FPSR) {
+                                                                                       fpsr = regs.fpsr;
+                                                                               } else if (v == CT_FPCR) {
+                                                                                       fpcr = regs.fpcr;
+                                                                               }
+                                                                       }
+                                                               }
                                                                // condition codes
                                                                fpp_set_fpsr(fpsr);
                                                                // precision and rounding
                                                                fpp_set_fpcr(fpcr);
-
                                                        }
+
                                                        // all CCR combinations or only all ones/all zeros?
                                                        if (maxflag >= 32) {
                                                                regs.sr = (ccr & 0xff) | sr_mask;
@@ -4747,26 +4953,26 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi
                                                                regs.sr = ((ccr & 1) ? 31 : 0) | sr_mask;
                                                        }
                                                        regs.sr |= feature_min_interrupt_mask << 8;
+
+                                                       // override special register values
+                                                       for (int i = 0; i < regdatacnt; i++) {
+                                                               struct regdata *rd = &regdatas[i];
+                                                               uae_u8 v = rd->type & CT_DATA_MASK;
+                                                               if (v == CT_SR) {
+                                                                       dst = modify_reg(dst, &regs, rd->type, rd->data);
+                                                               }
+                                                       }
+
                                                        regs.usp = regs.regs[15];
                                                        regs.isp = super_stack_memory - 0x80;
                                                        // copy user stack to super stack, for RTE etc support
                                                        memcpy(test_memory + (regs.isp - test_memory_start), test_memory + (regs.usp - test_memory_start), 0x20);
                                                        regs.msp = super_stack_memory;
-
+               
                                                        // data size optimization, only store data
                                                        // if it is different than in previous round
                                                        if (!ccr && !extraccr) {
-                                                               last_sr = regs.sr;
-                                                               last_pc = regs.pc;
-                                                               for (int i = 0; i < 16; i++) {
-                                                                       last_registers[i] = regs.regs[i];
-                                                               }
-                                                               for (int i = 0; i < 8; i++) {
-                                                                       last_fpuregisters[i] = regs.fp[i].fpx;
-                                                               }
-                                                               last_fpiar = regs.fpiar;
-                                                               last_fpcr = regs.fpcr;
-                                                               last_fpsr = regs.fpsr;
+                                                               memcpy(&last_regs, &regs, sizeof(regstruct));
                                                        }
 
                                                        if (regs.sr & 0x2000)
@@ -4781,8 +4987,13 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi
                                                        if (regs.s)
                                                                s_cnt++;
 
-                                                       // validate PC
-                                                       uae_u8 *pcaddr = get_addr(regs.pc, 2, 0);
+                                                       uae_u8 *pcaddr;
+                                                       // validate PC (PC in exception space if exception is fine, don't set out of space)
+                                                       if (test_exception && regs.pc < 0x100 && low_memory) {
+                                                               pcaddr = low_memory + regs.pc;
+                                                       } else {
+                                                               pcaddr = get_addr(regs.pc, 2, 0);
+                                                       }
 
                                                        // examine results
 
@@ -4943,47 +5154,47 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi
                                                                }
                                                                // save modified registers
                                                                for (int i = 0; i < MAX_REGISTERS; i++) {
-                                                                       uae_u32 s = last_registers[i];
+                                                                       uae_u32 s = last_regs.regs[i];
                                                                        uae_u32 d = regs.regs[i];
                                                                        if (s != d) {
                                                                                if (storeregs) {
                                                                                        dst = store_reg(dst, CT_DREG + i, s, d, -1);
                                                                                }
-                                                                               last_registers[i] = d;
+                                                                               last_regs.regs[i] = d;
                                                                        }
                                                                }
                                                                // SR/CCR
                                                                uae_u32 ccrignoremask = get_ccr_ignore(dp, extraword) << 16;
-                                                               if ((regs.sr | ccrignoremask) != last_sr) {
-                                                                       dst = store_reg(dst, CT_SR, last_sr, regs.sr | ccrignoremask, -1);
-                                                                       last_sr = regs.sr | ccrignoremask;
+                                                               if ((regs.sr | ccrignoremask) != last_regs.sr) {
+                                                                       dst = store_reg(dst, CT_SR, last_regs.sr, regs.sr | ccrignoremask, -1);
+                                                                       last_regs.sr = regs.sr | ccrignoremask;
                                                                }
                                                                // PC
-                                                               if (regs.pc != last_pc) {
-                                                                       dst = store_rel(dst, CT_PC, last_pc, regs.pc, 0);
-                                                                       last_pc = regs.pc;
+                                                               if (regs.pc - extraopcodeendsize != last_regs.pc) {
+                                                                       dst = store_rel(dst, CT_PC, last_regs.pc, regs.pc - extraopcodeendsize, 0);
+                                                                       last_regs.pc = regs.pc - extraopcodeendsize;
                                                                }
                                                                // FPU stuff
                                                                if (currprefs.fpu_model) {
                                                                        for (int i = 0; i < 8; i++) {
-                                                                               floatx80 s = last_fpuregisters[i];
+                                                                               floatx80 s = last_regs.fp[i].fpx;
                                                                                floatx80 d = regs.fp[i].fpx;
                                                                                if (s.high != d.high || s.low != d.low) {
-                                                                                       dst = store_fpureg(dst, CT_FPREG + i, d);
-                                                                                       last_fpuregisters[i] = d;
+                                                                                       dst = store_fpureg(dst, CT_FPREG + i, &s, d, 0);
+                                                                                       last_regs.fp[i].fpx = d;
                                                                                }
                                                                        }
-                                                                       if (regs.fpiar != last_fpiar) {
-                                                                               dst = store_reg(dst, CT_FPIAR, last_fpiar, regs.fpiar, -1);
-                                                                               last_fpiar = regs.fpiar;
+                                                                       if (regs.fpiar != last_regs.fpiar) {
+                                                                               dst = store_reg(dst, CT_FPIAR, last_regs.fpiar, regs.fpiar, -1);
+                                                                               last_regs.fpiar = regs.fpiar;
                                                                        }
-                                                                       if (regs.fpsr != last_fpsr) {
-                                                                               dst = store_reg(dst, CT_FPSR, last_fpsr, regs.fpsr, -1);
-                                                                               last_fpsr = regs.fpsr;
+                                                                       if (regs.fpsr != last_regs.fpsr) {
+                                                                               dst = store_reg(dst, CT_FPSR, last_regs.fpsr, regs.fpsr, -1);
+                                                                               last_regs.fpsr = regs.fpsr;
                                                                        }
-                                                                       if (regs.fpcr != last_fpcr) {
-                                                                               dst = store_reg(dst, CT_FPCR, last_fpcr, regs.fpcr, -1);
-                                                                               last_fpcr = regs.fpcr;
+                                                                       if (regs.fpcr != last_regs.fpcr) {
+                                                                               dst = store_reg(dst, CT_FPCR, last_regs.fpcr, regs.fpcr, -1);
+                                                                               last_regs.fpcr = regs.fpcr;
                                                                        }
                                                                }
                                                                if (cpu_lvl <= 1 && (last_cpu_cycles != cpu_cycles || first_cycles)) {
@@ -5044,25 +5255,27 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi
                                                data_saved = 1;
                                                // if test used data or fpu register as a source or destination: modify it
                                                if (srcregused >= 0) {
-                                                       uae_u32 prev = cur_registers[srcregused];
-                                                       if (regchange(srcregused, cur_registers)) {
-                                                               dst = store_reg(dst, CT_DREG + srcregused, prev, cur_registers[srcregused], -1);
+                                                       uae_u32 prev = cur_regs.regs[srcregused];
+                                                       if (regchange(srcregused, cur_regs.regs)) {
+                                                               dst = store_reg(dst, CT_DREG + srcregused, prev, cur_regs.regs[srcregused], -1);
                                                        }
                                                }
                                                if (dstregused >= 0 && srcregused != dstregused) {
-                                                       uae_u32 prev = cur_registers[dstregused];
-                                                       if (regchange(dstregused, cur_registers)) {
-                                                               dst = store_reg(dst, CT_DREG + dstregused, prev, cur_registers[dstregused], -1);
+                                                       uae_u32 prev = cur_regs.regs[dstregused];
+                                                       if (regchange(dstregused, cur_regs.regs)) {
+                                                               dst = store_reg(dst, CT_DREG + dstregused, prev, cur_regs.regs[dstregused], -1);
                                                        }
                                                }
                                                if (srcfpuregused >= 0) {
-                                                       if (fpuregchange(srcfpuregused, cur_fpuregisters)) {
-                                                               dst = store_fpureg(dst, CT_FPREG + srcfpuregused, cur_fpuregisters[srcfpuregused]);
+                                                       floatx80 prev = cur_regs.fp[srcfpuregused].fpx;
+                                                       if (fpuregchange(srcfpuregused, cur_regs.fp)) {
+                                                               dst = store_fpureg(dst, CT_FPREG + srcfpuregused, &prev, cur_regs.fp[srcfpuregused].fpx, 0);
                                                        }
                                                }
                                                if (dstfpuregused >= 0 && srcfpuregused != dstfpuregused) {
-                                                       if (fpuregchange(dstfpuregused, cur_fpuregisters)) {
-                                                               dst = store_fpureg(dst, CT_FPREG + dstfpuregused, cur_fpuregisters[dstfpuregused]);
+                                                       floatx80 prev = cur_regs.fp[dstfpuregused].fpx;
+                                                       if (fpuregchange(dstfpuregused, cur_regs.fp)) {
+                                                               dst = store_fpureg(dst, CT_FPREG + dstfpuregused, &prev, cur_regs.fp[dstfpuregused].fpx, 0);
                                                        }
                                                }
                                        }
@@ -5088,13 +5301,13 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi
                                                }
                                                dst = storage_buffer;
                                                for (int i = 0; i < MAX_REGISTERS; i++) {
-                                                       dst = store_reg(dst, CT_DREG + i, 0, cur_registers[i], -1);
-                                                       regs.regs[i] = cur_registers[i];
+                                                       dst = store_reg(dst, CT_DREG + i, 0, cur_regs.regs[i], -1);
+                                                       regs.regs[i] = cur_regs.regs[i];
                                                }
                                                if (currprefs.fpu_model) {
                                                        for (int i = 0; i < 8; i++) {
-                                                               dst = store_fpureg(dst, CT_FPREG + i, cur_fpuregisters[i]);
-                                                               regs.fp[i].fpx = cur_fpuregisters[i];
+                                                               dst = store_fpureg(dst, CT_FPREG + i, NULL, cur_regs.fp[i].fpx, 0);
+                                                               regs.fp[i].fpx = cur_regs.fp[i].fpx;
                                                        }
                                                }
                                        }
@@ -5152,7 +5365,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi
                                target_address = feature_target_ea[target_ea_dst_cnt][1];
                                target_ea[1] = target_address;
                        }
-                       generate_target_registers(target_address, cur_registers);
+                       generate_target_registers(target_address, cur_regs.regs);
                } else {
                        nextround = true;
                }
@@ -5186,17 +5399,10 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi
                        }
                }
 
-               cur_registers[0] &= 0xffff;
-               cur_registers[8] &= 0xffff;
-               cur_registers[8 + 6]--;
-               cur_registers[15] -= 2;
-
-               if (fpumode) {
-                       for (int i = 0; i < 8; i++) {
-                               uae_u32 v = rand32();
-                               cur_fpuregisters[i] = int32_to_floatx80(v);
-                       }
-               }
+               cur_regs.regs[0] &= 0xffff;
+               cur_regs.regs[8] &= 0xffff;
+               cur_regs.regs[8 + 6]--;
+               cur_regs.regs[15] -= 2;
        }
 
        markfile(dir);
@@ -5444,6 +5650,44 @@ static bool ini_getstringx(struct ini_data *ini, const TCHAR *sections, const TC
        return ret;
 }
 
+static const struct regtype regtypes[] =
+{
+       { _T("D0"), CT_SIZE_LONG | (CT_DREG + 0) },
+       { _T("D1"), CT_SIZE_LONG | (CT_DREG + 1) },
+       { _T("D2"), CT_SIZE_LONG | (CT_DREG + 2) },
+       { _T("D3"), CT_SIZE_LONG | (CT_DREG + 3) },
+       { _T("D4"), CT_SIZE_LONG | (CT_DREG + 4) },
+       { _T("D5"), CT_SIZE_LONG | (CT_DREG + 5) },
+       { _T("D6"), CT_SIZE_LONG | (CT_DREG + 6) },
+       { _T("D7"), CT_SIZE_LONG | (CT_DREG + 7) },
+
+       { _T("A0"), CT_SIZE_LONG | (CT_AREG + 0) },
+       { _T("A1"), CT_SIZE_LONG | (CT_AREG + 1) },
+       { _T("A2"), CT_SIZE_LONG | (CT_AREG + 2) },
+       { _T("A3"), CT_SIZE_LONG | (CT_AREG + 3) },
+       { _T("A4"), CT_SIZE_LONG | (CT_AREG + 4) },
+       { _T("A5"), CT_SIZE_LONG | (CT_AREG + 5) },
+       { _T("A6"), CT_SIZE_LONG | (CT_AREG + 6) },
+       { _T("A7"), CT_SIZE_LONG | (CT_AREG + 7) },
+
+       { _T("FP0"), CT_SIZE_FPU | (CT_FPREG + 0) },
+       { _T("FP1"), CT_SIZE_FPU | (CT_FPREG + 1) },
+       { _T("FP2"), CT_SIZE_FPU | (CT_FPREG + 2) },
+       { _T("FP3"), CT_SIZE_FPU | (CT_FPREG + 3) },
+       { _T("FP4"), CT_SIZE_FPU | (CT_FPREG + 4) },
+       { _T("FP5"), CT_SIZE_FPU | (CT_FPREG + 5) },
+       { _T("FP6"), CT_SIZE_FPU | (CT_FPREG + 6) },
+       { _T("FP7"), CT_SIZE_FPU | (CT_FPREG + 7) },
+
+       { _T("CCR"), CT_SR | CT_SIZE_BYTE, },
+       { _T("SR"), CT_SR | CT_SIZE_WORD, },
+       { _T("FPCR"), CT_FPCR | CT_SIZE_LONG, },
+       { _T("FPSR"), CT_FPSR | CT_SIZE_LONG, },
+       { _T("FPIAR"), CT_FPIAR | CT_SIZE_LONG, },
+
+       { NULL }
+};
+
 static int cputoindex(int cpu)
 {
        if (cpu == 68000) {
@@ -5611,6 +5855,42 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna
                safe_memory_mode = 0;
        }
 
+       if (ini_getstringx(ini, sections, _T("feature_forced_register"), &vs)) {
+               bool first = true;
+               TCHAR *p = vs;
+               while (p && *p) {
+                       TCHAR *pp = _tcschr(p, ',');
+                       if (pp) {
+                               *pp++ = 0;
+                       }
+                       TCHAR *pp2 = _tcschr(p, ':');
+                       if (pp2) {
+                               *pp2++ = 0;
+                               for (int i = 0; regtypes[i].name; i++) {
+                                       if (!_tcsicmp(regtypes[i].name, p)) {
+                                               if (regdatacnt >= MAX_REGDATAS) {
+                                                       wprintf(_T("Out of regdata!\n"));
+                                                       abort();
+                                               }
+                                               struct regdata *rd = &regdatas[regdatacnt];
+                                               rd->type = regtypes[i].type;
+                                               if (pp2[0] == '0' && (pp2[1] == 'x' || pp2[1] == 'X')) {
+                                                       TCHAR *endptr;
+                                                       rd->data[0] = _tcstol(pp2, &endptr, 16);
+                                               } else {
+                                                       rd->data[0] = _tstol(pp2);
+                                               }
+                                               regdatacnt++;
+                                               break;
+                                       }
+                               }
+                       }
+                       p = pp;
+               }
+               xfree(vs);
+       }
+
+       
 
        if (ini_getstringx(ini, sections, _T("exceptions"), &vs)) {
                bool first = true;
index a2b8775ce562407bdea89f09f5495c9a25effb1b..102a7cec45313d45564a1c2f31bba65586d5f9f4 100644 (file)
@@ -36,17 +36,17 @@ S_EXPSR = S_SR+4
 S_EXC = S_EXPSR+4
 S_EXC010 = S_EXC+4
 S_EXCFRAME = S_EXC010+4
-S_FPU = S_EXCFRAME+4
-S_FPIAR = S_FPU+8*12
-S_FPCR = S_FPIAR+4
-S_FPSR = S_FPCR+4
-S_FSAVE = S_FPSR+4
-S_TRACECNT = S_FSAVE+216
+S_TRACECNT = S_EXCFRAME+4
 S_TRACESTACK = S_TRACECNT+4
 S_CYCLES = S_TRACESTACK+12
 S_CYCLES2 = S_CYCLES+4
 S_CYCLEST = S_CYCLES2+4
-S_NEXT = S_CYCLEST+4
+S_FPU = S_CYCLEST+4
+S_FPIAR = S_FPU+8*12
+S_FPCR = S_FPIAR+4
+S_FPSR = S_FPCR+4
+S_FSAVE = S_FPSR+4
+S_NEXT = S_FSAVE+216
 
 _callinflate:
        movem.l a4-a6,-(sp)
@@ -681,6 +681,9 @@ _msp_address4:
 
 _error_vector:
        or.w #0x700,sr
+       movem.l d0-d7/a0-a7,0x7f000
+       move.l usp,a0
+       move.l a0,0x7f000+16*4
 waiterr:
        move.w #0x400,ACTIVITYREG
        move.w #0x004,ACTIVITYREG
index 4e7823e9e9848c8c8092caf9b6c5b8a0a8bf6b1a..42767ad2b8cb16666e404e08563d235792f65363 100644 (file)
@@ -1,5 +1,5 @@
 
-#define DATA_VERSION 16
+#define DATA_VERSION 17
 
 #define CT_FPREG 0
 #define CT_DREG 0
@@ -42,3 +42,4 @@
 #define CT_END_SKIP (0x80 | 0x40 | 0x01)
 #define CT_SKIP_REGS (0x80 | 0x40 | 0x02)
 #define CT_EMPTY CT_END_INIT
+#define CT_OVERRIDE_REG (0x80 | 0x40 | 0x10)
index d3bc4aea23d45ebe8c8e6e7480868091a58a5af3..73c6d553e91734ab41cad6c9cdccc7b19429fbd4 100644 (file)
@@ -142,6 +142,11 @@ feature_interrupts=0
 ; Note: instructions that generate privilege violation exception will automatically add extra S=1 round.
 feature_sr_mask=0x0000
 
+; Forced register, always use this value in all tests
+; D0-D7, A0-A6, FP0-FP7, SR, CCR, FPSR, FPCR, FPIAR
+; reg=0x1234 or reg=100
+;feature_forced_register=
+
 ; generate loop test: label: <test instruction> dbf dn,label
 ; value: 0 = disabled, >0 = number of loops
 feature_loop_mode=0
@@ -384,6 +389,18 @@ exceptions=-48,-49,-50,-51,-52,-53,-54
 min_opcode_test_rounds=5000
 mode=fmove,fsmove,fdmove,fint,fintrz,fneg,fsneg,fdneg,fabs,fsabs,fdabs,fdiv,fsdiv,fddiv,fadd,fsadd,fdadd,fmul,fsmul,fdmul,fsgldiv,fsglmul,fsub,fssub,fdsub,fcmp,ftst,fsqrt
 
+; logarithmic, trigonometric and misc
+; no arithmetic exceptions, unsupported instructions or datatypes, denormals or unnormals.
+[test=ComplexFPU]
+enabled=0
+verbose=1
+cpu=68020-68030
+fpu=68882
+exceptions=-48,-49,-50,-51,-52,-53,-54
+mode=fmod,frem,fscale,fgetexp,fgetman
+mode=facos,fasin,fatan,fatanh,fcos,fcosh,fetox,fetoxm1,ftwotox
+mode=flog10,flogn,flognp1,fsin,fsincos,fsinh,ftan,ftanh,ftentox
+
 ; non-arithmetic instructions (FMOVEM also includes FMOVE to/from control register)
 [test=intFPU]
 enabled=0
@@ -399,13 +416,15 @@ enabled=0
 cpu=68020-68060
 fpu=68882
 exceptions=-48,-49,-50,-51,-52,-53,-54
-feature_flags_mode=2
+feature_flags_mode=1
 feature_instruction_size=P
-mode=fall
+feature_forced_register=
+;mode=fall
+mode=fmove,fint,fintrz,fneg,fabs,fdiv,fadd,fmul,fsgldiv,fsglmul,fsub,fcmp,ftst,fsqrt
 
 ; FPU illegal or unimplemented instructions
 [test=IllgFPU]
-enabled=1
+enabled=0
 verbose=1
 cpu=68020-68060
 fpu=68882
index 848dc371634a9a3e86a406a7a2436a0bda6d5c7f..86f6f9ccb009e14e782d23fe43e68bbb9bbf1190 100644 (file)
@@ -45,23 +45,25 @@ struct registers
        uae_u32 expsr;
        uae_u32 exc, exc010;
        uae_u32 excframe;
-       struct fpureg fpuregs[8];
-       uae_u32 fpiar, fpcr, fpsr;
-       uae_u32 fsave[216/4];
        uae_u32 tracecnt;
        uae_u16 tracedata[6];
        uae_u32 cycles, cycles2, cyclest;
 
+       struct fpureg fpuregs[8];
+       uae_u32 fpiar, fpcr, fpsr;
+       uae_u32 fsave[216 / 4];
+
        uae_u32 srcaddr, dstaddr, branchtarget;
        uae_u8 branchtarget_mode;
        uae_u32 endpc;
+
        uae_u16 fpeaset;
 };
 
 static short continue_on_error;
 static struct registers test_regs;
-static struct registers last_registers;
-static struct registers regs;
+static struct registers last_regs;
+static struct registers cur_regs;
 static uae_u8 *opcode_memory;
 static uae_u32 opcode_memory_addr;
 static uae_u8 *low_memory;
@@ -86,6 +88,9 @@ static uae_u8 *absallocated;
 static int cpu_lvl, fpu_model;
 static uae_u16 sr_undefined_mask;
 static int check_undefined_sr;
+static short is_fpu_adjust;
+static short fpu_adjust_man, fpu_adjust_exp, fpu_adjust_zb;
+struct fpureg fpu_adjust;
 static uae_u32 cpustatearraystore[16];
 static uae_u32 cpustatearraynew[] = {
        0x00000005, // SFC
@@ -108,17 +113,21 @@ static int supercnt;
 static uae_u32 startpc, endpc;
 
 static char inst_name[16+1];
-#define DEFAULT_OUTBUFFER_SIZE 20000
+#define PAGE_OUTBUFFER_SIZE 3000
 static int outbuffer_size;
-static char *outbuffer;
-static char *outbuffer2;
+static char *stored_outbuffer;
+static char outbuffer[6000];
+static char outbuffer2[6000];
 static char tmpbuffer[1024];
 static char path[256];
 
 static char *outbp;
 static short infoadded;
 static int errors;
+static int totalerrors;
 static int testcnt;
+static short testcntsub, testcntsubmax;
+static int fpu_approx, fpu_approxcnt;
 static short dooutput = 1;
 static short quit;
 static uae_u8 ccr_mask;
@@ -138,6 +147,7 @@ static short gotcycles;
 static short interrupttest;
 static short randomizetest;
 static uae_u32 cyclecounter_addr;
+static int errorcnt;
 static short uaemode;
 #ifdef AMIGA
 static short interrupt_count;
@@ -746,13 +756,42 @@ static uae_u8 *restore_fpvalue(uae_u8 *p, struct fpureg *fp)
                endinfo();
                exit(0);
        }
-       fp->exp = gw(p);
-       p += 2;
-       fp->m[0] = gl(p);
-       p += 4;
-       fp->m[1] = gl(p);
-       p += 4;
        fp->dummy = 0;
+       uae_u8 size = *p++;
+       if (size == 0x00) {
+               fp->exp = 0;
+               fp->m[0] = fp->m[1] = 0;
+       } else if (size == 0xff) {
+               fp->exp = gw(p);
+               p += 2;
+               fp->m[0] = gl(p);
+               p += 4;
+               fp->m[1] = gl(p);
+               p += 4;
+       } else {
+               uae_u8 f[10];
+               f[0] = fp->exp >> 8;
+               f[1] = fp->exp;
+               f[2] = fp->m[0] >> 24;
+               f[3] = fp->m[0] >> 16;
+               f[4] = fp->m[0] >> 8;
+               f[5] = fp->m[0] >> 0;
+               f[6] = fp->m[1] >> 24;
+               f[7] = fp->m[1] >> 16;
+               f[8] = fp->m[1] >> 8;
+               f[9] = fp->m[1] >> 0;
+               uae_u8 size1 = (size >> 4) & 15;
+               for (uae_u8 i = 0; i < size1; i++) {
+                       f[i] = *p++;
+               }
+               uae_u8 size2 = (size >> 0) & 15;
+               for (uae_u8 i = 0; i < size2; i++) {
+                       f[9 - i] = *p++;
+               }
+               fp->exp = (f[0] << 8) | (f[1] << 0);
+               fp->m[0] = (f[2] << 24) | (f[3] << 16) | (f[4] << 8) | (f[5] << 0);
+               fp->m[1] = (f[6] << 24) | (f[7] << 16) | (f[8] << 8) | (f[9] << 0);
+       }
        return p;
 }
 
@@ -1068,7 +1107,7 @@ static uae_u8 *restore_memory(uae_u8 *p, int storedata)
        return p;
 }
 
-static uae_u8 *restore_data(uae_u8 *p)
+static uae_u8 *restore_data(uae_u8 *p, struct registers *r)
 {
        uae_u8 v = *p;
        if (v & CT_END) {
@@ -1080,43 +1119,43 @@ static uae_u8 *restore_data(uae_u8 *p)
        int mode = v & CT_DATA_MASK;
        if (mode == CT_SRCADDR) {
                int size;
-               p = restore_value(p, &regs.srcaddr, &size);
+               p = restore_value(p, &r->srcaddr, &size);
        } else if (mode == CT_DSTADDR) {
                int size;
-               p = restore_value(p, &regs.dstaddr, &size);
+               p = restore_value(p, &r->dstaddr, &size);
        } else if (mode == CT_ENDPC) {
                int size;
-               p = restore_value(p, &regs.endpc, &size);
+               p = restore_value(p, &r->endpc, &size);
        } else if (mode == CT_PC) {
                int size;
-               p = restore_value(p, &regs.pc, &size);
+               p = restore_value(p, &r->pc, &size);
        } else if (mode == CT_BRANCHTARGET) {
                int size;
-               p = restore_value(p, &regs.branchtarget, &size);
-               regs.branchtarget_mode = *p++;
+               p = restore_value(p, &r->branchtarget, &size);
+               r->branchtarget_mode = *p++;
        } else if (mode < CT_AREG + 8) {
                int size;
                if ((v & CT_SIZE_MASK) == CT_SIZE_FPU) {
-                       p = restore_fpvalue(p, &regs.fpuregs[mode]);
+                       p = restore_fpvalue(p, &r->fpuregs[mode]);
                } else {
-                       p = restore_value(p, &regs.regs[mode], &size);
+                       p = restore_value(p, &r->regs[mode], &size);
                }
        } else if (mode == CT_SR) {
                int size;
-               p = restore_value(p, &regs.sr, &size);
+               p = restore_value(p, &r->sr, &size);
        } else if (mode == CT_CYCLES) {
                int size;
-               p = restore_value(p, &regs.cycles, &size);
+               p = restore_value(p, &r->cycles, &size);
                gotcycles = 1;
        } else if (mode == CT_FPIAR) {
                int size;
-               p = restore_value(p, &regs.fpiar, &size);
+               p = restore_value(p, &r->fpiar, &size);
        } else if (mode == CT_FPCR) {
                int size;
-               p = restore_value(p, &regs.fpcr, &size);
+               p = restore_value(p, &r->fpcr, &size);
        } else if (mode == CT_FPSR) {
                int size;
-               p = restore_value(p, &regs.fpsr, &size);
+               p = restore_value(p, &r->fpsr, &size);
        } else if (mode == CT_MEMWRITE) {
                // if memwrite, store old data
                p = restore_memory(p, 1);
@@ -1131,8 +1170,7 @@ static uae_u8 *restore_data(uae_u8 *p)
        return p;
 }
 
-static uae_u16 test_sr, test_ccrignoremask;
-static uae_u32 test_fpsr, test_fpcr;
+static uae_u16 test_ccrignoremask;
 
 static int addr_diff(uae_u8 *ap, uae_u8 *bp, int size)
 {
@@ -1231,6 +1269,7 @@ static void out_disasm(uae_u8 *mem)
 
 static void addinfo(void)
 {
+       struct registers *r = &cur_regs;
        if (infoadded)
                return;
        infoadded = 1;
@@ -1239,10 +1278,9 @@ static void addinfo(void)
 
        if (disasm) {
                out_disasm(opcode_memory);
-       }
-
-       if (regs.branchtarget != 0xffffffff) {
-               out_disasm((uae_u8*)regs.branchtarget);
+               if (r->branchtarget != 0xffffffff && !(r->branchtarget & 1)) {
+                       out_disasm((uae_u8 *)r->branchtarget);
+               }
        }
 
        uae_u16 *code = (uae_u16*)opcode_memory;
@@ -1250,25 +1288,25 @@ static void addinfo(void)
                addinfo_bytes("P", stackaddr, stackaddr_ptr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
                addinfo_bytes(" ", (uae_u8 *)stackaddr_ptr - SIZE_STORED_ADDRESS_OFFSET, stackaddr_ptr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
        }
-       if (regs.srcaddr != 0xffffffff) {
+       if (r->srcaddr != 0xffffffff) {
                uae_u8 *a = srcaddr;
-               uae_u8 *b = (uae_u8 *)regs.srcaddr - SIZE_STORED_ADDRESS_OFFSET;
-               addinfo_bytes("S", a, regs.srcaddr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
+               uae_u8 *b = (uae_u8 *)r->srcaddr - SIZE_STORED_ADDRESS_OFFSET;
+               addinfo_bytes("S", a, r->srcaddr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
                if (addr_diff(a, b, SIZE_STORED_ADDRESS)) {
-                       addinfo_bytes(" ", b, regs.srcaddr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
+                       addinfo_bytes(" ", b, r->srcaddr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
                }
        }
-       if (regs.dstaddr != 0xffffffff) {
+       if (r->dstaddr != 0xffffffff) {
                uae_u8 *a = dstaddr;
-               uae_u8 *b = (uae_u8*)regs.dstaddr - SIZE_STORED_ADDRESS_OFFSET;
-               addinfo_bytes("D", a, regs.dstaddr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
+               uae_u8 *b = (uae_u8*)r->dstaddr - SIZE_STORED_ADDRESS_OFFSET;
+               addinfo_bytes("D", a, r->dstaddr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
                if (addr_diff(a, b, SIZE_STORED_ADDRESS)) {
-                       addinfo_bytes(" ", b, regs.dstaddr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
+                       addinfo_bytes(" ", b, r->dstaddr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
                }
        }
-       if (regs.branchtarget != 0xffffffff && regs.srcaddr != regs.branchtarget && regs.dstaddr != regs.branchtarget) {
-               uae_u8 *b = (uae_u8 *)regs.branchtarget - SIZE_STORED_ADDRESS_OFFSET;
-               addinfo_bytes("B", b, regs.branchtarget, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
+       if (r->branchtarget != 0xffffffff && r->srcaddr != r->branchtarget && r->dstaddr != r->branchtarget) {
+               uae_u8 *b = (uae_u8 *)r->branchtarget - SIZE_STORED_ADDRESS_OFFSET;
+               addinfo_bytes("B", b, r->branchtarget, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
        }
 //     sprintf(outbp, "STARTPC=%08x ENDPC=%08x\n", startpc, endpc);
 //     outbp += strlen(outbp);
@@ -1292,7 +1330,12 @@ static const struct srbit srbits[] = {
        { NULL, 0 }
 };
 
-static void out_regs(struct registers *r, int before)
+// r = registers to output
+// r1 = test results
+// r2 = expected results
+// sreg = original registers
+
+static void out_regs(struct registers *r, struct registers *r1, struct registers *r2, struct registers *sreg, int before)
 {
        if (before) {
                for (int i = 0; i < 16; i++) {
@@ -1302,18 +1345,18 @@ static void out_regs(struct registers *r, int before)
                                strcat(outbp, " ");
                        }
                        outbp += strlen(outbp);
-                       sprintf(outbp, "%c%d:%c%08x", i < 8 ? 'D' : 'A', i & 7, test_regs.regs[i] != last_registers.regs[i] ? '*' : ' ', r->regs[i]);
+                       sprintf(outbp, "%c%d:%c%08x", i < 8 ? 'D' : 'A', i & 7, r1->regs[i] != r2->regs[i] ? '*' : ' ', r->regs[i]);
                        outbp += strlen(outbp);
                }
                *outbp++ = '\n';
-               sprintf(outbp, "SR:%c%04x      PC: %08x ISP: %08x", test_sr != last_registers.sr ? '*' : ' ', test_sr, r->pc, r->ssp);
+               sprintf(outbp, "SR:%c%04x      PC: %08x ISP: %08x", r1->sr != r2->sr ? '*' : ' ', r->sr, r->pc, r->ssp);
        } else {
                // output only lines that have at least one modified register to save screen space
                for (int i = 0; i < 4; i++) {
                        int diff = 0;
                        for (int j = 0; j < 4; j++) {
                                int idx = i * 4 + j;
-                               if (test_regs.regs[idx] != regs.regs[idx]) {
+                               if (r1->regs[idx] != r2->regs[idx]) {
                                        diff = 1;
                                }
                        }
@@ -1322,13 +1365,13 @@ static void out_regs(struct registers *r, int before)
                                        int idx = i * 4 + j;
                                        if (j > 0)
                                                *outbp++ = ' ';
-                                       sprintf(outbp, "%c%d:%c%08x", idx < 8 ? 'D' : 'A', idx & 7, test_regs.regs[idx] != last_registers.regs[idx] ? '*' : ' ', test_regs.regs[idx]);
+                                       sprintf(outbp, "%c%d:%c%08x", idx < 8 ? 'D' : 'A', idx & 7, r->regs[idx] != r2->regs[idx] ? '*' : ' ', r->regs[idx]);
                                        outbp += strlen(outbp);
                                }
                                *outbp++ = '\n';
                        }
                }
-               sprintf(outbp, "SR:%c%04x/%04x PC: %08x ISP: %08x", test_sr != last_registers.sr ? '*' : ' ', test_regs.sr, test_regs.expsr, r->pc, r->ssp);
+               sprintf(outbp, "SR:%c%04x/%04x PC: %08x ISP: %08x", r->sr != r2->sr ? '*' : ' ', r->sr, r->expsr, r->pc, r->ssp);
        }
        outbp += strlen(outbp);
        if (cpu_lvl >= 2 && cpu_lvl <= 4) {
@@ -1336,12 +1379,13 @@ static void out_regs(struct registers *r, int before)
                outbp += strlen(outbp);
        }
        *outbp++ = '\n';
+       *outbp = 0;
 
        if (before >= 0) {
-               uae_u16 s = before ? test_sr : test_regs.sr; // current value
-               uae_u16 s1 = regs.sr; // original value
-               uae_u16 s2 = test_regs.sr; // test result value
-               uae_u16 s3 = last_registers.sr; // expected result value
+               uae_u16 s = r->sr; // current value
+               uae_u16 s1 = sreg->sr; // original value
+               uae_u16 s2 = r1->sr; // test result value
+               uae_u16 s3 = r2->sr; // expected result value
                for (int i = 0; srbits[i].name; i++) {
                        if (i > 0)
                                *outbp++ = ' ';
@@ -1351,33 +1395,63 @@ static void out_regs(struct registers *r, int before)
                        outbp += strlen(outbp);
                }
                *outbp++ = '\n';
+               *outbp = 0;
        }
 
        if (!fpu_model)
                return;
 
-       for (int i = 0; i < 8; i++) {
-               if (i > 0 && (i % 2) == 0) {
-                       strcat(outbp, "\n");
+       if (before) {
+               for (int i = 0; i < 8; i++) {
+                       if (i > 0 && (i % 2) == 0) {
+                               strcat(outbp, "\n");
+                       } else if ((i % 4) != 0) {
+                               strcat(outbp, " ");
+                       }
+                       outbp += strlen(outbp);
+                       struct fpureg *f = &r->fpuregs[i];
+                       void *f1 = &r->fpuregs[i];
+                       void *f2 = &r1->fpuregs[i];
+                       sprintf(outbp, "FP%d:%c%04x-%08x%08x %f",
+                               i,
+                               memcmp(f1, f2, sizeof(struct fpureg)) ? '*' : ' ',
+                               f->exp, f->m[0], f->m[1],
+                               *((long double *)f));
+                       outbp += strlen(outbp);
                }
-               else if ((i % 4) != 0) {
-                       strcat(outbp, " ");
+               *outbp++ = '\n';
+               *outbp = 0;
+       } else {
+               for (int i = 0; i < 8; i += 2) {
+                       struct fpureg *f = &r->fpuregs[i];
+                       void *f1 = &r1->fpuregs[i];
+                       void *f2 = &r2->fpuregs[i];
+                       void *f1b = &r1->fpuregs[i + 1];
+                       void *f2b = &r2->fpuregs[i + 1];
+
+                       if (memcmp(f1, f2, sizeof(struct fpureg)) || memcmp(f1b, f2b, sizeof(struct fpureg))) {
+                               for (int j = 0; j < 2; j++) {
+                                       f1 = &r->fpuregs[i + j];
+                                       f2 = &test_regs.fpuregs[i + j];
+                                       f = &test_regs.fpuregs[i + j];
+                                       if (j > 0)
+                                               *outbp++ = ' ';
+                                       sprintf(outbp, "FP%d:%c%04x-%08x%08x %f",
+                                               i + j,
+                                               memcmp(f1, f2, sizeof(struct fpureg)) ? '*' : ' ',
+                                               f->exp, f->m[0], f->m[1],
+                                               *((long double *)f));
+                                       outbp += strlen(outbp);
+                               }
+                               *outbp++ = '\n';
+                               *outbp = 0;
+                       }
                }
-               outbp += strlen(outbp);
-               struct fpureg *f = &r->fpuregs[i];
-               void *f1 = &regs.fpuregs[i];
-               void *f2 = &test_regs.fpuregs[i];
-               sprintf(outbp, "FP%d:%c%04x-%08x%08x %f",
-                       i,
-                       memcmp(f1, f2, sizeof(struct fpureg)) ? '*' : ' ',
-                       f->exp, f->m[0], f->m[1],
-                       *((long double*)f));
-               outbp += strlen(outbp);
        }
-       sprintf(outbp, "\nFPSR:%c%08x FPCR:%c%08x FPIAR:%c%08x\n",
-               test_fpsr != last_registers.fpsr ? '*' : ' ', before ? test_fpsr : test_regs.fpsr,
-               test_fpcr != last_registers.fpcr ? '*' : ' ', before ? test_fpcr : test_regs.fpcr,
-               regs.fpiar != last_registers.fpiar ? '*' : ' ', r->fpiar);
+       sprintf(outbp, "FPSR:%c%08x FPCR:%c%08x FPIAR:%c%08x\n",
+               r->fpsr != r2->fpsr ? '*' : ' ', r->fpsr,
+               r->fpcr != r2->fpcr ? '*' : ' ', r->fpcr,
+               r->fpiar != r2->fpiar ? '*' : ' ', r->fpiar);
 
        outbp += strlen(outbp);
 
@@ -1542,8 +1616,10 @@ static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, short excnu
                                // sr
                                exc[8] = regs->sr >> 8;
                                exc[9] = regs->sr;
-                               // pc
-                               pl(exc + 10, regs->pc);
+                               // program counter
+                               v = opcode_memory_addr;
+                               p = restore_rel_ordered(p, &v);
+                               pl(exc + 10, v);
                                exclen = 14;
                                if (basicexcept) {
                                        // I/N field is not always as documented
@@ -1844,7 +1920,7 @@ static int get_cycles_amiga(void)
 }
 #endif
 
-static int check_cycles(int exc, short extratrace, short extrag2w1)
+static int check_cycles(int exc, short extratrace, short extrag2w1, struct registers *lregs)
 {
        int gotcycles = 0;
 
@@ -1874,7 +1950,7 @@ static int check_cycles(int exc, short extratrace, short extrag2w1)
 #endif
        }
 
-       int expectedcycles = last_registers.cycles;
+       int expectedcycles = lregs->cycles;
        int exceptioncycles = getexceptioncycles(exc);
        if (cpu_lvl == 0) {
                // move.w CYCLEREG,cycles
@@ -1943,45 +2019,178 @@ static int check_cycles(int exc, short extratrace, short extrag2w1)
        return 1;
 }
 
-// regs: registers before execution of test code
-// test_reg: registers used during execution of test code, also modified by test code.
-// last_registers: registers after modifications from data files. Test ok if test_reg == last_registers.
+static short getzobits(uae_u32 *vvp, uae_u8 b)
+{
+       uae_u32 vv[2];
 
-static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr)
+       vv[0] = vvp[0];
+       vv[1] = vvp[1];
+       // xxxx-yyyyyyy-00000001 <> xxxx-yyyyyyyy-00000000
+       if ((vv[1] & 0x1f) == 0x01) {
+               vv[1] &= ~1;
+       }
+       int bc = 0;
+       for (short i = 1; i >= 0; i--) {
+               uae_u32 v = vv[i];
+               for (short j = 0; j < 32; j++) {
+                       if ((v & 1) != b)
+                               return bc;
+                       v >>= 1;
+                       bc++;
+               }
+       }
+       return bc;
+}
+
+// mostly ugly workarounds for logarithmic/trigonometric functions
+// not returning identical values (6888x algorithms are unknown)
+static short fpucheckextra(struct fpureg *f1, struct fpureg *f2)
 {
-       uae_u8 regs_changed[16] = { 0 };
-       uae_u8 regs_fpuchanged[8] = { 0 };
+       if (!is_fpu_adjust)
+               return 0;
+
+       uae_u32 m1[2];
+       uae_u32 m2[2];
+       m1[0] = f1->m[0];
+       m1[1] = f1->m[1];
+       m2[0] = f2->m[0];
+       m2[1] = f2->m[1];
+       uae_u16 exp1 = f1->exp & 0x7fff;
+       uae_u16 exp2 = f2->exp & 0x7fff;
+       // NaN or Infinite: both must match
+       if (exp1 == 0x7fff || exp2 == 0x7fff) {
+               return 0;
+       }
+       // Zero: both must match
+       if ((!exp1 && !m1[0] && !m1[1]) || (!exp2 && !m2[0] && !m2[1])) {
+               return 0;
+       }
+
+       // rounding difference
+       // yyyy-ffffffff-ffffffff <> xxxx+1-80000000-00000000
+       if (exp1 == exp2 + 1 && m1[0] == 0x80000000 && m1[1] == 0x00000000 && (m2[0] & 0xffff0000) == 0xffff0000) {
+               exp1--;
+               m1[0] = m2[0];
+               m1[1] = m2[1];
+       } else if (exp2 == exp1 + 1 && m2[0] == 0x80000000 && m2[1] == 0x00000000 && (m1[0] & 0xffff0000) == 0xffff0000) {
+               exp2--;
+               m2[0] = m1[0];
+               m2[1] = m1[1];
+       }
+
+       if (fpu_adjust_exp >= 0) {
+               if (abs(exp1 - exp2) > fpu_adjust_exp)
+                       return 0;
+       }
+
+       // Some functions return xxxxxxxx-xxxxx800
+       // ...f800 -> ...ffff
+       // ...0800 -> ...0000
+       if ((m1[1] & 0xffff) == 0x0800) {
+               m1[1] &= ~0xffff;
+       }
+       if ((m1[1] & 0xffff) == 0xf800) {
+               m1[1] |= 0xffff;
+       }
+       if ((m2[1] & 0xffff) == 0x0800) {
+               m2[1] &= ~0xffff;
+       }
+       if ((m2[1] & 0xffff) == 0xf800) {
+               m2[1] |= 0xffff;
+       }
+
+       short zb1 = getzobits(m1, 0);
+       short zb2 = getzobits(m2, 0);
+       short ob1 = getzobits(m1, 1);
+       short ob2 = getzobits(m2, 1);
+
+       // if another value ends to multiple zero bits
+       // and another to multiple one bits:
+       // skip it.
+       if (zb1 >= 4 && ob2 >= 4 && !zb2) {
+               zb2 = zb1;
+       } else if (zb2 >= 4 && ob1 >= 4 && !zb1) {
+               zb1 = zb2;
+       }
+
+       if (fpu_adjust_zb >= 0) {
+
+               if (abs(zb1 - zb2) > fpu_adjust_zb)
+                       return 0;
+       }
+
+       // skip n bits from the end
+       if (fpu_adjust_man >= 0) {
+               short shift = zb1 < zb2 ? zb1 : zb2;
+               short startm = 1;
+               if (shift >= 32) {
+                       startm = 0;
+                       shift -= 32;
+               }
+
+               short diff = 0;
+               for (short i = startm; i >= 0; i--) {
+                       while (shift < 32) {
+                               short v1 = (m1[i] >> shift) & 1;
+                               short v2 = (m2[i] >> shift) & 1;
+                               if (v1 != v2) {
+                                       diff++;
+                                       if (diff > fpu_adjust_man) {
+                                               return 0;
+                                       }
+                               }
+                               shift++;
+                       }
+                       shift = 0;
+               }
+       }
+
+       fpu_approx++;
+       return 1;
+}
+
+// sregs: registers before execution of test code
+// tregs: registers used during execution of test code, also modified by test code.
+// lregs: registers after modifications from data files. Test ok if tregs == lregs.
+
+static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr, struct registers *sregs, struct registers *tregs, struct registers *lregs, int opcodeendsizeextra)
+{
+       uae_u8 regs_changed[16] = { 0 }, regs_changed_any = 0;
+       uae_u8 regs_fpuchanged[8] = { 0 }, regs_fpuchanged_any = 0;
        uae_u8 sr_changed = 0, ccr_changed = 0, pc_changed = 0;
        uae_u8 fpiar_changed = 0, fpsr_changed = 0, fpcr_changed = 0;
        short exc = -1;
 
-       for (int i = 0; i < 16; i++) {
-               if (last_registers.regs[i] != test_regs.regs[i]) {
+       // Register modified in test? (start register != test register)
+       for (short i = 0; i < 16; i++) {
+               if (sregs->regs[i] != tregs->regs[i]) {
                        regs_changed[i] = 1;
+                       regs_changed_any = 1;
                }
        }
-       if ((last_registers.sr & test_ccrignoremask & 0xff00) != (test_regs.sr & test_ccrignoremask & 0xff00)) {
+       if ((sregs->sr & test_ccrignoremask & 0xff00) != (tregs->sr & test_ccrignoremask & 0xff00)) {
                sr_changed = 1;
        }
-       if ((last_registers.sr & test_ccrignoremask & 0x00ff) != (test_regs.sr & test_ccrignoremask & 0x00ff)) {
+       if ((sregs->sr & test_ccrignoremask & 0x00ff) != (tregs->sr & test_ccrignoremask & 0x00ff)) {
                ccr_changed = 1;
        }
-       if (last_registers.pc != test_regs.pc) {
+       if (sregs->pc + opcodeendsizeextra != tregs->pc) {
                pc_changed = 1;
        }
        if (fpu_model) {
-               for (int i = 0; i < 8; i++) {
-                       if (memcmp(&last_registers.fpuregs[i], &test_regs.fpuregs[i], sizeof(struct fpureg))) {
+               for (short i = 0; i < 8; i++) {
+                       if (memcmp(&sregs->fpuregs[i], &tregs->fpuregs[i], sizeof(struct fpureg))) {
                                regs_fpuchanged[i] = 1;
+                               regs_fpuchanged_any = 1;
                        }
                }
-               if (last_registers.fpsr != test_regs.fpsr) {
+               if (sregs->fpsr != tregs->fpsr) {
                        fpsr_changed = 1;
                }
-               if (last_registers.fpcr != test_regs.fpcr) {
+               if (sregs->fpcr != tregs->fpcr) {
                        fpcr_changed = 1;
                }
-               if (last_registers.fpiar != test_regs.fpiar) {
+               if (sregs->fpiar != tregs->fpiar) {
                        fpiar_changed = 1;
                }
        }
@@ -2002,8 +2211,8 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr)
                uae_u8 v = *p;
                if (v & CT_END) {
                        exc = v & CT_EXCEPTION_MASK;
-                       short cpuexc = test_regs.exc & 65535;
-                       short cpuexc010 = test_regs.exc010 & 65535;
+                       short cpuexc = tregs->exc & 65535;
+                       short cpuexc010 = tregs->exc010 & 65535;
                        p++;
                        if ((v & CT_END_INIT) == CT_END_INIT) {
                                end_test();
@@ -2030,10 +2239,10 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr)
                        }
                        if (exc == 0 && cpuexc == 4) {
                                // successful complete generates exception 4 with matching PC
-                               if (last_registers.pc != test_regs.pc && dooutput) {
-                                       sprintf(outbp, "PC: expected %08x but got %08x\n", last_registers.pc, test_regs.pc);
+                               if (lregs->pc + opcodeendsizeextra != tregs->pc && dooutput) {
+                                       sprintf(outbp, "PC: expected %08x but got %08x\n", lregs->pc, tregs->pc);
                                        outbp += strlen(outbp);
-                                       if (test_regs.pc == opcode_memory_addr) {
+                                       if (tregs->pc == opcode_memory_addr) {
                                                sprintf(outbp, "Got unexpected exception %d (unsupported instruction?)\n", cpuexc);
                                        } else {
                                                sprintf(outbp, "Got unexpected exception %d\n", cpuexc);
@@ -2057,7 +2266,7 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr)
                        }
                        if (exc != cpuexc && exc >= 2) {
                                if (dooutput) {
-                                       if (cpuexc == 4 && last_registers.pc == test_regs.pc) {
+                                       if (cpuexc == 4 && lregs->pc + opcodeendsizeextra == tregs->pc) {
                                                sprintf(outbp, "Exception: expected %d but got no exception.\n", exc);
                                        } else if (cpuexc == 4) {
                                                sprintf(outbp, "Exception: expected %d but got %d (or no exception)\n", exc, cpuexc);
@@ -2074,52 +2283,55 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr)
                short mode = v & CT_DATA_MASK;
 
                if (mode < CT_AREG + 8 && (v & CT_SIZE_MASK) != CT_SIZE_FPU) {
-                       uae_u32 val = last_registers.regs[mode];
+                       uae_u32 val = lregs->regs[mode];
                        int size;
                        p = restore_value(p, &val, &size);
-                       if (val != test_regs.regs[mode] && !ignore_errors && !skipregchange) {
-                               if (dooutput) {
-                                       if (regs.regs[mode] == test_regs.regs[mode]) {
-                                               sprintf(outbp, "%c%d: expected %08x but register was not modified\n", mode < CT_AREG ? 'D' : 'A', mode & 7, val);
-                                       } else {
-                                               sprintf(outbp, "%c%d: expected %08x but got %08x\n", mode < CT_AREG ? 'D' : 'A', mode & 7, val, test_regs.regs[mode]);
+                       if (val != tregs->regs[mode]) {
+                               if (!ignore_errors && !skipregchange) {
+                                       if (dooutput) {
+                                               if (sregs->regs[mode] == tregs->regs[mode]) {
+                                                       sprintf(outbp, "%c%d: expected %08x but register was not modified\n", mode < CT_AREG ? 'D' : 'A', mode & 7, val);
+                                               } else {
+                                                       sprintf(outbp, "%c%d: expected %08x but got %08x\n", mode < CT_AREG ? 'D' : 'A', mode & 7, val, tregs->regs[mode]);
+                                               }
+                                               outbp += strlen(outbp);
                                        }
-                                       outbp += strlen(outbp);
+                                       errflag |= 1 << 0;
                                }
-                               errflag |= 1 << 0;
                        }
+                       lregs->regs[mode] = val;
                        regs_changed[mode] = 0;
-                       last_registers.regs[mode] = val;
-               } else if (mode < CT_AREG && (v & CT_SIZE_MASK) == CT_SIZE_FPU && !skipregchange) {
+               } else if (mode < CT_AREG && (v & CT_SIZE_MASK) == CT_SIZE_FPU) {
                        struct fpureg val;
+                       memcpy(&val, &lregs->fpuregs[mode], sizeof(struct fpureg));
                        p = restore_fpvalue(p, &val);
-                       if (memcmp(&val, &test_regs.fpuregs[mode], sizeof(struct fpureg)) && !ignore_errors) {
-                               if (dooutput) {
-                                       if (regs.fpuregs[mode].m[0] == test_regs.fpuregs[mode].m[0] &&
-                                               regs.fpuregs[mode].m[1] == test_regs.fpuregs[mode].m[1] &&
-                                               regs.fpuregs[mode].exp == test_regs.fpuregs[mode].exp) {
-                                               sprintf(outbp, "FP%d: expected %04x-%08x%08x but register was not modified\n", mode,
-                                                       val.exp, val.m[0], val.m[1]);
-                                       } else {
-                                               sprintf(outbp, "FP%d: expected %04x-%08x%08x but got %04x-%08x%08x\n", mode,
-                                                       val.exp, val.m[0], val.m[1],
-                                                       test_regs.fpuregs[mode].exp, test_regs.fpuregs[mode].m[0], test_regs.fpuregs[mode].m[1]);
+                       if (memcmp(&val, &tregs->fpuregs[mode], sizeof(struct fpureg))) {
+                               if (!ignore_errors && !skipregchange && !fpucheckextra(&val, &tregs->fpuregs[mode])) {
+                                       if (dooutput) {
+                                               if (!memcmp(&sregs->fpuregs, &tregs->fpuregs[mode], sizeof(struct fpureg))) {
+                                                       sprintf(outbp, "FP%d: expected %04x-%08x%08x but register was not modified\n", mode,
+                                                               val.exp, val.m[0], val.m[1]);
+                                               } else {
+                                                       sprintf(outbp, "FP%d: expected %04x-%08x%08x but got %04x-%08x%08x\n", mode,
+                                                               val.exp, val.m[0], val.m[1],
+                                                               tregs->fpuregs[mode].exp, tregs->fpuregs[mode].m[0], tregs->fpuregs[mode].m[1]);
+                                               }
+                                               outbp += strlen(outbp);
                                        }
-                                       outbp += strlen(outbp);
+                                       errflag |= 1 << 1;
                                }
-                               errflag |= 1 << 1;
                        }
+                       memcpy(&lregs->fpuregs[mode], &val, sizeof(struct fpureg));
                        regs_fpuchanged[mode] = 0;
-                       xmemcpy(&last_registers.fpuregs[mode], &val, sizeof(struct fpureg));
                } else if (mode == CT_SR) {
-                       uae_u32 val = last_registers.sr;
+                       uae_u32 val = lregs->sr;
                        int size;
                        // High 16 bit: ignore mask, low 16 bit: SR/CCR
                        p = restore_value(p, &val, &size);
                        test_ccrignoremask = ~(val >> 16);
-                       if ((val & (sr_undefined_mask & test_ccrignoremask)) != (test_regs.sr & (sr_undefined_mask & test_ccrignoremask)) && !ignore_errors && !ignore_sr) {
+                       if ((val & (sr_undefined_mask & test_ccrignoremask)) != (tregs->sr & (sr_undefined_mask & test_ccrignoremask)) && !ignore_errors && !ignore_sr) {
                                if (dooutput) {
-                                       sprintf(outbp, "SR: expected %04x -> %04x but got %04x", test_sr & 0xffff, val & 0xffff, test_regs.sr & 0xffff);
+                                       sprintf(outbp, "SR: expected %04x -> %04x but got %04x", sregs->sr & 0xffff, val & 0xffff, tregs->sr & 0xffff);
                                        outbp += strlen(outbp);
                                        if (test_ccrignoremask != 0xffff) {
                                                sprintf(outbp, " (%04x)", test_ccrignoremask);
@@ -2131,92 +2343,96 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr)
                                }
                                // SR check
                                uae_u16 mask = test_ccrignoremask & 0xff00;
-                               if ((val & (sr_undefined_mask & mask)) == (test_regs.sr & (sr_undefined_mask & mask))) {
+                               if ((val & (sr_undefined_mask & mask)) == (tregs->sr & (sr_undefined_mask & mask))) {
                                        errflag &= ~(1 << 2);
                                }
                                // CCR check
                                mask = test_ccrignoremask & 0x00ff;
-                               if (skipccrchange || ((val & (sr_undefined_mask & mask)) == (test_regs.sr & (sr_undefined_mask & mask)))) {
+                               if (skipccrchange || ((val & (sr_undefined_mask & mask)) == (tregs->sr & (sr_undefined_mask & mask)))) {
                                        errflag &= ~(1 << 7);
                                }
                        }
                        sr_changed = 0;
                        ccr_changed = 0;
-                       last_registers.sr = val;
-                       if (!(test_regs.expsr & 0x2000)) {
+                       if (!(tregs->expsr & 0x2000)) {
                                sprintf(outbp, "SR S-bit is not set at start of exception handler!\n");
                                outbp += strlen(outbp);
                                errflag |= 1 << 16;
                        }
-                       if ((test_regs.expsr & 0xff) != (test_regs.sr & 0xff)) {
+                       if ((tregs->expsr & 0xff) != (tregs->sr & 0xff)) {
                                sprintf(outbp, "Exception stacked CCR != CCR at start of exception handler!\n");
                                outbp += strlen(outbp);
                                errflag |= 1 << 16;
                        }
-
+                       lregs->sr = val;
                } else if (mode == CT_PC) {
-                       uae_u32 val = last_registers.pc;
+                       uae_u32 val = lregs->pc;
                        p = restore_rel(p, &val, 0);
                        pc_changed = 0;
-                       last_registers.pc = val;
+                       lregs->pc = val;
                } else if (mode == CT_CYCLES) {
-                       uae_u32 val = last_registers.cycles;
+                       uae_u32 val = lregs->cycles;
                        int size;
                        p = restore_value(p, &val, &size);
-                       last_registers.cycles = val;
+                       lregs->cycles = val;
                        gotcycles = 1;
                } else if (mode == CT_FPCR) {
-                       uae_u32 val = last_registers.fpcr;
+                       uae_u32 val = lregs->fpcr;
                        int size;
                        p = restore_value(p, &val, &size);
-                       if (val != test_regs.fpcr && !ignore_errors) {
-                               if (dooutput) {
-                                       if (regs.fpcr == test_regs.fpcr) {
-                                               sprintf(outbp, "FPCR: expected %08x but register was not modified\n", val);
-                                       } else {
-                                               sprintf(outbp, "FPCR: expected %08x -> %08x but got %08x\n", test_fpcr, val, test_regs.fpcr);
+                       if (val != tregs->fpcr) {
+                               if (!ignore_errors) {
+                                       if (dooutput) {
+                                               if (sregs->fpcr == tregs->fpcr) {
+                                                       sprintf(outbp, "FPCR: expected %08x but register was not modified\n", val);
+                                               } else {
+                                                       sprintf(outbp, "FPCR: expected %08x -> %08x but got %08x\n", sregs->fpcr, val, tregs->fpcr);
+                                               }
+                                               outbp += strlen(outbp);
                                        }
-                                       outbp += strlen(outbp);
+                                       errflag |= 1 << 3;
                                }
-                               errflag |= 1 << 3;
                        }
+                       lregs->fpcr = val;
                        fpcr_changed = 0;
-                       last_registers.fpcr = val;
                } else if (mode == CT_FPSR) {
-                       uae_u32 val = last_registers.fpsr;
+                       uae_u32 val = lregs->fpsr;
                        int size;
                        p = restore_value(p, &val, &size);
-                       if (val != test_regs.fpsr && !ignore_errors) {
-                               if (dooutput) {
-                                       if (regs.fpsr == test_regs.fpsr) {
-                                               sprintf(outbp, "FPSR: expected %08x but register was not modified\n", val);
-                                       } else {
-                                               sprintf(outbp, "FPSR: expected %08x -> %08x but got %08x\n", test_fpsr, val, test_regs.fpsr);
+                       if (val != tregs->fpsr) {
+                               if (!ignore_errors) {
+                                       if (dooutput) {
+                                               if (sregs->fpsr == tregs->fpsr) {
+                                                       sprintf(outbp, "FPSR: expected %08x but register was not modified\n", val);
+                                               } else {
+                                                       sprintf(outbp, "FPSR: expected %08x -> %08x but got %08x\n", sregs->fpsr, val, tregs->fpsr);
+                                               }
+                                               outbp += strlen(outbp);
                                        }
-                                       outbp += strlen(outbp);
+                                       errflag |= 1 << 4;
                                }
-                               errflag |= 1 << 4;
                        }
+                       lregs->fpsr = val;
                        fpsr_changed = 0;
-                       last_registers.fpsr = val;
                } else if (mode == CT_FPIAR) {
-                       uae_u32 val = last_registers.fpiar;
+                       uae_u32 val = lregs->fpiar;
                        int size;
                        p = restore_value(p, &val, &size);
-                       if (val != test_regs.fpiar && !ignore_errors) {
-                               if (dooutput) {
-                                       if (regs.fpiar == test_regs.fpiar) {
-                                               sprintf(outbp, "FPIAR: expected %08x but register was not modified\n", val);
-                                       } else {
-                                               sprintf(outbp, "FPIAR: expected %08x but got %08x\n", val, test_regs.fpiar);
+                       if (val != tregs->fpiar) {
+                               if (!ignore_errors) {
+                                       if (dooutput) {
+                                               if (sregs->fpiar == tregs->fpiar) {
+                                                       sprintf(outbp, "FPIAR: expected %08x but register was not modified\n", val);
+                                               } else {
+                                                       sprintf(outbp, "FPIAR: expected %08x but got %08x\n", val, tregs->fpiar);
+                                               }
+                                               outbp += strlen(outbp);
                                        }
-                                       outbp += strlen(outbp);
+                                       errflag |= 1 << 5;
                                }
-                               errflag |= 1 << 5;
                        }
+                       lregs->fpiar = val;
                        fpiar_changed = 0;
-                       last_registers.fpiar = val;
-
                } else if (mode == CT_MEMWRITES) {
                        p = restore_memory(p, 0);
                } else if (mode == CT_MEMWRITE) {
@@ -2270,64 +2486,70 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr)
                }
        }
        if (!ignore_errors) {
-               if (!skipregchange) {
-                       for (int i = 0; i < 16; i++) {
-                               if (regs_changed[i]) {
+               if (!skipregchange && regs_changed_any) {
+                       for (short mode = 0; mode < 16; mode++) {
+                               if (regs_changed[mode] && tregs->regs[mode] != lregs->regs[mode]) {
                                        if (dooutput) {
-                                               sprintf(outbp, "%c%d: modified %08x -> %08x but expected no modifications\n", i < 8 ? 'D' : 'A', i & 7, last_registers.regs[i], test_regs.regs[i]);
-                                               outbp += strlen(outbp);
+                                               uae_u32 val = lregs->regs[mode];
+                                               sprintf(outbp, "%c%d: expected %08x but got %08x\n", mode < CT_AREG ? 'D' : 'A', mode & 7, val, tregs->regs[mode]);
                                        }
                                        errflag |= 1 << 0;
                                }
                        }
                }
                if (!ignore_sr) {
-                       if (sr_changed) {
+                       if (sr_changed && tregs->sr != lregs->sr) {
                                if (dooutput) {
-                                       sprintf(outbp, "SR: modified %04x -> %04x but expected no modifications\n", last_registers.sr & 0xffff, test_regs.sr & 0xffff);
+                                       sprintf(outbp, "SR: modified %04x -> %04x but expected %04x\n", sregs->sr & 0xffff, tregs->sr & 0xffff, lregs->sr & 0xffff);
                                        outbp += strlen(outbp);
                                }
                                errflag |= 1 << 2;
-                       } else if (ccr_changed && !skipccrchange) {
+                       } else if (ccr_changed && !skipccrchange && (tregs->sr & 0xff) != (lregs->sr & 0xff)) {
                                if (dooutput) {
-                                       sprintf(outbp, "SR: modified %04x -> %04x but expected no modifications\n", last_registers.sr & 0xffff, test_regs.sr & 0xffff);
+                                       sprintf(outbp, "SR: modified %04x -> %04x but expected %04x\n", sregs->sr & 0xffff, tregs->sr & 0xffff, lregs->sr & 0xffff);
                                        outbp += strlen(outbp);
                                }
                                errflag |= 1 << 2;
                        }
                }
-               if (!skipregchange) {
-                       for (int i = 0; i < 8; i++) {
-                               if (regs_fpuchanged[i]) {
-                                       if (dooutput) {
-                                               sprintf(outbp, "FP%d: modified %04x-%08x%08x -> %04x-%08x%08x but expected no modifications\n", i,
-                                                       last_registers.fpuregs[i].exp, last_registers.fpuregs[i].m[0], last_registers.fpuregs[i].m[1],
-                                                       test_regs.fpuregs[i].exp, test_regs.fpuregs[i].m[0], test_regs.fpuregs[i].m[1]);
-                                               outbp += strlen(outbp);
+               if (!skipregchange && regs_fpuchanged_any) {
+                       for (short mode = 0; mode < 8; mode++) {
+                               if (regs_fpuchanged[mode] && memcmp(&tregs->fpuregs[mode], &lregs->fpuregs[mode], sizeof(struct fpureg))) {
+                                       if (!fpucheckextra(&tregs->fpuregs[mode], &lregs->fpuregs[mode])) {
+                                               if (dooutput) {
+                                                       struct fpureg *val = &lregs->fpuregs[mode];
+                                                       sprintf(outbp, "FP%d: expected %04x-%08x%08x but got %04x-%08x%08x\n", mode,
+                                                               val->exp, val->m[0], val->m[1],
+                                                               tregs->fpuregs[mode].exp, tregs->fpuregs[mode].m[0], tregs->fpuregs[mode].m[1]);
+                                                       outbp += strlen(outbp);
+                                               }
+                                               errflag |= 1 << 1;
                                        }
-                                       errflag |= 1 << 1;
                                }
                        }
                }
                if (!ignore_sr) {
-                       if (fpsr_changed) {
+                       if (fpsr_changed && tregs->fpsr != lregs->fpsr) {
                                if (dooutput) {
-                                       sprintf(outbp, "FPSR: modified %08x -> %08x but expected no modifications\n", last_registers.fpsr, test_regs.fpsr);
+                                       uae_u32 val = lregs->fpsr;
+                                       sprintf(outbp, "FPSR: expected %08x -> %08x but got %08x\n", sregs->fpsr, val, tregs->fpsr);
                                        outbp += strlen(outbp);
                                }
                                errflag |= 1 << 3;
                        }
                }
-               if (fpcr_changed) {
+               if (fpcr_changed && tregs->fpcr != lregs->fpcr) {
                        if (dooutput) {
-                               sprintf(outbp, "FPCR: modified %08x -> %08x but expected no modifications\n", last_registers.fpcr, test_regs.fpcr);
+                               uae_u32 val = lregs->fpcr;
+                               sprintf(outbp, "FPCR: expected %08x -> %08x but got %08x\n", sregs->fpcr, val, tregs->fpcr);
                                outbp += strlen(outbp);
                        }
                        errflag |= 1 << 4;
                }
-               if (fpiar_changed) {
+               if (fpiar_changed && tregs->fpiar != lregs->fpiar) {
                        if (dooutput) {
-                               sprintf(outbp, "FPIAR: modified %08x -> %08x but expected no modifications\n", last_registers.fpiar, test_regs.fpiar);
+                               uae_u32 val = lregs->fpiar;
+                               sprintf(outbp, "FPIAR: expected %08x but got %08x\n", val, tregs->fpiar);
                                outbp += strlen(outbp);
                        }
                        errflag |= 1 << 5;
@@ -2339,7 +2561,7 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr)
                                        outbp += strlen(outbp);
                                }
                        } else {
-                               if (!check_cycles(exc, extratrace, extrag2w1)) {
+                               if (!check_cycles(exc, extratrace, extrag2w1, lregs)) {
                                        errflag |= 1 << 8;
                                }
                        }
@@ -2358,10 +2580,10 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr)
                strcpy(outbp, outbuffer2);
                strcat(outbp, "Registers before:\n");
                outbp += strlen(outbp);
-               out_regs(&regs, 1);
+               out_regs(sregs, tregs, lregs, sregs, 1);
                strcat(outbp, "Registers after:\n");
                outbp += strlen(outbp);
-               out_regs(&test_regs, 0);
+               out_regs(tregs, tregs, lregs, sregs, 0);
                if (exc > 1) {
                        if (!experr) {
                                sprintf(outbp, "OK: exception %d ", exc);
@@ -2382,7 +2604,7 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr)
                                        ((test_regs.exc >> (16 + 0)) & 7));
                                outbp += strlen(outbp);
                        }
-               } else if (exc == 0 && (test_regs.exc & 65535) == 4 && last_registers.pc == test_regs.pc) {
+               } else if (exc == 0 && (test_regs.exc & 65535) == 4 && lregs->pc == test_regs.pc) {
                        sprintf(outbp, "OK: No exception generated\n");
                        outbp += strlen(outbp);
                }
@@ -2396,6 +2618,31 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr)
        return p;
 }
 
+static void out_endinfo(void)
+{
+       sprintf(outbp, "%u (%u/%u) ", testcnt, testcntsub, testcntsubmax);
+       outbp += strlen(outbp);
+       sprintf(outbp, "S=%d", supercnt);
+       outbp += strlen(outbp);
+       for (int i = 0; i < 128; i++) {
+               if (exceptioncount[0][i] || exceptioncount[1][i] || exceptioncount[2][i]) {
+                       if (i == 2 || i == 3) {
+                               sprintf(outbp, " E%02d=%d/%d/%d", i, exceptioncount[0][i], exceptioncount[1][i], exceptioncount[2][i]);
+                       } else {
+                               sprintf(outbp, " E%02d=%d", i, exceptioncount[0][i]);
+                       }
+                       outbp += strlen(outbp);
+               }
+       }
+       strcat(outbp, "\n");
+       outbp += strlen(outbp);
+       if (fpu_approxcnt) {
+               sprintf(outbp, "FPU approximate matches: %d\n", fpu_approxcnt);
+       }
+       supercnt = 0;
+       memset(exceptioncount, 0, sizeof(exceptioncount));
+}
+
 static void store_addr(uae_u32 s, uae_u8 *d)
 {
        if (s == 0xffffffff)
@@ -2449,6 +2696,14 @@ static uae_u32 xorshift32(void)
        return xorshiftstate;
 }
 
+static void copyregs(struct registers *d, struct registers *s, short fpumode)
+{
+       memcpy(&d->regs[0], &s->regs[0], offsetof(struct registers, cycles));
+       if (fpumode) {
+               memcpy(&d->fpuregs[0], &s->fpuregs[0], offsetof(struct registers, fsave) - offsetof(struct registers, fpuregs));
+       }
+}
+
 static void process_test(uae_u8 *p)
 {
        outbp = outbuffer2;
@@ -2456,11 +2711,11 @@ static void process_test(uae_u8 *p)
        infoadded = 0;
        errors = 0;
 
-       memset(&regs, 0, sizeof(struct registers));
-       regs.sr = interrupt_mask << 8;
-       regs.srcaddr = 0xffffffff;
-       regs.dstaddr = 0xffffffff;
-       regs.branchtarget = 0xffffffff;
+       memset(&cur_regs, 0, sizeof(struct registers));
+       cur_regs.sr = interrupt_mask << 8;
+       cur_regs.srcaddr = 0xffffffff;
+       cur_regs.dstaddr = 0xffffffff;
+       cur_regs.branchtarget = 0xffffffff;
 
        if (safe_memory_mode) {
                set_berr(safe_memory_mode, 0);
@@ -2480,38 +2735,39 @@ static void process_test(uae_u8 *p)
 
        for (;;) {
 
-               regs.endpc = endpc;
-               regs.pc = startpc;
+               cur_regs.endpc = endpc;
+               cur_regs.pc = startpc;
 
                for (;;) {
                        uae_u8 v = *p;
                        if (v == CT_END_INIT || v == CT_END_FINISH)
                                break;
-                       p = restore_data(p);
+                       p = restore_data(p, &cur_regs);
                }
                if (*p == CT_END_FINISH)
                        break;
                p++;
 
                int stackcopysize = 0;
-               for (int i = 0; i < 32; i += 2) {
-                       if (!is_valid_test_addr_readwrite(regs.regs[15] + i))
+               for (short i = 0; i < 32; i += 2) {
+                       if (!is_valid_test_addr_readwrite(cur_regs.regs[15] + i))
                                break;
                        stackcopysize += 2;
                }
 
-               store_addr(regs.srcaddr, srcaddr);
-               store_addr(regs.dstaddr, dstaddr);
-               store_addr(regs.branchtarget, branchtarget);
-               startpc = regs.pc;
-               endpc = regs.endpc;
+               store_addr(cur_regs.srcaddr, srcaddr);
+               store_addr(cur_regs.dstaddr, dstaddr);
+               store_addr(cur_regs.branchtarget, branchtarget);
+               startpc = cur_regs.pc;
+               endpc = cur_regs.endpc;
                uae_u8 *opcode_memory_end = (uae_u8*)endpc;
 
-               xmemcpy(&last_registers, &regs, sizeof(struct registers));
-
                int fpumode = fpu_model && (opcode_memory[0] & 0xf0) == 0xf0;
 
+               copyregs(&last_regs, &cur_regs, fpumode);
+
                uae_u32 originalopcodeend = 0x4afc4e71;
+               short opcodeendsizeextra = 0;
                uae_u32 opcodeend = originalopcodeend;
                int extraccr = 0;
                int validendsize = 0;
@@ -2521,8 +2777,6 @@ static void process_test(uae_u8 *p)
                        validendsize = 1;
                }
 
-               uae_u32 last_pc = startpc;
-               uae_u32 last_fpiar = startpc;
                int old_super = -1;
 
                for (;;) {
@@ -2539,51 +2793,53 @@ static void process_test(uae_u8 *p)
 
                        uae_u8 ccrmode = *p++;
                        int maxccr = ccrmode & 0x3f;
-                       for (int ccr = 0;  ccr < maxccr; ccr++) {
+                       testcntsubmax = maxccr;
+                       testcntsub = 0;
+                       for (short ccr = 0;  ccr < maxccr; ccr++, testcntsub++) {
+
+                               copyregs(&test_regs, &cur_regs, fpumode);
+                               fpu_approx = 0;
 
                                opcodeend = (opcodeend >> 16) | (opcodeend << 16);
+                               opcodeendsizeextra = opcodeendsizeextra ? 0 : 2;
                                if (validendsize == 2) {
                                        pl(opcode_memory_end, opcodeend);
                                } else if (validendsize == 1) {
                                        pw(opcode_memory_end, opcodeend >> 16);
                                }
 
-                               if (regs.branchtarget != 0xffffffff && !(regs.branchtarget & 1)) {
-                                       if (regs.branchtarget_mode == 1) {
-                                               uae_u32 bv = gl((uae_u8*)regs.branchtarget);
+                               if (test_regs.branchtarget != 0xffffffff && !(test_regs.branchtarget & 1)) {
+                                       if (test_regs.branchtarget_mode == 1) {
+                                               uae_u32 bv = gl((uae_u8*)test_regs.branchtarget);
                                                bv = (bv >> 16) | (bv << 16);
-                                               pl((uae_u8*)regs.branchtarget, bv);
-                                       } else if (regs.branchtarget_mode == 2) {
-                                               uae_u16 bv = gw((uae_u8 *)regs.branchtarget);
+                                               pl((uae_u8*)test_regs.branchtarget, bv);
+                                       } else if (test_regs.branchtarget_mode == 2) {
+                                               uae_u16 bv = gw((uae_u8 *)test_regs.branchtarget);
                                                if (bv == 0x4e71)
                                                        bv = 0x4afc;
                                                else
                                                        bv = 0x4e71;
-                                               pw((uae_u8 *)regs.branchtarget, bv);
+                                               pw((uae_u8 *)test_regs.branchtarget, bv);
                                        }
                                }
 
-                               regs.ssp = super_stack_memory - 0x80;
-                               regs.msp = super_stack_memory;
-                               regs.pc = startpc;
-                               regs.fpiar = startpc;
-                               regs.cyclest = 0xffffffff;
-                               regs.fpeaset = 0;
+                               test_regs.ssp = super_stack_memory - 0x80;
+                               test_regs.msp = super_stack_memory;
+                               test_regs.pc = startpc;
+                               test_regs.fpiar = startpc;
+                               test_regs.cyclest = 0xffffffff;
+                               test_regs.fpeaset = 0;
 
 #ifdef M68K
                                if (stackcopysize > 0)
-                                       xmemcpy((void*)regs.ssp, (void*)regs.regs[15], stackcopysize);
+                                       xmemcpy((void*)test_regs.ssp, (void*)test_regs.regs[15], stackcopysize);
 #endif
-                               xmemcpy(&test_regs, &regs, sizeof(struct registers));
-
                                if (maxccr >= 32) {
                                        test_regs.sr = ccr & 0xff;
                                } else {
                                        test_regs.sr = (ccr & 1) ? 31 : 0;
                                }
                                test_regs.sr |= sr_mask | (interrupt_mask << 8);
-                               test_regs.expsr = test_regs.sr | 0x2000;
-                               test_sr = test_regs.sr;
                                if (fpumode) {
                                        test_regs.fpcr = 0;
                                        test_regs.fpsr = 0;
@@ -2600,13 +2856,69 @@ static void process_test(uae_u8 *p)
                                                        test_regs.fpcr = (ccr & 15) << 4;
                                                }
                                        }
-                                       test_fpsr = test_regs.fpsr;
-                                       test_fpcr = test_regs.fpcr;
                                }
+
+                               while ((*p) == CT_OVERRIDE_REG) {
+                                       p++;
+                                       uae_u8 v = *p++;
+                                       uae_u8 r = v & CT_DATA_MASK;
+                                       uae_u8 size = v & CT_SIZE_MASK;
+                                       if (r == CT_SR) {
+                                               if (size == CT_SIZE_BYTE) {
+                                                       test_regs.sr &= 0xff00;
+                                                       test_regs.sr |= *p++;
+                                               } else {
+                                                       test_regs.sr = (*p++) << 8;
+                                                       test_regs.sr |= *p++;
+                                               }
+                                               cur_regs.sr = test_regs.sr;
+                                       } else if (r == CT_FPSR) {
+                                               cur_regs.fpsr = test_regs.fpsr = gl(p);
+                                               p += 4;
+                                       } else if (r == CT_FPCR) {
+                                               cur_regs.fpcr = test_regs.fpcr = gl(p);
+                                               p += 4;
+                                       } else if (r == CT_FPIAR) {
+                                               cur_regs.fpiar = test_regs.fpiar = gl(p);
+                                               p += 4;
+                                       } else if (r >= CT_DREG && r < CT_DREG + 16) {
+                                               if (size == CT_SIZE_FPU) {
+                                                       struct fpureg *f = &test_regs.fpuregs[r - CT_DREG];
+                                                       uae_u32 val = gl(p);
+                                                       f->exp = val >> 16;
+                                                       f->dummy = val;
+                                                       f->m[0] = gl(p + 4);
+                                                       f->m[1] = gl(p + 8);
+                                                       p += 12;
+                                               } else {
+                                                       cur_regs.regs[r - CT_DREG] = gl(p);
+                                                       p += 4;
+                                               }
+                                       } else {
+                                               end_test();
+                                               printf("Unknown override register %02x!\n", v);
+                                               exit(0);
+                                       }
+                               }
+
+                               test_regs.expsr = test_regs.sr | 0x2000;
+
+                               // internally modified registers become part of cur_regs
+                               cur_regs.sr = test_regs.sr;
+                               cur_regs.expsr = test_regs.expsr;
+                               cur_regs.fpsr = test_regs.fpsr;
+                               cur_regs.fpcr = test_regs.fpcr;
+                               if (!sr_mask && !ccr) {
+                                       last_regs.sr = test_regs.sr;
+                                       last_regs.expsr = test_regs.expsr;
+                                       last_regs.fpsr = test_regs.fpsr;
+                                       last_regs.fpcr = test_regs.fpcr;
+                               }
+
                                int super = (test_regs.sr & 0x2000) != 0;
 
                                if (super != old_super) {
-                                       stackaddr_ptr = super ? regs.ssp : regs.regs[15];
+                                       stackaddr_ptr = super ? test_regs.ssp : test_regs.regs[15];
                                        store_addr(stackaddr_ptr, stackaddr);
                                        old_super = super;
                                }
@@ -2617,7 +2929,7 @@ static void process_test(uae_u8 *p)
                                                addinfo();
                                                strcat(outbp, "Registers before:\n");
                                                outbp += strlen(outbp);
-                                               out_regs(&regs, 1);
+                                               out_regs(&cur_regs, &test_regs, &last_regs, &cur_regs, 1);
                                                end_test();
                                                printf(outbuffer);
                                                printf("\nExit count expired\n");
@@ -2642,13 +2954,20 @@ static void process_test(uae_u8 *p)
                                                volatile int *tn = (volatile int*)0x100;
                                                *tn = testcnt;
 #endif
+#if 0
+                                               uae_u32 *sx = (uae_u32 *)startpc;
+                                               if (*sx == 0xf2364c98) {
+                                                       volatile uae_u16 *tn = (volatile uae_u16*)0x70000;
+                                                       *tn = 0x1234;
+                                               }
+#endif
+
 
 #ifdef AMIGA
                                                if (interrupttest) {
                                                        set_interrupt();
                                                }
 #endif
-
                                                if (cpu_lvl == 1) {
                                                        execute_test010(&test_regs);
                                                } else if (cpu_lvl >= 2) {
@@ -2674,16 +2993,12 @@ static void process_test(uae_u8 *p)
 
                                        } else {
 
-                                               test_regs.sr = test_sr;
-                                               test_regs.fpsr = test_fpsr;
                                                ignore_errors = 1;
                                                ignore_sr = 1;
 
                                        }
 
-                                       last_registers.pc = last_pc;
-                                       last_registers.fpiar = last_fpiar;
-
+#if 0
                                        if ((*p) == CT_SKIP_REGS) {
                                                p++;
                                                for (int i = 0; i < 16; i++) {
@@ -2695,15 +3010,14 @@ static void process_test(uae_u8 *p)
                                                        }
                                                }
                                        }
+#endif
 
-                                       p = validate_test(p, ignore_errors, ignore_sr);
+                                       p = validate_test(p, ignore_errors, ignore_sr, &cur_regs, &test_regs, &last_regs, opcodeendsizeextra);
 
                                        testcnt++;
                                        if (super)
                                                supercnt++;
 
-                                       last_pc = last_registers.pc;
-                                       last_fpiar = last_registers.fpiar;
                                }
 
                                if (testexit()) {
@@ -2712,14 +3026,30 @@ static void process_test(uae_u8 *p)
                                        exit(0);
                                }
 
+                               if (fpu_approx) {
+                                       fpu_approxcnt++;
+                               }
+
                                if (quit || errors) {
-                                       if (continue_on_error) {
-                                               // always abort if buffer is getting too small
-                                               if (outbp - outbuffer >= outbuffer_size - 3000)
+                                       if (!quit && errorcnt > 0 && totalerrors < errorcnt) {
+                                               if (totalerrors > 0) {
+                                                       strcat(stored_outbuffer, "----------------------------------------\n");
+                                               }
+                                               if (strlen(stored_outbuffer) + strlen(outbuffer) + 40 >= outbuffer_size) {
                                                        goto end;
+                                               }
+                                               strcat(stored_outbuffer, outbuffer);
+                                               outbp = stored_outbuffer + strlen(stored_outbuffer);
+                                               out_endinfo();
+                                               infoadded = 0;
+                                               errors = 0;
+                                               outbuffer[0] = 0;
+                                               outbuffer2[0] = 0;
+                                               outbp = outbuffer2;
                                        } else {
                                                goto end;
                                        }
+                                       totalerrors++;
                                }
                        }
 
@@ -2746,9 +3076,13 @@ end:
        end_test();
        set_berr(0, 0);
 
-       if (infoadded) {
-               printf("\n");
-               printf(outbuffer);
+       if (errorcnt > 0) {
+               printf("%s", stored_outbuffer);
+       } else {
+               if (infoadded) {
+                       printf("\n");
+                       printf("%s", outbuffer);
+               }
        }
 }
 
@@ -2903,6 +3237,7 @@ static int test_mnemo(const char *opcode)
        printf("%s (%s):\n", inst_name, group);
 
        testcnt = 0;
+       fpu_approxcnt = 0;
        memset(exceptioncount, 0, sizeof(exceptioncount));
        supercnt = 0;
 
@@ -2962,18 +3297,11 @@ static int test_mnemo(const char *opcode)
                filecnt++;
        }
 
-       printf("%u ", testcnt);
-       printf("S=%d", supercnt);
-       for (int i = 0; i < 128; i++) {
-               if (exceptioncount[0][i] || exceptioncount[1][i] || exceptioncount[2][i]) {
-                       if (i == 2 || i == 3) {
-                               printf(" E%02d=%d/%d/%d", i, exceptioncount[0][i], exceptioncount[1][i], exceptioncount[2][i]);
-                       } else {
-                               printf(" E%02d=%d", i, exceptioncount[0][i]);
-                       }
-               }
+       if (errorcnt == 0) {
+               outbp = outbuffer;
+               out_endinfo();
+               printf("%s", outbuffer);
        }
-       printf("\n");
 
        if (!errors && !quit) {
                printf("All tests complete (total %u).\n", testcnt);
@@ -3055,7 +3383,7 @@ int main(int argc, char *argv[])
                printf("all <mnemonic> = test all, starting from <mnemonic>\n");
                printf("all <mnemonic> -next = test all, starting after <mnemonic>\n");
                printf("-continue = don't stop on error (continue to next test, all mode only)\n");
-               printf("-nostop = don't stop on error (continue current instruction)\n");
+               printf("-errors n = store up to n errors before aborting test.\n");
                printf("-ccrmask = ignore CCR bits that are not set.\n");
                printf("-nodisasm = do not disassemble failed test.\n");
                printf("-basicexc = do only basic checks when exception is 2 or 3.\n");
@@ -3064,6 +3392,7 @@ int main(int argc, char *argv[])
                printf("-skipreg = do not validate registers.\n");
                printf("-askifmissing = ask for new path if dat file is missing.\n");
                printf("-exit n = exit after n tests.\n");
+               printf("-fpuadj <exp diff> <man bit count diff> <man zero bit count diff>.\n");
                printf("-cycles [range adjust] = check cycle counts.\n");
                printf("-cyclecnt <address>. Use custom hardware cycle counter.\n");
 #ifdef AMIGA
@@ -3081,7 +3410,9 @@ int main(int argc, char *argv[])
        exitcnt = -1;
        cyclecounter_addr = 0xffffffff;
        cycles_range = 2;
-       outbuffer_size = DEFAULT_OUTBUFFER_SIZE;
+       fpu_adjust_exp = -1;
+       fpu_adjust_man = -1;
+       fpu_adjust_zb = -1;
 
        for (int i = 1; i < argc; i++) {
                char *s = argv[i];
@@ -3137,6 +3468,22 @@ int main(int argc, char *argv[])
                                exitcnt = atoi(next);
                                i++;
                        }
+               } else if (!_stricmp(s, "-fpuadj")) {
+                       if (next) {
+                               fpu_adjust_exp = atol(next);
+                               char *p = strchr(next, ',');
+                               if (p) {
+                                       fpu_adjust_man = atol(p + 1);
+                                       char *p = strchr(next, ',');
+                                       if (p) {
+                                               fpu_adjust_zb = atol(p + 1);
+                                       }
+                               }
+                               if (fpu_adjust_exp >= 0 || fpu_adjust_man >= 0 || fpu_adjust_zb >= 0) {
+                                       is_fpu_adjust = 1;
+                               }
+
+                       }
                } else if (!_stricmp(s, "-cycles")) {
                        cycles = 1;
                        if (i + 1 < argc && argv[i][0] != '-') {
@@ -3154,10 +3501,10 @@ int main(int argc, char *argv[])
                        }
                } else if (!_stricmp(s, "-uae")) {
                        uaemode = 1;
-               } else if (!_stricmp(s, "-outbuffer")) {
+               } else if (!_stricmp(s, "-errors")) {
                        if (i + 1 < argc) {
                                i++;
-                               outbuffer_size = atoi(argv[i]);
+                               errorcnt = atoi(argv[i]);
                        }
                }
 
@@ -3181,14 +3528,13 @@ int main(int argc, char *argv[])
        }
 #endif
 
-       if (outbuffer_size < 4000) {
-               outbuffer_size = 4000;
-       }
-       outbuffer = (char*)calloc(outbuffer_size, 1);
-       outbuffer2 = (char*)calloc(outbuffer_size, 1);
-       if (!outbuffer || !outbuffer2) {
-               printf("Out of memory when allocating output buffer.\n");
-               return 0;
+       if (errorcnt > 0) {
+               outbuffer_size = errorcnt * PAGE_OUTBUFFER_SIZE;
+               stored_outbuffer = calloc(outbuffer_size, 1);
+               if (!stored_outbuffer) {
+                       printf("Out of memory when allocating temporary output buffer.\n");
+                       return 0;
+               }
        }
 
        DIR *groupd = NULL;
index 47c1058765a72d0ee74e6b29c0c8adf7da59a160..c3208b7dfedcc700f8d8ead8756dad1461561f15 100644 (file)
@@ -131,6 +131,15 @@ If mismatch is detected, opcode word(s), instruction disassembly, registers befo
 
 Change log:
 
+09.05.2020
+
+- dat format changed, now it is possible to continue running test if previous test reported error.
+- dat file stored FPU data uses less space.
+- added forced_register option, force static content to any supported register.
+- added -exit n command line parameter, n = number of errors until current test run gets aborted.
+- added -fpuadj x,y,z command line parameter. x = max exponent difference allowed, y = ignore y last bits of mantissa, z = ignore z last zero bits of mantissa.
+- 68000 bus/address error stack frame program counter field was ignored.
+
 19.04.2020
 
 - * = ignore rest of name, for example "cputest basic/neg*" will run NEG.B, NEG.W and NEG.L tests.