mirror of
https://github.com/LIV2/WinUAE.git
synced 2025-12-06 00:12:52 +00:00
1479 lines
32 KiB
C
1479 lines
32 KiB
C
|
|
#define _CRT_SECURE_NO_WARNINGS
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <memory.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
#include "msc_dirent.h"
|
|
#else
|
|
#include <dirent.h>
|
|
#endif
|
|
|
|
#define DONTSTOPONERROR 0
|
|
|
|
typedef unsigned int uae_u32;
|
|
typedef int uae_s32;
|
|
typedef unsigned short uae_u16;
|
|
typedef short uae_s16;
|
|
typedef unsigned char uae_u8;
|
|
typedef signed char uae_s8;
|
|
|
|
#include "cputest_defines.h"
|
|
|
|
struct fpureg
|
|
{
|
|
uae_u16 exp;
|
|
uae_u16 dummy;
|
|
uae_u32 m[2];
|
|
};
|
|
|
|
struct registers
|
|
{
|
|
uae_u32 regs[16];
|
|
uae_u32 ssp;
|
|
uae_u32 msp;
|
|
uae_u32 pc;
|
|
uae_u32 sr;
|
|
uae_u32 exc;
|
|
struct fpureg fpuregs[8];
|
|
uae_u32 fpiar, fpcr, fpsr;
|
|
};
|
|
|
|
static struct registers test_regs;
|
|
static struct registers last_registers;
|
|
static struct registers regs;
|
|
static uae_u8 *opcode_memory;
|
|
static uae_u32 opcode_memory_addr;
|
|
static uae_u8 *low_memory;
|
|
static uae_u8 *high_memory;
|
|
static uae_u8 *test_memory;
|
|
static uae_u32 test_memory_addr;
|
|
static uae_u32 test_memory_size;
|
|
static uae_u8 *test_data;
|
|
static int test_data_size;
|
|
static uae_u32 oldvbr;
|
|
static uae_u8 *vbr_zero = 0;
|
|
static int hmem_rom, lmem_rom;
|
|
static uae_u8 *absallocated;
|
|
static int cpu_lvl, fpu_model;
|
|
static uae_u16 sr_undefined_mask;
|
|
static int check_undefined_sr;
|
|
static uae_u32 cpustatearraystore[16];
|
|
static uae_u32 cpustatearraynew[] = {
|
|
0x00000005, // SFC
|
|
0x00000005, // DFC
|
|
0x00000009, // CACR
|
|
0x00000000, // CAAR
|
|
0x00000000, // MSP
|
|
};
|
|
|
|
static uae_u8 low_memory_temp[32768];
|
|
static uae_u8 high_memory_temp[32768];
|
|
static uae_u8 low_memory_back[32768];
|
|
static uae_u8 high_memory_back[32768];
|
|
|
|
static uae_u32 vbr[256];
|
|
|
|
static char inst_name[16+1];
|
|
#ifdef _MSC_VER
|
|
static char outbuffer[40000];
|
|
#else
|
|
static char outbuffer[4000];
|
|
#endif
|
|
static char *outbp;
|
|
static int infoadded;
|
|
static int errors;
|
|
static int testcnt;
|
|
static int dooutput = 1;
|
|
static int quit;
|
|
static uae_u8 ccr_mask;
|
|
static uae_u32 addressing_mask = 0x00ffffff;
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
#define xmemcpy memcpy
|
|
|
|
static uae_u8 *allocate_absolute(uae_u32 addr, uae_u32 size)
|
|
{
|
|
return calloc(1, size);
|
|
}
|
|
static void free_absolute(uae_u32 addr, uae_u32 size)
|
|
{
|
|
}
|
|
static void execute_test000(struct registers *regs)
|
|
{
|
|
}
|
|
static void execute_test010(struct registers *regs)
|
|
{
|
|
}
|
|
static void execute_test020(struct registers *regs)
|
|
{
|
|
}
|
|
static void execute_testfpu(struct registers *regs)
|
|
{
|
|
}
|
|
static uae_u32 tosuper(uae_u32 v)
|
|
{
|
|
return 0;
|
|
}
|
|
static void touser(uae_u32 v)
|
|
{
|
|
}
|
|
static uae_u32 exceptiontable000, exception010, exception020, exceptionfpu;
|
|
static uae_u32 testexit(void)
|
|
{
|
|
return 0;
|
|
}
|
|
static uae_u32 setvbr(uae_u32 v)
|
|
{
|
|
return 0;
|
|
}
|
|
static uae_u32 get_cpu_model(void)
|
|
{
|
|
return 0;
|
|
}
|
|
static void setcpu(uae_u32 v, uae_u32 *s, uae_u32 *d)
|
|
{
|
|
}
|
|
static void flushcache(void)
|
|
{
|
|
}
|
|
#else
|
|
|
|
static void xmemcpy(void *d, void *s, int size)
|
|
{
|
|
__builtin_memcpy(d, s, size);
|
|
}
|
|
|
|
extern uae_u8 *allocate_absolute(uae_u32, uae_u32);
|
|
extern void free_absolute(uae_u32, uae_u32);
|
|
extern void execute_test000(struct registers*);
|
|
extern void execute_test010(struct registers *);
|
|
extern void execute_test020(struct registers *);
|
|
extern void execute_testfpu(struct registers *);
|
|
extern uae_u32 tosuper(uae_u32);
|
|
extern void touser(uae_u32);
|
|
extern uae_u32 exceptiontable000, exception010, exception020, exceptionfpu;
|
|
extern uae_u32 testexit(void);
|
|
extern uae_u32 setvbr(uae_u32);
|
|
extern uae_u32 get_cpu_model(void);
|
|
extern void setcpu(uae_u32, uae_u32*, uae_u32*);
|
|
extern void flushcache(void);
|
|
|
|
#endif
|
|
|
|
struct accesshistory
|
|
{
|
|
uae_u8 *addr;
|
|
uae_u32 val;
|
|
uae_u32 oldval;
|
|
int size;
|
|
};
|
|
static int ahcnt;
|
|
|
|
#define MAX_ACCESSHIST 8
|
|
static struct accesshistory ahist[MAX_ACCESSHIST];
|
|
|
|
static void endinfo(void)
|
|
{
|
|
printf("Last test: %lu\n", testcnt);
|
|
uae_u8 *p = opcode_memory;
|
|
for (int i = 0; i < 32 * 2; i += 2) {
|
|
uae_u16 v = (p[i] << 8) | (p[i + 1]);
|
|
if (v == 0x4afc && i > 0)
|
|
break;
|
|
printf(" %04x", v);
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
static int test_active;
|
|
static uae_u32 enable_data;
|
|
|
|
static void start_test(void)
|
|
{
|
|
if (test_active)
|
|
return;
|
|
|
|
#ifndef _MSC_VER
|
|
if (lmem_rom) {
|
|
if (memcmp(low_memory, low_memory_temp, 32768)) {
|
|
printf("Low memory ROM mismatch!\n");
|
|
exit(0);
|
|
}
|
|
}
|
|
if (hmem_rom) {
|
|
if (memcmp(high_memory, high_memory_temp, 32768)) {
|
|
printf("High memory ROM mismatch!\n");
|
|
exit(0);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
test_active = 1;
|
|
|
|
enable_data = tosuper(0);
|
|
|
|
memcpy(low_memory_back, low_memory, 32768);
|
|
if (!hmem_rom)
|
|
memcpy(high_memory_back, high_memory, 32768);
|
|
|
|
memcpy(low_memory, low_memory_temp, 32768);
|
|
if (!hmem_rom)
|
|
memcpy(high_memory, high_memory_temp, 32768);
|
|
|
|
if (cpu_lvl == 0) {
|
|
uae_u32 *p = (uae_u32 *)vbr_zero;
|
|
for (int i = 3; i < 12; i++) {
|
|
p[i] = (uae_u32)(((uae_u32)&exceptiontable000) + (i - 3) * 2);
|
|
}
|
|
for (int i = 32; i < 48; i++) {
|
|
p[i] = (uae_u32)(((uae_u32)&exceptiontable000) + (i - 3) * 2);
|
|
}
|
|
} else {
|
|
oldvbr = setvbr((uae_u32)vbr);
|
|
for (int i = 0; i < 256; i++) {
|
|
vbr[i] = fpu_model ? (uae_u32)(&exceptionfpu) : (cpu_lvl == 1 ? (uae_u32)(&exception010) : (uae_u32)(&exception020));
|
|
}
|
|
}
|
|
setcpu(cpu_lvl, cpustatearraynew, cpustatearraystore);
|
|
}
|
|
|
|
static void end_test(void)
|
|
{
|
|
if (!test_active)
|
|
return;
|
|
test_active = 0;
|
|
|
|
memcpy(low_memory, low_memory_back, 32768);
|
|
if (!hmem_rom)
|
|
memcpy(high_memory, high_memory_back, 32768);
|
|
|
|
if (cpu_lvl > 0) {
|
|
setvbr(oldvbr);
|
|
}
|
|
setcpu(cpu_lvl, cpustatearraystore, NULL);
|
|
|
|
touser(enable_data);
|
|
}
|
|
|
|
static uae_u8 *load_file(const char *path, const char *file, uae_u8 *p, int *sizep)
|
|
{
|
|
char fname[256];
|
|
sprintf(fname, "%s%s", path, file);
|
|
FILE *f = fopen(fname, "rb");
|
|
if (!f) {
|
|
printf("Couldn't open '%s'\n", fname);
|
|
exit(0);
|
|
}
|
|
int size = *sizep;
|
|
if (size < 0) {
|
|
fseek(f, 0, SEEK_END);
|
|
size = ftell(f);
|
|
fseek(f, 0, SEEK_SET);
|
|
}
|
|
if (!p) {
|
|
p = calloc(1, size);
|
|
if (!p) {
|
|
printf("Couldn't allocate %ld bytes, file '%s'\n", size, fname);
|
|
exit(0);
|
|
}
|
|
}
|
|
*sizep = fread(p, 1, size, f);
|
|
if (*sizep != size) {
|
|
printf("Couldn't read file '%s'\n", fname);
|
|
exit(0);
|
|
}
|
|
fclose(f);
|
|
return p;
|
|
}
|
|
|
|
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_u8 *restore_fpvalue(uae_u8 *p, struct fpureg *fp)
|
|
{
|
|
uae_u8 v = *p++;
|
|
if ((v & CT_SIZE_MASK) != CT_SIZE_FPU) {
|
|
end_test();
|
|
printf("Expected CT_SIZE_FPU, got %02x\n", v);
|
|
endinfo();
|
|
exit(0);
|
|
}
|
|
fp->exp = (p[0] << 8) | p[1];
|
|
p += 2;
|
|
fp->m[0] = gl(p);
|
|
p += 4;
|
|
fp->m[1] = gl(p);
|
|
p += 4;
|
|
return p;
|
|
}
|
|
|
|
static uae_u8 *restore_value(uae_u8 *p, uae_u32 *vp, int *sizep)
|
|
{
|
|
uae_u32 val = *vp;
|
|
uae_u8 v = *p++;
|
|
switch(v & CT_SIZE_MASK)
|
|
{
|
|
case CT_SIZE_BYTE:
|
|
val &= 0xffffff00;
|
|
val |= *p++;
|
|
*sizep = 0;
|
|
break;
|
|
case CT_SIZE_WORD:
|
|
val &= 0xffff0000;
|
|
val |= (*p++) << 8;
|
|
val |= *p++;
|
|
*sizep = 1;
|
|
break;
|
|
case CT_SIZE_LONG:
|
|
val = (*p++) << 24;
|
|
val |= (*p++) << 16;
|
|
val |= (*p++) << 8;
|
|
val |= *p++;
|
|
*sizep = 2;
|
|
break;
|
|
case CT_SIZE_FPU:
|
|
end_test();
|
|
printf("Unexpected CT_SIZE_FPU\n");
|
|
endinfo();
|
|
exit(0);
|
|
break;
|
|
}
|
|
*vp = val;
|
|
return p;
|
|
}
|
|
|
|
static uae_u8 *restore_rel(uae_u8 *p, uae_u32 *vp)
|
|
{
|
|
uae_u32 v = *vp;
|
|
switch ((*p++) & CT_SIZE_MASK)
|
|
{
|
|
case CT_RELATIVE_START_BYTE:
|
|
{
|
|
uae_u8 val;
|
|
val = *p++;
|
|
v += (uae_s8)val;
|
|
break;
|
|
}
|
|
case CT_RELATIVE_START_WORD:
|
|
{
|
|
uae_u16 val;
|
|
val = (*p++) << 8;
|
|
val |= *p++;
|
|
v += (uae_s16)val;
|
|
break;
|
|
}
|
|
case CT_ABSOLUTE_WORD:
|
|
{
|
|
uae_u16 val;
|
|
val = (*p++) << 8;
|
|
val |= *p++;
|
|
v = (uae_s32)(uae_s16)val;
|
|
break;
|
|
}
|
|
case CT_ABSOLUTE_LONG:
|
|
{
|
|
uae_u32 val;
|
|
val = (*p++) << 24;
|
|
val |= (*p++) << 16;
|
|
val |= (*p++) << 8;
|
|
val |= *p++;
|
|
v = val;
|
|
if ((val & addressing_mask) < 0x8000) {
|
|
; // low memory
|
|
} else if ((val & ~addressing_mask) == ~addressing_mask && val >= 0xfff80000) {
|
|
; // high memory
|
|
} else if ((val & addressing_mask) < test_memory_addr || (val & addressing_mask) >= test_memory_addr + test_memory_size) {
|
|
end_test();
|
|
printf("restore_rel CT_ABSOLUTE_LONG outside of test memory! %08x\n", v);
|
|
endinfo();
|
|
exit(0);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
*vp = v;
|
|
return p;
|
|
}
|
|
|
|
static void validate_mode(uae_u8 mode, uae_u8 v)
|
|
{
|
|
if ((mode & CT_DATA_MASK) != v) {
|
|
end_test();
|
|
printf("CT_MEMWRITE expected but got %02X\n", mode);
|
|
endinfo();
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
static uae_u8 *get_memory_addr(uae_u8 *p, uae_u8 **addrp)
|
|
{
|
|
uae_u8 v = *p++;
|
|
switch(v & CT_SIZE_MASK)
|
|
{
|
|
case CT_ABSOLUTE_WORD:
|
|
{
|
|
uae_u16 val;
|
|
val = (*p++) << 8;
|
|
val |= *p++;
|
|
uae_u8 *addr;
|
|
uae_s16 offset = (uae_s16)val;
|
|
if (offset < 0) {
|
|
addr = high_memory + 32768 + offset;
|
|
} else {
|
|
addr = low_memory + offset;
|
|
}
|
|
validate_mode(p[0], CT_MEMWRITE);
|
|
*addrp = addr;
|
|
return p;
|
|
}
|
|
case CT_ABSOLUTE_LONG:
|
|
{
|
|
uae_u32 val;
|
|
val = (*p++) << 24;
|
|
val |= (*p++) << 16;
|
|
val |= (*p++) << 8;
|
|
val |= *p++;
|
|
if (val < test_memory_addr || val >= test_memory_addr + test_memory_size) {
|
|
end_test();
|
|
printf("get_memory_addr CT_ABSOLUTE_LONG outside of test memory! %08x\n", val);
|
|
endinfo();
|
|
exit(0);
|
|
}
|
|
#ifdef _MSC_VER
|
|
uae_u8 *addr = test_memory + (val - test_memory_addr);
|
|
#else
|
|
uae_u8 *addr = (uae_u8 *)val;
|
|
#endif
|
|
validate_mode(p[0], CT_MEMWRITE);
|
|
*addrp = addr;
|
|
return p;
|
|
}
|
|
case CT_RELATIVE_START_WORD:
|
|
{
|
|
uae_u16 val;
|
|
val = (*p++) << 8;
|
|
val |= *p++;
|
|
uae_s16 offset = (uae_s16)val;
|
|
uae_u8 *addr = opcode_memory + offset;
|
|
validate_mode(p[0], CT_MEMWRITE);
|
|
*addrp = addr;
|
|
return p;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
end_test();
|
|
printf("get_memory_addr unknown size %02x\n", v);
|
|
endinfo();
|
|
exit(0);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void tomem(uae_u8 *p, uae_u32 v, uae_u32 oldv, int size, int storedata)
|
|
{
|
|
if (storedata) {
|
|
struct accesshistory *ah = &ahist[ahcnt++];
|
|
ah->oldval = oldv;
|
|
ah->val = v;
|
|
ah->size = size;
|
|
ah->addr = p;
|
|
}
|
|
switch (size)
|
|
{
|
|
case 0:
|
|
p[0] = (uae_u8)v;
|
|
break;
|
|
case 1:
|
|
p[0] = (uae_u8)(v >> 8);
|
|
p[1] = (uae_u8)(v >> 0);
|
|
break;
|
|
case 2:
|
|
p[0] = (uae_u8)(v >> 24);
|
|
p[1] = (uae_u8)(v >> 16);
|
|
p[2] = (uae_u8)(v >> 8);
|
|
p[3] = (uae_u8)(v >> 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void restoreahist(void)
|
|
{
|
|
for (int i = ahcnt - 1; i >= 0; i--) {
|
|
struct accesshistory *ah = &ahist[ahcnt];
|
|
tomem(ah->addr, ah->oldval, 0, ah->size, 0);
|
|
}
|
|
ahcnt = 0;
|
|
}
|
|
|
|
|
|
static uae_u8 *restore_memory(uae_u8 *p, int storedata)
|
|
{
|
|
uae_u8 v = *p;
|
|
switch (v & CT_SIZE_MASK)
|
|
{
|
|
case CT_ABSOLUTE_WORD:
|
|
{
|
|
uae_u8 *addr;
|
|
int size;
|
|
p = get_memory_addr(p, &addr);
|
|
uae_u32 mv = 0;
|
|
uae_u32 oldv = 0;
|
|
p = restore_value(p, &oldv, &size);
|
|
p = restore_value(p, &mv, &size);
|
|
tomem(addr, mv, oldv, size, storedata);
|
|
return p;
|
|
}
|
|
case CT_ABSOLUTE_LONG:
|
|
{
|
|
uae_u8 *addr;
|
|
int size;
|
|
p = get_memory_addr(p, &addr);
|
|
uae_u32 mv = 0;
|
|
uae_u32 oldv = 0;
|
|
p = restore_value(p, &oldv, &size);
|
|
p = restore_value(p, &mv, &size);
|
|
tomem(addr, mv, oldv, size, storedata);
|
|
return p;
|
|
}
|
|
}
|
|
if ((v & CT_DATA_MASK) == CT_MEMWRITES) {
|
|
switch (v & CT_SIZE_MASK)
|
|
{
|
|
case CT_PC_BYTES:
|
|
{
|
|
p++;
|
|
uae_u8 *addr = opcode_memory;
|
|
uae_u8 v = *p++;
|
|
addr += v >> 5;
|
|
v &= 31;
|
|
if (v == 0)
|
|
v = 32;
|
|
memcpy(addr, p, v);
|
|
p += v;
|
|
break;
|
|
}
|
|
default:
|
|
end_test();
|
|
printf("Unknown restore_memory type!?\n");
|
|
endinfo();
|
|
exit(0);
|
|
break;
|
|
}
|
|
} else {
|
|
switch (v & CT_SIZE_MASK)
|
|
{
|
|
case CT_RELATIVE_START_WORD:
|
|
{
|
|
uae_u8 *addr;
|
|
int size;
|
|
p = get_memory_addr(p, &addr);
|
|
uae_u32 mv = 0, oldv = 0;
|
|
p = restore_value(p, &oldv, &size);
|
|
p = restore_value(p, &mv, &size);
|
|
tomem(addr, mv, oldv, size, storedata);
|
|
return p;
|
|
}
|
|
default:
|
|
end_test();
|
|
printf("Unknown restore_memory type!?\n");
|
|
endinfo();
|
|
exit(0);
|
|
break;
|
|
}
|
|
}
|
|
return p;
|
|
}
|
|
|
|
static uae_u8 *restore_data(uae_u8 *p)
|
|
{
|
|
uae_u8 v = *p;
|
|
if (v & CT_END) {
|
|
end_test();
|
|
printf("Unexpected end bit!? offset %ld\n", p - test_data);
|
|
endinfo();
|
|
exit(0);
|
|
}
|
|
int mode = v & CT_DATA_MASK;
|
|
if (mode < CT_AREG + 8) {
|
|
int size;
|
|
if ((v & CT_SIZE_MASK) == CT_SIZE_FPU) {
|
|
p = restore_fpvalue(p, ®s.fpuregs[mode]);
|
|
} else {
|
|
p = restore_value(p, ®s.regs[mode], &size);
|
|
}
|
|
} else if (mode == CT_SR) {
|
|
int size;
|
|
p = restore_value(p, ®s.sr, &size);
|
|
} else if (mode == CT_FPIAR) {
|
|
int size;
|
|
p = restore_value(p, ®s.fpiar, &size);
|
|
} else if (mode == CT_FPCR) {
|
|
int size;
|
|
p = restore_value(p, ®s.fpcr, &size);
|
|
} else if (mode == CT_FPSR) {
|
|
int size;
|
|
p = restore_value(p, ®s.fpsr, &size);
|
|
} else if (mode == CT_MEMWRITE) {
|
|
// if memwrite, store old data
|
|
p = restore_memory(p, 1);
|
|
} else if (mode == CT_MEMWRITES) {
|
|
p = restore_memory(p, 0);
|
|
} else {
|
|
end_test();
|
|
printf("Unexpected mode %02x\n", v);
|
|
endinfo();
|
|
exit(0);
|
|
}
|
|
return p;
|
|
}
|
|
|
|
int Disass68k(long addr, char *labelBuffer, char *opcodeBuffer, char *operandBuffer, char *commentBuffer);
|
|
void Disasm_SetCPUType(int CPU, int FPU);
|
|
|
|
static uae_u16 test_sr;
|
|
static uae_u32 test_fpsr, test_fpcr;
|
|
|
|
static void addinfo(void)
|
|
{
|
|
if (infoadded)
|
|
return;
|
|
infoadded = 1;
|
|
if (!dooutput)
|
|
return;
|
|
sprintf(outbp, "%lu:", testcnt);
|
|
outbp += strlen(outbp);
|
|
uae_u8 *p = opcode_memory;
|
|
for (int i = 0; i < 32 * 2; i += 2) {
|
|
uae_u16 v = (p[i] << 8) |(p[i + 1]);
|
|
if (v == 0x4afc && i > 0)
|
|
break;
|
|
sprintf(outbp, " %04x", v);
|
|
outbp += strlen(outbp);
|
|
}
|
|
strcat(outbp, " ");
|
|
outbp += strlen(outbp);
|
|
|
|
Disasm_SetCPUType(0, 0);
|
|
char buf1[80], buf2[80], buf3[80], buf4[80];
|
|
Disass68k((long)opcode_memory, buf1, buf2, buf3, buf4);
|
|
sprintf(outbp, "%s %s\n", buf2, buf3);
|
|
outbp += strlen(outbp);
|
|
}
|
|
|
|
static void out_regs(struct registers *r, int before)
|
|
{
|
|
for (int i = 0; i < 16; i++) {
|
|
if (i > 0 && (i % 4) == 0) {
|
|
strcat(outbp, "\n");
|
|
} else if ((i % 8) != 0) {
|
|
strcat(outbp, " ");
|
|
}
|
|
outbp += strlen(outbp);
|
|
sprintf(outbp, "%c%d:%c%08lx", i < 8 ? 'D' : 'A', i & 7, test_regs.regs[i] != regs.regs[i] ? '*' : ' ', r->regs[i]);
|
|
outbp += strlen(outbp);
|
|
}
|
|
strcat(outbp, "\n");
|
|
outbp += strlen(outbp);
|
|
sprintf(outbp, "SR:%c%04x PC: %08lx ISP: %08lx MSP: %08lx\n", test_regs.sr != test_sr ? '*' : ' ', before ? test_sr : r->sr, r->pc, r->ssp, r->msp);
|
|
outbp += strlen(outbp);
|
|
uae_u16 s = before ? test_sr : r->sr;
|
|
uae_u16 s1 = test_regs.sr;
|
|
uae_u16 s2 = test_sr;
|
|
sprintf(outbp, "T%c%d S%c%d X%c%d N%c%d Z%c%d V%c%d C%c%d",
|
|
(s1 & 0x8000) != (s2 & 0x8000) ? '*' : '=', (s & 0x8000) != 0,
|
|
(s1 & 0x2000) != (s2 & 0x2000) ? '*' : '=', (s & 0x2000) != 0,
|
|
(s1 & 0x10) != (s2 & 0x10) ? '*' : '=', (s & 0x10) != 0,
|
|
(s1 & 0x08) != (s2 & 0x08) ? '*' : '=', (s & 0x08) != 0,
|
|
(s1 & 0x04) != (s2 & 0x04) ? '*' : '=', (s & 0x04) != 0,
|
|
(s1 & 0x02) != (s2 & 0x02) ? '*' : '=', (s & 0x02) != 0,
|
|
(s1 & 0x01) != (s2 & 0x01) ? '*' : '=', (s & 0x01) != 0);
|
|
outbp += strlen(outbp);
|
|
|
|
if (!fpu_model) {
|
|
strcat(outbp, "\n");
|
|
outbp += strlen(outbp);
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < 8; i++) {
|
|
if ((i % 2) == 0) {
|
|
strcat(outbp, "\n");
|
|
}
|
|
else if ((i % 4) != 0) {
|
|
strcat(outbp, " ");
|
|
}
|
|
outbp += strlen(outbp);
|
|
struct fpureg *f = &r->fpuregs[i];
|
|
void *f1 = ®s.fpuregs[i];
|
|
void *f2 = &test_regs.fpuregs[i];
|
|
sprintf(outbp, "FP%d:%c%04x-%08lx%08lx %f",
|
|
i,
|
|
memcmp(f1, f2, 12) ? '*' : ' ',
|
|
f->exp, f->m[0], f->m[1],
|
|
*((long double*)f));
|
|
outbp += strlen(outbp);
|
|
}
|
|
sprintf(outbp, "\nFPSR:%c%08lx FPCR:%c%08lx FPIAR:%c%08lx\n",
|
|
test_fpsr != test_regs.fpsr ? '*' : ' ', before ? test_fpsr : r->fpsr,
|
|
test_fpcr != test_regs.fpcr ? '*' : ' ', before ? test_fpcr : r->fpcr,
|
|
regs.fpiar != test_regs.fpiar ? '*' : ' ', r->fpiar);
|
|
|
|
outbp += strlen(outbp);
|
|
|
|
}
|
|
|
|
static uae_u8 *validate_test(uae_u8 *p, int ignore_errors, int ignore_sr)
|
|
{
|
|
uae_u8 regs_changed[16] = { 0 };
|
|
uae_u8 regs_fpuchanged[8] = { 0 };
|
|
uae_u8 sr_changed = 0, pc_changed = 0;
|
|
uae_u8 fpiar_changed = 0, fpsr_changed = 0, fpcr_changed = 0;
|
|
int exc = -1;
|
|
|
|
for (int i = 0; i < 16; i++) {
|
|
if (last_registers.regs[i] != test_regs.regs[i]) {
|
|
regs_changed[i] = 1;
|
|
}
|
|
}
|
|
if (last_registers.sr != test_regs.sr) {
|
|
sr_changed = 1;
|
|
}
|
|
if (last_registers.pc != test_regs.pc) {
|
|
pc_changed = 1;
|
|
}
|
|
if (fpu_model) {
|
|
for (int i = 0; i < 8; i++) {
|
|
if (memcmp(&last_registers.fpuregs[i], &test_regs.fpuregs[i], 12)) {
|
|
regs_fpuchanged[i] = 1;
|
|
}
|
|
}
|
|
if (last_registers.fpsr != test_regs.fpsr) {
|
|
fpsr_changed = 1;
|
|
}
|
|
if (last_registers.fpcr != test_regs.fpcr) {
|
|
fpcr_changed = 1;
|
|
}
|
|
if (last_registers.fpiar != test_regs.fpiar) {
|
|
fpiar_changed = 1;
|
|
}
|
|
}
|
|
|
|
if (*p == CT_END_SKIP)
|
|
return p + 1;
|
|
|
|
for (;;) {
|
|
uae_u8 v = *p;
|
|
if (v & CT_END) {
|
|
exc = v & CT_EXCEPTION_MASK;
|
|
int cpuexc = test_regs.exc & 65535;
|
|
p++;
|
|
if ((v & CT_END_INIT) == CT_END_INIT) {
|
|
end_test();
|
|
printf("Unexpected CT_END_INIT %02x %08lx\n", v, p - test_data);
|
|
endinfo();
|
|
exit(0);
|
|
}
|
|
if (exc == 1) {
|
|
end_test();
|
|
printf("Invalid exception ID %02x\n", exc);
|
|
endinfo();
|
|
exit(0);
|
|
}
|
|
if (ignore_errors)
|
|
break;
|
|
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 %08lx but got %08lx\n", last_registers.pc, test_regs.pc);
|
|
outbp += strlen(outbp);
|
|
errors++;
|
|
}
|
|
break;
|
|
}
|
|
if (exc != cpuexc) {
|
|
addinfo();
|
|
if (dooutput) {
|
|
if (cpuexc == 4 && last_registers.pc == test_regs.pc) {
|
|
sprintf(outbp, "Exception ID: expected %d but got no exception.\n", exc);
|
|
} else {
|
|
sprintf(outbp, "Exception ID: expected %d but got %d\n", exc, cpuexc);
|
|
}
|
|
}
|
|
outbp += strlen(outbp);
|
|
errors++;
|
|
}
|
|
break;
|
|
}
|
|
int mode = v & CT_DATA_MASK;
|
|
if (mode < CT_AREG + 8) {
|
|
uae_u32 val = last_registers.regs[mode];
|
|
int size;
|
|
p = restore_value(p, &val, &size);
|
|
if (val != test_regs.regs[mode] && !ignore_errors) {
|
|
addinfo();
|
|
if (dooutput) {
|
|
sprintf(outbp, "%c%d: expected %08lx but got %08lx\n", mode < CT_AREG ? 'D' : 'A', mode & 7, val, test_regs.regs[mode]);
|
|
outbp += strlen(outbp);
|
|
}
|
|
errors++;
|
|
}
|
|
regs_changed[mode] = 0;
|
|
last_registers.regs[mode] = val;
|
|
} else if (mode == CT_SR) {
|
|
uae_u32 val = last_registers.sr;
|
|
int size;
|
|
p = restore_value(p, &val, &size);
|
|
if ((val & sr_undefined_mask) != (test_regs.sr & sr_undefined_mask) && !ignore_errors && !ignore_sr) {
|
|
addinfo();
|
|
if (dooutput) {
|
|
sprintf(outbp, "SR: expected %04x -> %04x but got %04x\n", test_sr, val, test_regs.sr);
|
|
outbp += strlen(outbp);
|
|
}
|
|
errors++;
|
|
}
|
|
sr_changed = 0;
|
|
last_registers.sr = val;
|
|
} else if (mode == CT_PC) {
|
|
uae_u32 val = last_registers.pc;
|
|
p = restore_rel(p, &val);
|
|
pc_changed = 0;
|
|
last_registers.pc = val;
|
|
} else if (mode == CT_FPCR) {
|
|
uae_u32 val = last_registers.fpcr;
|
|
int size;
|
|
p = restore_value(p, &val, &size);
|
|
if (val != test_regs.fpcr && !ignore_errors) {
|
|
addinfo();
|
|
if (dooutput) {
|
|
sprintf(outbp, "FPCR: expected %08lx -> %08lx but got %08lx\n", test_fpcr, val, test_regs.fpcr);
|
|
outbp += strlen(outbp);
|
|
}
|
|
errors++;
|
|
}
|
|
fpcr_changed = 0;
|
|
last_registers.fpcr = val;
|
|
} else if (mode == CT_FPSR) {
|
|
uae_u32 val = last_registers.fpsr;
|
|
int size;
|
|
p = restore_value(p, &val, &size);
|
|
if (val != test_regs.fpsr && !ignore_errors) {
|
|
addinfo();
|
|
if (dooutput) {
|
|
sprintf(outbp, "FPSR: expected %08lx -> %08lx but got %08lx\n", test_fpsr, val, test_regs.fpsr);
|
|
outbp += strlen(outbp);
|
|
}
|
|
errors++;
|
|
}
|
|
fpsr_changed = 0;
|
|
last_registers.fpsr = val;
|
|
} else if (mode == CT_FPIAR) {
|
|
uae_u32 val = last_registers.fpiar;
|
|
p = restore_rel(p, &val);
|
|
if (val != test_regs.fpiar && !ignore_errors) {
|
|
addinfo();
|
|
if (dooutput) {
|
|
sprintf(outbp, "FPIAR: expected %08x but got %08x\n", val, test_regs.fpiar);
|
|
outbp += strlen(outbp);
|
|
}
|
|
errors++;
|
|
}
|
|
fpiar_changed = 0;
|
|
last_registers.fpiar = val;
|
|
|
|
} else if (mode == CT_MEMWRITES) {
|
|
p = restore_memory(p, 0);
|
|
} else if (mode == CT_MEMWRITE) {
|
|
uae_u8 *addr;
|
|
uae_u32 val = 0, mval = 0, oldval = 0;
|
|
int size;
|
|
p = get_memory_addr(p, &addr);
|
|
p = restore_value(p, &oldval, &size);
|
|
p = restore_value(p, &val, &size);
|
|
switch(size)
|
|
{
|
|
case 0:
|
|
mval = addr[0];
|
|
if (mval != val && !ignore_errors) {
|
|
addinfo();
|
|
if (dooutput) {
|
|
sprintf(outbp, "Memory byte write: address %08lx, expected %02x but got %02x\n", (uae_u32)addr, val, mval);
|
|
outbp += strlen(outbp);
|
|
}
|
|
errors++;
|
|
}
|
|
addr[0] = oldval;
|
|
break;
|
|
case 1:
|
|
mval = (addr[0] << 8) | (addr[1]);
|
|
if (mval != val && !ignore_errors) {
|
|
addinfo();
|
|
if (dooutput) {
|
|
sprintf(outbp, "Memory word write: address %08lx, expected %04x but got %04x\n", (uae_u32)addr, val, mval);
|
|
outbp += strlen(outbp);
|
|
}
|
|
errors++;
|
|
}
|
|
addr[0] = oldval >> 8;
|
|
addr[1] = oldval;
|
|
break;
|
|
case 2:
|
|
mval = gl(addr);
|
|
if (mval != val && !ignore_errors) {
|
|
addinfo();
|
|
if (dooutput) {
|
|
sprintf(outbp, "Memory long write: address %08lx, expected %08lx but got %08x\n", (uae_u32)addr, val, mval);
|
|
outbp += strlen(outbp);
|
|
}
|
|
errors++;
|
|
}
|
|
pl(addr, oldval);
|
|
break;
|
|
}
|
|
} else {
|
|
end_test();
|
|
printf("Unknown test data %02x\n", v);
|
|
exit(0);
|
|
}
|
|
}
|
|
if (!ignore_errors) {
|
|
for (int i = 0; i < 16; i++) {
|
|
if (regs_changed[i]) {
|
|
addinfo();
|
|
if (dooutput) {
|
|
sprintf(outbp, "%c%d: modified %08lx -> %08lx but expected no modifications\n", i < 8 ? 'D' : 'A', i & 7, last_registers.regs[i], test_regs.regs[i]);
|
|
outbp += strlen(outbp);
|
|
}
|
|
errors++;
|
|
}
|
|
}
|
|
if (sr_changed) {
|
|
addinfo();
|
|
if (dooutput) {
|
|
sprintf(outbp, "SR: modified %04x -> %04x but expected no modifications\n", last_registers.sr, test_regs.sr);
|
|
outbp += strlen(outbp);
|
|
}
|
|
errors++;
|
|
}
|
|
for (int i = 0; i < 8; i++) {
|
|
if (regs_fpuchanged[i]) {
|
|
addinfo();
|
|
if (dooutput) {
|
|
sprintf(outbp, "FP%d: modified %f -> %f but expected no modifications\n", i,
|
|
*((long double *)(&last_registers.fpuregs[i])), *((long double *)(&test_regs.fpuregs[i])));
|
|
outbp += strlen(outbp);
|
|
}
|
|
errors++;
|
|
}
|
|
}
|
|
if (fpsr_changed) {
|
|
addinfo();
|
|
if (dooutput) {
|
|
sprintf(outbp, "FPSR: modified %08x -> %08x but expected no modifications\n", last_registers.fpsr, test_regs.fpsr);
|
|
outbp += strlen(outbp);
|
|
}
|
|
errors++;
|
|
}
|
|
if (fpcr_changed) {
|
|
addinfo();
|
|
if (dooutput) {
|
|
sprintf(outbp, "FPCR: modified %08x -> %08x but expected no modifications\n", last_registers.fpcr, test_regs.fpcr);
|
|
outbp += strlen(outbp);
|
|
}
|
|
errors++;
|
|
}
|
|
if (fpiar_changed) {
|
|
addinfo();
|
|
if (dooutput) {
|
|
sprintf(outbp, "FPIAR: modified %08x -> %08x but expected no modifications\n", last_registers.fpiar, test_regs.fpiar);
|
|
outbp += strlen(outbp);
|
|
}
|
|
errors++;
|
|
}
|
|
}
|
|
if (errors && dooutput) {
|
|
addinfo();
|
|
if (!fpu_model) {
|
|
strcat(outbp, "Registers before:\n");
|
|
outbp += strlen(outbp);
|
|
}
|
|
out_regs(®s, 1);
|
|
if (!fpu_model) {
|
|
strcat(outbp, "Registers after:\n");
|
|
outbp += strlen(outbp);
|
|
}
|
|
out_regs(&test_regs, 0);
|
|
if (exc > 1) {
|
|
sprintf(outbp, "OK: Generated exception %d\n", exc);
|
|
outbp += strlen(outbp);
|
|
if (exc == 3 && cpu_lvl == 0) {
|
|
sprintf(outbp, "RW=%d IN=%d FC=%d\n",
|
|
((test_regs.exc >> (16 + 4)) & 1),
|
|
((test_regs.exc >> (16 + 3)) & 1),
|
|
((test_regs.exc >> (16 + 0)) & 7));
|
|
outbp += strlen(outbp);
|
|
}
|
|
} else if (exc == 0 && (test_regs.exc & 65535) == 4) {
|
|
sprintf(outbp, "OK: No exception generated\n");
|
|
outbp += strlen(outbp);
|
|
}
|
|
}
|
|
return p;
|
|
}
|
|
|
|
static void process_test(uae_u8 *p)
|
|
{
|
|
outbp = outbuffer;
|
|
outbp[0] = 0;
|
|
infoadded = 0;
|
|
errors = 0;
|
|
|
|
memset(®s, 0, sizeof(struct registers));
|
|
|
|
start_test();
|
|
|
|
ahcnt = 0;
|
|
|
|
for (;;) {
|
|
|
|
#ifdef _MSC_VER
|
|
outbp = outbuffer;
|
|
#endif
|
|
|
|
for (;;) {
|
|
uae_u8 v = *p;
|
|
if (v == CT_END_INIT || v == CT_END_FINISH)
|
|
break;
|
|
p = restore_data(p);
|
|
}
|
|
if (*p == CT_END_FINISH)
|
|
break;
|
|
p++;
|
|
|
|
xmemcpy(&last_registers, ®s, sizeof(struct registers));
|
|
|
|
int fpumode = fpu_model && (opcode_memory[0] & 0xf0) == 0xf0;
|
|
|
|
if (cpu_lvl >= 2)
|
|
flushcache();
|
|
|
|
uae_u32 pc = opcode_memory_addr;
|
|
|
|
int extraccr = 0;
|
|
|
|
uae_u32 last_pc = opcode_memory_addr;
|
|
uae_u32 last_fpiar = opcode_memory_addr;
|
|
|
|
for (;;) {
|
|
uae_u16 sr_mask = 0;
|
|
|
|
if (extraccr & 1)
|
|
sr_mask |= 0x2000; // S
|
|
if (extraccr & 2)
|
|
sr_mask |= 0x4000; // T0
|
|
if (extraccr & 4)
|
|
sr_mask |= 0x8000; // T1
|
|
if (extraccr & 8)
|
|
sr_mask |= 0x1000; // M
|
|
|
|
int ccrmax = fpumode ? 256 : 32;
|
|
for (int ccr = 0; ccr < ccrmax; ccr++) {
|
|
|
|
regs.ssp = test_memory_addr + test_memory_size - 0x80;
|
|
regs.msp = test_memory_addr + test_memory_size;
|
|
regs.pc = opcode_memory_addr;
|
|
regs.fpiar = opcode_memory_addr;
|
|
|
|
xmemcpy(&test_regs, ®s, sizeof(struct registers));
|
|
|
|
test_regs.sr = ccr | sr_mask;
|
|
test_sr = test_regs.sr;
|
|
if (fpumode) {
|
|
test_regs.fpsr = (ccr & 15) << 24;
|
|
test_regs.fpcr = (ccr >> 4) << 4;
|
|
test_fpsr = test_regs.fpsr;
|
|
test_fpcr = test_regs.fpcr;
|
|
}
|
|
|
|
|
|
if ((*p) == CT_END_SKIP) {
|
|
|
|
p++;
|
|
|
|
} else {
|
|
|
|
int ignore_errors = 0;
|
|
int ignore_sr = 0;
|
|
|
|
if ((ccr_mask & ccr) || (ccr == 0)) {
|
|
|
|
if (cpu_lvl == 1) {
|
|
execute_test010(&test_regs);
|
|
} else if (cpu_lvl == 2) {
|
|
if (fpu_model)
|
|
execute_testfpu(&test_regs);
|
|
else
|
|
execute_test020(&test_regs);
|
|
} else {
|
|
execute_test000(&test_regs);
|
|
}
|
|
|
|
if (ccr_mask == 0 && ccr == 0)
|
|
ignore_sr = 1;
|
|
|
|
} else {
|
|
|
|
test_regs.sr = test_sr;
|
|
ignore_errors = 1;
|
|
ignore_sr = 1;
|
|
|
|
}
|
|
|
|
last_registers.pc = last_pc;
|
|
last_registers.fpiar = last_fpiar;
|
|
|
|
p = validate_test(p, ignore_errors, ignore_sr);
|
|
|
|
last_pc = last_registers.pc;
|
|
last_fpiar = last_registers.fpiar;
|
|
|
|
}
|
|
|
|
testcnt++;
|
|
|
|
if (testexit()) {
|
|
end_test();
|
|
printf("\nAborted\n");
|
|
exit(0);
|
|
}
|
|
|
|
#if DONTSTOPONERROR == 0
|
|
if (quit || errors)
|
|
goto end;
|
|
#endif
|
|
}
|
|
|
|
if (*p == CT_END) {
|
|
p++;
|
|
break;
|
|
}
|
|
|
|
extraccr = *p++;
|
|
|
|
}
|
|
|
|
restoreahist();
|
|
|
|
}
|
|
|
|
end:
|
|
end_test();
|
|
|
|
if (infoadded) {
|
|
printf("\n");
|
|
printf(outbuffer);
|
|
}
|
|
|
|
}
|
|
|
|
static void freestuff(void)
|
|
{
|
|
if (test_memory && test_memory_addr)
|
|
free_absolute(test_memory_addr, test_memory_size);
|
|
}
|
|
|
|
|
|
static int test_mnemo(const char *path, const char *opcode)
|
|
{
|
|
int size;
|
|
uae_u8 data[4] = { 0 };
|
|
uae_u32 v;
|
|
char fname[256], tfname[256];
|
|
int filecnt = 1;
|
|
uae_u32 starttimeid;
|
|
|
|
errors = 0;
|
|
quit = 0;
|
|
|
|
sprintf(tfname, "%s%s/0000.dat", path, opcode);
|
|
FILE *f = fopen(tfname, "rb");
|
|
if (!f) {
|
|
printf("Couldn't open '%s'\n", tfname);
|
|
exit(0);
|
|
}
|
|
int header_size = 32;
|
|
fread(data, 1, 4, f);
|
|
v = gl(data);
|
|
if (v != 0x00000001) {
|
|
printf("Invalid test data file (header)\n");
|
|
exit(0);
|
|
}
|
|
fread(data, 1, 4, f);
|
|
starttimeid = gl(data);
|
|
fread(data, 1, 4, f);
|
|
hmem_rom = gl(data) >> 16;
|
|
lmem_rom = gl(data) & 65535;
|
|
fread(data, 1, 4, f);
|
|
test_memory_addr = gl(data);
|
|
fread(data, 1, 4, f);
|
|
test_memory_size = gl(data);
|
|
fread(data, 1, 4, f);
|
|
opcode_memory_addr = gl(data) + test_memory_addr;
|
|
fread(data, 1, 4, f);
|
|
cpu_lvl = gl(data) >> 16;
|
|
sr_undefined_mask = gl(data);
|
|
fread(data, 1, 4, f);
|
|
fpu_model = gl(data);
|
|
fread(inst_name, 1, sizeof(inst_name) - 1, f);
|
|
inst_name[sizeof(inst_name) - 1] = 0;
|
|
|
|
if (!check_undefined_sr) {
|
|
sr_undefined_mask = ~sr_undefined_mask;
|
|
} else {
|
|
sr_undefined_mask = 0xffff;
|
|
}
|
|
|
|
if (!absallocated) {
|
|
test_memory = allocate_absolute(test_memory_addr, test_memory_size);
|
|
if (!test_memory) {
|
|
printf("Couldn't allocate tmem area %08lx-%08lx\n", (uae_u32)test_memory_addr, test_memory_size);
|
|
exit(0);
|
|
}
|
|
absallocated = test_memory;
|
|
}
|
|
if (absallocated != test_memory) {
|
|
printf("tmem area changed!?\n");
|
|
exit(0);
|
|
}
|
|
|
|
opcode_memory = test_memory + (opcode_memory_addr - test_memory_addr);
|
|
|
|
size = test_memory_size;
|
|
load_file(path, "tmem.dat", test_memory, &size);
|
|
if (size != test_memory_size) {
|
|
printf("tmem.dat size mismatch\n");
|
|
exit(0);
|
|
}
|
|
|
|
printf("%s:\n", inst_name);
|
|
|
|
testcnt = 0;
|
|
|
|
for (;;) {
|
|
printf("%s. %lu...\n", tfname, testcnt);
|
|
|
|
sprintf(tfname, "%s%s/%04ld.dat", path, opcode, filecnt);
|
|
FILE *f = fopen(tfname, "rb");
|
|
if (!f)
|
|
break;
|
|
fread(data, 1, 4, f);
|
|
if (gl(data) != 0x00000001) {
|
|
printf("Invalid test data file (header)\n");
|
|
exit(0);
|
|
}
|
|
fread(data, 1, 4, f);
|
|
if (gl(data) != starttimeid) {
|
|
printf("Test data file header mismatch\n");
|
|
exit(0);
|
|
}
|
|
fseek(f, 0, SEEK_END);
|
|
test_data_size = ftell(f);
|
|
fseek(f, 16, SEEK_SET);
|
|
test_data_size -= 16;
|
|
if (test_data_size <= 0)
|
|
break;
|
|
test_data = calloc(1, test_data_size);
|
|
if (!test_data) {
|
|
printf("Couldn't allocate memory for '%s', %lu bytes\n", tfname, test_memory_size);
|
|
exit(0);
|
|
}
|
|
if (fread(test_data, 1, test_data_size, f) != test_data_size) {
|
|
printf("Couldn't read '%s'\n", fname);
|
|
break;
|
|
}
|
|
fclose(f);
|
|
if (test_data[test_data_size - 1] != CT_END_FINISH) {
|
|
printf("Invalid test data file (footer)\n");
|
|
exit(0);
|
|
}
|
|
|
|
process_test(test_data);
|
|
|
|
if (errors || quit)
|
|
break;
|
|
|
|
free(test_data);
|
|
filecnt++;
|
|
}
|
|
|
|
if (!errors && !quit) {
|
|
printf("All tests complete (total %lu).\n", testcnt);
|
|
}
|
|
|
|
return errors || quit;
|
|
}
|
|
|
|
static int getparamval(const char *p)
|
|
{
|
|
if (strlen(p) > 2 && p[0] == '0' && toupper(p[1]) == 'X') {
|
|
char *endptr;
|
|
return strtol(p + 2, &endptr, 16);
|
|
} else {
|
|
return atol(p);
|
|
}
|
|
}
|
|
|
|
static char path[256];
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int size;
|
|
char opcode[16];
|
|
int stop_on_error = 1;
|
|
|
|
atexit(freestuff);
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
char *params[] = { "", "or.w", "", NULL };
|
|
argv = params;
|
|
argc = 3;
|
|
|
|
strcpy(path, "C:\\projects\\winuae\\src\\cputest\\data\\");
|
|
|
|
low_memory = calloc(1, 32768);
|
|
high_memory = calloc(1, 32768);
|
|
vbr_zero = calloc(1, 1024);
|
|
|
|
cpu_lvl = 0;
|
|
#else
|
|
|
|
#define _stricmp stricmp
|
|
|
|
if (strlen(argv[1]) >= sizeof(opcode) - 1)
|
|
return 0;
|
|
|
|
strcpy(path, "data/");
|
|
|
|
low_memory = (uae_u8 *)0;
|
|
high_memory = (uae_u8 *)0xffff8000;
|
|
|
|
cpu_lvl = get_cpu_model();
|
|
#endif
|
|
|
|
if (argc < 2) {
|
|
printf("cputest <all/mnemonic> (<start mnemonic>) (continue)\n");
|
|
printf("mnemonic = test single mnemonic\n");
|
|
printf("all = test all\n");
|
|
printf("all <mnemonic> = test all, starting from <mnemonic>\n");
|
|
printf("continue = don't stop on error (all mode only)\n");
|
|
printf("ccrmask = ignore CCR bits that are not set.\n");
|
|
return 0;
|
|
}
|
|
|
|
sprintf(path + strlen(path), "%lu/", 68000 + cpu_lvl * 10);
|
|
|
|
strcpy(opcode, argv[1]);
|
|
|
|
check_undefined_sr = 1;
|
|
ccr_mask = 0xff;
|
|
for (int i = 1; i < argc; i++) {
|
|
char *s = argv[i];
|
|
char *next = i + 1 < argc ? argv[i + 1] : NULL;
|
|
if (!_stricmp(s, "continue")) {
|
|
stop_on_error = 0;
|
|
} else if (!_stricmp(s, "noundefined")) {
|
|
check_undefined_sr = 0;
|
|
} else if (!_stricmp(s, "ccrmask")) {
|
|
ccr_mask = 0;
|
|
if (next) {
|
|
ccr_mask = getparamval(next);
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
size = 32768;
|
|
load_file(path, "lmem.dat", low_memory_temp, &size);
|
|
size = 32768;
|
|
load_file(path, "hmem.dat", high_memory_temp, &size);
|
|
|
|
if (!_stricmp(opcode, "all")) {
|
|
DIR *d = opendir(path);
|
|
if (!d) {
|
|
printf("Couldn't list directory '%s'\n", path);
|
|
return 0;
|
|
}
|
|
#define MAX_FILE_LEN 128
|
|
#define MAX_MNEMOS 256
|
|
char *dirs = calloc(MAX_MNEMOS, MAX_FILE_LEN);
|
|
int diroff = 0;
|
|
if (!dirs)
|
|
return 0;
|
|
|
|
for (;;) {
|
|
struct dirent *dr = readdir(d);
|
|
if (!dr)
|
|
break;
|
|
if (dr->d_type == DT_DIR && dr->d_name[0] != '.') {
|
|
strcpy(dirs + diroff, dr->d_name);
|
|
diroff += MAX_FILE_LEN;
|
|
if (diroff >= MAX_FILE_LEN * MAX_MNEMOS) {
|
|
printf("too many directories!?\n");
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
closedir(d);
|
|
|
|
for (int i = 0; i < diroff; i += MAX_FILE_LEN) {
|
|
for (int j = i + MAX_FILE_LEN; j < diroff; j += MAX_FILE_LEN) {
|
|
if (_stricmp(dirs + i, dirs + j) > 0) {
|
|
char tmp[MAX_FILE_LEN];
|
|
strcpy(tmp, dirs + j);
|
|
strcpy(dirs + j, dirs + i);
|
|
strcpy(dirs + i, tmp);
|
|
}
|
|
}
|
|
}
|
|
|
|
int first = 0;
|
|
if (argc >= 3) {
|
|
for (int i = 0; i < diroff; i += MAX_FILE_LEN) {
|
|
if (!_stricmp(dirs + i, argv[2])) {
|
|
first = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
for (int i = first; i < diroff; i += MAX_FILE_LEN) {
|
|
if (test_mnemo(path, dirs + i)) {
|
|
if (stop_on_error)
|
|
break;
|
|
}
|
|
}
|
|
|
|
free(dirs);
|
|
|
|
} else {
|
|
test_mnemo(path, opcode);
|
|
}
|
|
}
|