]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
CPU tester cycle counting support, multi test set support and more.
authorToni Wilen <twilen@winuae.net>
Sat, 18 Jan 2020 09:55:50 +0000 (11:55 +0200)
committerToni Wilen <twilen@winuae.net>
Sat, 18 Jan 2020 09:55:50 +0000 (11:55 +0200)
cputest.cpp
cputest/amiga.S
cputest/asm.S
cputest/cputest_defines.h
cputest/cputestgen.ini
cputest/inflate.S
cputest/main.c
cputest/readme.txt
gencpu.cpp
include/cputest.h
ini.cpp

index 838fc726cb91982395605a3214a67d954e7b4e00..e8464a08a455fe8e0b205cffd9ab146973e55e25 100644 (file)
@@ -57,6 +57,7 @@ static struct cputbl_data cpudatatbl[65536];
 
 struct regstruct regs;
 struct flag_struct regflags;
+int cpu_cycles;
 
 static int verbose = 1;
 static int feature_exception3_data = 0;
@@ -70,6 +71,7 @@ static int feature_test_rounds = 2;
 static int feature_flag_mode = 0;
 static int feature_usp = 0;
 static int feature_exception_vectors = 0;
+static int feature_interrupts = 0;
 static TCHAR *feature_instruction_size = NULL;
 static uae_u32 feature_addressing_modes[2];
 static int feature_gzip = 0;
@@ -153,6 +155,7 @@ static int test_memory_accessed;
 static uae_u16 extra_or, extra_and;
 static uae_u32 cur_registers[MAX_REGISTERS];
 static uae_u16 read_buffer_prev;
+static int interrupt_count;
 
 struct uae_prefs currprefs;
 
@@ -313,10 +316,20 @@ static void check_bus_error(uaecptr addr, int write, int fc)
        }
 }
 
+static void add_memory_cycles(int c)
+{
+       if (!testing_active)
+               return;
+       if (trace_store_pc != 0xffffffff)
+               return;
+       cpu_cycles += c * 4;
+}
+
 static uae_u8 get_ibyte_test(uaecptr addr)
 {
        check_bus_error(addr, 0, regs.s ? 5 : 1);
        uae_u8 *p = get_addr(addr, 1, 0);
+       add_memory_cycles(1);
        return *p;
 }
 
@@ -327,6 +340,7 @@ static uae_u16 get_iword_test(uaecptr addr)
                return (get_ibyte_test(addr + 0) << 8) | (get_ibyte_test(addr + 1) << 0);
        } else {
                uae_u8 *p = get_addr(addr, 2, 0);
+               add_memory_cycles(1);
                return (p[0] << 8) | (p[1]);
        }
 }
@@ -336,6 +350,7 @@ uae_u16 get_word_test_prefetch(int o)
        // no real prefetch
        if (cpu_lvl < 2)
                o -= 2;
+       add_memory_cycles(-1);
        regs.irc = get_iword_test(m68k_getpci() + o + 2);
        read_buffer_prev = regs.read_buffer;
        regs.read_buffer = regs.irc;
@@ -374,6 +389,7 @@ void put_byte_test(uaecptr addr, uae_u32 v)
        }
        regs.write_buffer = v;
        *p = v;
+       add_memory_cycles(1);
 }
 void put_word_test(uaecptr addr, uae_u32 v)
 {
@@ -401,6 +417,7 @@ void put_word_test(uaecptr addr, uae_u32 v)
                p[1] = v & 0xff;
        }
        regs.write_buffer = v;
+       add_memory_cycles(1);
 }
 void put_long_test(uaecptr addr, uae_u32 v)
 {
@@ -432,6 +449,7 @@ void put_long_test(uaecptr addr, uae_u32 v)
                p[1] = v >> 16;
                p[2] = v >> 8;
                p[3] = v >> 0;
+               add_memory_cycles(2);
        }
        regs.write_buffer = v;
 }
@@ -469,6 +487,7 @@ uae_u32 get_byte_test(uaecptr addr)
        uae_u8 *p = get_addr(addr, 1, 0);
        read_buffer_prev = regs.read_buffer;
        regs.read_buffer = *p;
+       add_memory_cycles(1);
        return *p;
 }
 uae_u32 get_word_test(uaecptr addr)
@@ -483,6 +502,7 @@ uae_u32 get_word_test(uaecptr addr)
        }
        read_buffer_prev = regs.read_buffer;
        regs.read_buffer = v;
+       add_memory_cycles(1);
        return v;
 }
 uae_u32 get_long_test(uaecptr addr)
@@ -501,6 +521,7 @@ uae_u32 get_long_test(uaecptr addr)
        } else {
                uae_u8 *p = get_addr(addr, 4, 0);
                v = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
+               add_memory_cycles(2);
        }
        read_buffer_prev = regs.read_buffer;
        regs.read_buffer = v;
@@ -641,10 +662,33 @@ bool mmu_op30(uaecptr pc, uae_u32 opcode, uae_u16 extra, uaecptr extraa)
        return true;
 }
 
+int is_cycle_ce(void)
+{
+       return 0;
+}
+
+void ipl_fetch(void)
+{
+}
+
+int intlev(void)
+{
+       return 0;
+}
+
+void do_cycles_test(int cycles)
+{
+       if (!testing_active)
+               return;
+       cpu_cycles += cycles;
+}
+
 uae_u32(*x_get_long)(uaecptr);
 uae_u32(*x_get_word)(uaecptr);
+uae_u32(*x_get_byte)(uaecptr);
 void (*x_put_long)(uaecptr, uae_u32);
 void (*x_put_word)(uaecptr, uae_u32);
+void (*x_put_byte)(uaecptr, uae_u32);
 
 uae_u32(*x_cp_get_long)(uaecptr);
 uae_u32(*x_cp_get_word)(uaecptr);
@@ -661,6 +705,31 @@ void (*x_do_cycles)(unsigned long);
 
 uae_u32(REGPARAM3 *x_cp_get_disp_ea_020)(uae_u32 base, int idx) REGPARAM;
 
+void m68k_do_rts_ce(void)
+{
+       uaecptr pc;
+       pc = x_get_word(m68k_areg(regs, 7)) << 16;
+       pc |= x_get_word(m68k_areg(regs, 7) + 2);
+       m68k_areg(regs, 7) += 4;
+       m68k_setpci(pc);
+}
+
+void m68k_do_bsr_ce(uaecptr oldpc, uae_s32 offset)
+{
+       m68k_areg(regs, 7) -= 4;
+       x_put_word(m68k_areg(regs, 7), oldpc >> 16);
+       x_put_word(m68k_areg(regs, 7) + 2, oldpc);
+       m68k_incpci(offset);
+}
+
+void m68k_do_jsr_ce(uaecptr oldpc, uaecptr dest)
+{
+       m68k_areg(regs, 7) -= 4;
+       x_put_word(m68k_areg(regs, 7), oldpc >> 16);
+       x_put_word(m68k_areg(regs, 7) + 2, oldpc);
+       m68k_setpci(dest);
+}
+
 static int SPCFLAG_TRACE, SPCFLAG_DOTRACE;
 
 uae_u32 get_disp_ea_test(uae_u32 base, uae_u32 dp)
@@ -823,6 +892,7 @@ static void doexcstack2(void)
 
        int noac = noaccesshistory;
        int ta = testing_active;
+       int cycs = cpu_cycles;
        noaccesshistory = 1;
        testing_active = -1;
 
@@ -881,6 +951,7 @@ static void doexcstack2(void)
        m68k_areg(regs, 7) = tmp;
        testing_active = ta;
        noaccesshistory = noac;
+       cpu_cycles = cycs;
 }
 
 static void doexcstack(void)
@@ -1558,7 +1629,8 @@ static void save_data(uae_u8 *dst, const TCHAR *dir)
                fwrite(data, 1, 4, f);
                pl(data, (uae_u32)starttime);
                fwrite(data, 1, 4, f);
-               pl(data, ((hmem_rom | (test_high_memory_start == 0xffffffff ? 0x8000 : 0x0000)) << 16) | (lmem_rom | (test_low_memory_start == 0xffffffff ? 0x8000 : 0x0000)));
+               pl(data, ((hmem_rom | (test_high_memory_start == 0xffffffff ? 0x8000 : 0x0000)) << 16) |
+                       (lmem_rom | (test_low_memory_start == 0xffffffff ? 0x8000 : 0x0000)));
                fwrite(data, 1, 4, f);
                pl(data, test_memory_start);
                fwrite(data, 1, 4, f);
@@ -1566,7 +1638,8 @@ static void save_data(uae_u8 *dst, const TCHAR *dir)
                fwrite(data, 1, 4, f);
                pl(data, opcode_memory_start);
                fwrite(data, 1, 4, f);
-               pl(data, (cpu_lvl << 16) | sr_undefined_mask | (addressing_mask == 0xffffffff ? 0x80000000 : 0) | (feature_min_interrupt_mask << 20) | (safe_memory_mode << 23));
+               pl(data, (cpu_lvl << 16) | sr_undefined_mask | (addressing_mask == 0xffffffff ? 0x80000000 : 0) |
+                       (feature_min_interrupt_mask << 20) | (safe_memory_mode << 23) | (feature_interrupts << 26));
                fwrite(data, 1, 4, f);
                pl(data, currprefs.fpu_model);
                fwrite(data, 1, 4, f);
@@ -1881,13 +1954,17 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str
        }
        case absw:
        {
-               uae_u16 v;
+               uae_u32 v;
+               if (!high_memory && !low_memory)
+                       return -1;
                for (;;) {
                        v = rand16();
+                       if (v >= 0x8000)
+                               v |= 0xffff0000;
                        if (other_targetea_same(srcdst, (uae_s32)(uae_s16)v))
                                continue;
                        if (analyze_address(dp, srcdst, v))
-                               break;  
+                               break;
                }
                put_word_test(pc, v);
                *isconstant = 16;
@@ -2622,6 +2699,11 @@ static int handle_specials_stack(uae_u16 opcode, uaecptr pc, struct instr *dp, i
        return offset;
 }
 
+static const int interrupt_levels[] =
+{
+       1, 1, 1, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 0
+};
+
 static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp)
 {
        uae_u16 opc = regs.ir;
@@ -2659,6 +2741,7 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp)
        regs.read_buffer = regs.irc;
        regs.write_buffer = 0xf00d;
        exception_extra_frame_size = 0;
+       cpu_cycles = 0;
 
        int cnt = (feature_loop_mode + 1) * 2;
        if (multi_mode)
@@ -2677,8 +2760,20 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp)
                        abort();
                }
 
-               if (SPCFLAG_TRACE)
+               if (SPCFLAG_TRACE) {
                        do_trace();
+               }
+
+               if (feature_interrupts) {
+                       int ic = interrupt_count;
+                       interrupt_count++;
+                       interrupt_count &= 15;
+                       int lvl = interrupt_levels[ic];
+                       if (lvl > 0 && lvl > feature_min_interrupt_mask) {
+                               Exception(lvl + 24);
+                               break;
+                       }
+               }
 
                regs.instruction_pc = regs.pc;
                uaecptr a7 = regs.regs[15];
@@ -3115,6 +3210,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi
        int rounds = feature_test_rounds;
        int subtest_count = 0;
        int data_saved = 0;
+       int first_cycles = 1;
 
        int count = 0;
 
@@ -3194,6 +3290,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi
 
        full_format_cnt = 0;
        last_exception_len = -1;
+       interrupt_count = 0;
 
        int sr_override = 0;
 
@@ -3721,6 +3818,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi
 
                                        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;
@@ -4058,6 +4156,11 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi
                                                                                last_fpcr = regs.fpcr;
                                                                        }
                                                                }
+                                                               if (cpu_lvl <= 1 && (last_cpu_cycles != cpu_cycles || first_cycles)) {
+                                                                       dst = store_reg(dst, CT_CYCLES, last_cpu_cycles, cpu_cycles, first_cycles  ? 0 : -1);
+                                                                       last_cpu_cycles = cpu_cycles;
+                                                                       first_cycles = 0;
+                                                               }
                                                                // store test instruction generated changes
                                                                dst = store_mem_writes(dst, 0);
                                                                // save exception, possible combinations:
@@ -4401,20 +4504,71 @@ static const TCHAR *addrmodes[] =
 
 #define INISECTION _T("cputest")
 
-int __cdecl main(int argc, char *argv[])
+static bool ini_getvalx(struct ini_data *ini, const TCHAR *sections, const TCHAR *key, int *val)
+{
+       bool ret = false;
+       while (*sections) {
+               const TCHAR *sect = sections;
+               if (_tcsicmp(sections, INISECTION)) {
+                       TCHAR *tout = NULL;
+                       if (ini_getstring(ini, sections, key, &tout)) {
+                               if (!_tcsicmp(tout, _T("*"))) {
+                                       sect = INISECTION;
+                               }
+                               xfree(tout);
+                       }
+               }
+               if (ini_getval(ini, sect, key, val))
+                       ret = true;
+               sections += _tcslen(sections) + 1;
+       }
+       if (ret)
+               wprintf(_T("%s=%08x (%d)\n"), key, *val, *val);
+       return ret;
+}
+static bool ini_getstringx(struct ini_data *ini, const TCHAR *sections, const TCHAR *key, TCHAR **out)
+{
+       bool ret = false;
+       *out = NULL;
+       while (*sections) {
+               TCHAR *tout = NULL;
+               if (ini_getstring(ini, sections, key, &tout)) {
+                       if (!_tcsicmp(tout, _T("*"))) {
+                               xfree(tout);
+                               if (!ini_getstring(ini, INISECTION, key, &tout)) {
+                                       tout = my_strdup(_T(""));
+                               }
+                       }
+                       ret = true;
+                       if (*out) {
+                               free(*out);
+                       }
+                       *out = tout;
+               }
+               sections += _tcslen(sections) + 1;
+       }
+       if (ret)
+               wprintf(_T("%s=%s\n"), key, *out);
+       return ret;
+}
+
+static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testname)
 {
        const struct cputbl *tbl = NULL;
        TCHAR path[1000], *vs;
        int v;
 
-       struct ini_data *ini = ini_load(_T("cputestgen.ini"), false);
-       if (!ini) {
-               wprintf(_T("Couldn't open cputestgen.ini"));
-               return 0;
+       wprintf(_T("Generating test '%s'\n"), testname);
+
+       v = 0;
+       ini_getvalx(ini, sections, _T("enabled"), &v);
+       if (!v) {
+               wprintf(_T("Test disabled\n"));
+               return 1;
        }
 
        currprefs.cpu_model = 68000;
-       ini_getval(ini, INISECTION, _T("cpu"), &currprefs.cpu_model);
+       ini_getvalx(ini, sections, _T("cpu"), &currprefs.cpu_model);
        if (currprefs.cpu_model != 68000 && currprefs.cpu_model != 68010 && currprefs.cpu_model != 68020 &&
                currprefs.cpu_model != 68030 && currprefs.cpu_model != 68040 && currprefs.cpu_model != 68060) {
                wprintf(_T("Unsupported CPU model.\n"));
@@ -4424,7 +4578,7 @@ int __cdecl main(int argc, char *argv[])
        currprefs.address_space_24 = 1;
        addressing_mask = 0x00ffffff;
        v = 24;
-       ini_getval(ini, INISECTION, _T("cpu_address_space"), &v);
+       ini_getvalx(ini, sections, _T("cpu_address_space"), &v);
        if (v == 32 || currprefs.cpu_model >= 68030) {
                currprefs.address_space_24 = 0;
                addressing_mask = 0xffffffff;
@@ -4432,7 +4586,7 @@ int __cdecl main(int argc, char *argv[])
 
        currprefs.fpu_model = 0;
        currprefs.fpu_mode = 1;
-       ini_getval(ini, INISECTION, _T("fpu"), &currprefs.fpu_model);
+       ini_getvalx(ini, sections, _T("fpu"), &currprefs.fpu_model);
        if (currprefs.fpu_model && currprefs.cpu_model < 68020) {
                wprintf(_T("FPU requires 68020 or 68040 CPU.\n"));
                return 0;
@@ -4443,10 +4597,10 @@ int __cdecl main(int argc, char *argv[])
        }
 
        verbose = 1;
-       ini_getval(ini, INISECTION, _T("verbose"), &verbose);
+       ini_getvalx(ini, sections, _T("verbose"), &verbose);
 
        feature_gzip = 0;
-       ini_getval(ini, INISECTION, _T("feature_gzip"), &feature_gzip);
+       ini_getvalx(ini, sections, _T("feature_gzip"), &feature_gzip);
 
        feature_addressing_modes[0] = 0xffffffff;
        feature_addressing_modes[1] = 0xffffffff;
@@ -4454,18 +4608,18 @@ int __cdecl main(int argc, char *argv[])
        pc8r[0] = pc8r[1] = 1;
 
        feature_exception3_data = 0;
-       ini_getval(ini, INISECTION, _T("feature_exception3_data"), &feature_exception3_data);
+       ini_getvalx(ini, sections, _T("feature_exception3_data"), &feature_exception3_data);
        feature_exception3_instruction = 0;
-       ini_getval(ini, INISECTION, _T("feature_exception3_instruction"), &feature_exception3_instruction);
+       ini_getvalx(ini, sections, _T("feature_exception3_instruction"), &feature_exception3_instruction);
 
        safe_memory_start = 0xffffffff;
-       if (ini_getval(ini, INISECTION, _T("feature_safe_memory_start"), &v))
+       if (ini_getvalx(ini, sections, _T("feature_safe_memory_start"), &v))
                safe_memory_start = v;
        safe_memory_end = 0xffffffff;
-       if (ini_getval(ini, INISECTION, _T("feature_safe_memory_size"), &v))
+       if (ini_getvalx(ini, sections, _T("feature_safe_memory_size"), &v))
                safe_memory_end = safe_memory_start + v;
        safe_memory_mode = 7;
-       if (ini_getstring(ini, INISECTION, _T("feature_safe_memory_mode"), &vs)) {
+       if (ini_getstringx(ini, sections, _T("feature_safe_memory_mode"), &vs)) {
                safe_memory_mode = 0;
                if (_totupper(vs[0]) == 'R')
                        safe_memory_mode |= 1;
@@ -4488,7 +4642,7 @@ int __cdecl main(int argc, char *argv[])
                feature_target_ea[i][2] = 0xffffffff;
        }
        for (int i = 0; i < 3; i++) {
-               if (ini_getstring(ini, INISECTION, i == 2 ? _T("feature_target_opcode_offset") : (i ? _T("feature_target_dst_ea") : _T("feature_target_src_ea")), &vs)) {
+               if (ini_getstringx(ini, sections, i == 2 ? _T("feature_target_opcode_offset") : (i ? _T("feature_target_dst_ea") : _T("feature_target_src_ea")), &vs)) {
                        int cnt = 0;
                        TCHAR *p = vs;
                        int exp3cnt = 0;
@@ -4536,25 +4690,27 @@ int __cdecl main(int argc, char *argv[])
        }
 
        feature_sr_mask = 0;
-       ini_getval(ini, INISECTION, _T("feature_sr_mask"), &feature_sr_mask);
+       ini_getvalx(ini, sections, _T("feature_sr_mask"), &feature_sr_mask);
        feature_min_interrupt_mask = 0;
-       ini_getval(ini, INISECTION, _T("feature_min_interrupt_mask"), &feature_min_interrupt_mask);
+       ini_getvalx(ini, sections, _T("feature_min_interrupt_mask"), &feature_min_interrupt_mask);
 
        feature_loop_mode = 0;
-       ini_getval(ini, INISECTION, _T("feature_loop_mode"), &feature_loop_mode);
+       ini_getvalx(ini, sections, _T("feature_loop_mode"), &feature_loop_mode);
        if (feature_loop_mode) {
                feature_loop_mode_register = 7;
        }
        feature_flag_mode = 0;
-       ini_getval(ini, INISECTION, _T("feature_flags_mode"), &feature_flag_mode);
+       ini_getvalx(ini, sections, _T("feature_flags_mode"), &feature_flag_mode);
        feature_usp = 0;
-       ini_getval(ini, INISECTION, _T("feature_usp"), &feature_usp);
+       ini_getvalx(ini, sections, _T("feature_usp"), &feature_usp);
        feature_exception_vectors = 0;
-       ini_getval(ini, INISECTION, _T("feature_exception_vectors"), &feature_exception_vectors);
+       ini_getvalx(ini, sections, _T("feature_exception_vectors"), &feature_exception_vectors);
+       feature_interrupts = 0;
+       ini_getvalx(ini, sections, _T("feature_interrupts"), &feature_interrupts);
 
        feature_full_extension_format = 0;
        if (currprefs.cpu_model >= 68020) {
-               ini_getval(ini, INISECTION, _T("feature_full_extension_format"), &feature_full_extension_format);
+               ini_getvalx(ini, sections, _T("feature_full_extension_format"), &feature_full_extension_format);
                if (feature_full_extension_format) {
                        ad8r[0] |= 2;
                        ad8r[1] |= 2;
@@ -4565,7 +4721,7 @@ int __cdecl main(int argc, char *argv[])
 
        for (int j = 0; j < 2; j++) {
                TCHAR *am = NULL;
-               if (ini_getstring(ini, INISECTION, j ? _T("feature_addressing_modes_dst") : _T("feature_addressing_modes_src"), &am)) {
+               if (ini_getstringx(ini, sections, j ? _T("feature_addressing_modes_dst") : _T("feature_addressing_modes_src"), &am)) {
                        if (_tcslen(am) > 0) {
                                feature_addressing_modes[j] = 0;
                                ad8r[j] = 0;
@@ -4606,10 +4762,10 @@ int __cdecl main(int argc, char *argv[])
 
 
        TCHAR *mode = NULL;
-       ini_getstring(ini, INISECTION, _T("mode"), &mode);
+       ini_getstringx(ini, sections, _T("mode"), &mode);
 
        TCHAR *ipath = NULL;
-       ini_getstring(ini, INISECTION, _T("path"), &ipath);
+       ini_getstringx(ini, sections, _T("path"), &ipath);
        if (!ipath) {
                _tcscpy(path, _T("data/"));
        } else {
@@ -4617,21 +4773,21 @@ int __cdecl main(int argc, char *argv[])
        }
        free(ipath);
 
-       _stprintf(path + _tcslen(path), _T("%lu/"), currprefs.cpu_model);
+       _stprintf(path + _tcslen(path), _T("%lu_%s/"), currprefs.cpu_model, testname);
        _wmkdir(path);
 
        xorshiftstate = 1;
 
        feature_test_rounds = 2;
-       ini_getval(ini, INISECTION, _T("test_rounds"), &feature_test_rounds);
+       ini_getvalx(ini, sections, _T("test_rounds"), &feature_test_rounds);
 
        feature_instruction_size = NULL;
-       ini_getstring(ini, INISECTION, _T("feature_instruction_size"), &feature_instruction_size);
+       ini_getstringx(ini, sections, _T("feature_instruction_size"), &feature_instruction_size);
 
-       ini_getval(ini, INISECTION, _T("feature_instruction_size"), &feature_test_rounds);
+       ini_getvalx(ini, sections, _T("feature_instruction_size"), &feature_test_rounds);
 
        v = 0;
-       ini_getval(ini, INISECTION, _T("test_memory_start"), &v);
+       ini_getvalx(ini, sections, _T("test_memory_start"), &v);
        if (!v) {
                wprintf(_T("test_memory_start is required\n"));
                return 0;
@@ -4639,7 +4795,7 @@ int __cdecl main(int argc, char *argv[])
        test_memory_start = v;
 
        v = 0;
-       ini_getval(ini, INISECTION, _T("test_memory_size"), &v);
+       ini_getvalx(ini, sections, _T("test_memory_size"), &v);
        if (!v) {
                wprintf(_T("test_memory_start is required\n"));
                return 0;
@@ -4650,19 +4806,19 @@ int __cdecl main(int argc, char *argv[])
        test_low_memory_start = 0xffffffff;
        test_low_memory_end = 0xffffffff;
        v = 0;
-       if (ini_getval(ini, INISECTION, _T("test_low_memory_start"), &v))
+       if (ini_getvalx(ini, sections, _T("test_low_memory_start"), &v))
                test_low_memory_start = v;
        v = 0;
-       if (ini_getval(ini, INISECTION, _T("test_low_memory_end"), &v))
+       if (ini_getvalx(ini, sections, _T("test_low_memory_end"), &v))
                test_low_memory_end = v;
 
        test_high_memory_start = 0xffffffff;
        test_high_memory_end = 0xffffffff;
        v = 0;
-       if (ini_getval(ini, INISECTION, _T("test_high_memory_start"), &v))
+       if (ini_getvalx(ini, sections, _T("test_high_memory_start"), &v))
                test_high_memory_start = v;
        v = 0;
-       if (ini_getval(ini, INISECTION, _T("test_high_memory_end"), &v))
+       if (ini_getvalx(ini, sections, _T("test_high_memory_end"), &v))
                test_high_memory_end = v;
 
        if (addressing_mask == 0xffffffff && test_high_memory_end <= 0x01000000) {
@@ -4678,7 +4834,7 @@ int __cdecl main(int argc, char *argv[])
        }
 
        v = 0;
-       if (ini_getval(ini, INISECTION, _T("opcode_memory_start"), &v)) {
+       if (ini_getvalx(ini, sections, _T("opcode_memory_start"), &v)) {
                opcode_memory_start = v;
                opcode_memory = test_memory + (opcode_memory_start - test_memory_start);
        } else {
@@ -4689,7 +4845,7 @@ int __cdecl main(int argc, char *argv[])
                wprintf(_T("Opcode memory out of bounds\n"));
                return 0;
        }
-       if (ini_getval(ini, INISECTION, _T("feature_stack_memory"), &v)) {
+       if (ini_getvalx(ini, sections, _T("feature_stack_memory"), &v)) {
                super_stack_memory = v;
                user_stack_memory = super_stack_memory - (RESERVED_SUPERSTACK + RESERVED_USERSTACK_EXTRA);
        } else {
@@ -4714,7 +4870,7 @@ int __cdecl main(int argc, char *argv[])
 
        if (test_low_memory_start != 0xffffffff) {
                TCHAR *lmem_rom_name = NULL;
-               ini_getstring(ini, INISECTION, _T("low_rom"), &lmem_rom_name);
+               ini_getstringx(ini, sections, _T("low_rom"), &lmem_rom_name);
                if (lmem_rom_name) {
                        if (load_file(NULL, lmem_rom_name, low_memory_temp, low_memory_size, 0)) {
                                wprintf(_T("Low test memory ROM loaded\n"));
@@ -4727,7 +4883,7 @@ int __cdecl main(int argc, char *argv[])
 
        if (test_high_memory_start != 0xffffffff) {
                TCHAR *hmem_rom_name = NULL;
-               ini_getstring(ini, INISECTION, _T("high_rom"), &hmem_rom_name);
+               ini_getstringx(ini, sections, _T("high_rom"), &hmem_rom_name);
                if (hmem_rom_name) {
                        if (load_file(NULL, hmem_rom_name, high_memory_temp, high_memory_size, -1)) {
                                wprintf(_T("High test memory ROM loaded\n"));
@@ -4849,8 +5005,10 @@ int __cdecl main(int argc, char *argv[])
 
        x_get_long = get_long_test;
        x_get_word = get_word_test;
+       x_get_byte = get_byte_test;
        x_put_long = put_long_test;
        x_put_word = put_word_test;
+       x_put_byte = put_byte_test;
 
        x_next_iword = next_iword_test;
        x_cp_next_iword = next_iword_test;
@@ -4943,7 +5101,49 @@ int __cdecl main(int argc, char *argv[])
                modep = sp;
        }
 
+       xfree(low_memory);
+       xfree(low_memory_temp);
+       xfree(high_memory);
+       xfree(high_memory_temp);
+       xfree(test_memory);
+       xfree(test_memory_temp);
+       xfree(storage_buffer);
+
        wprintf(_T("%d total tests generated\n"), test_count);
 
-       return 0;
+       return 1;
 }
+
+static TCHAR sections[1000];
+
+int __cdecl main(int argc, char *argv[])
+{
+       const struct cputbl *tbl = NULL;
+       TCHAR path[1000], *vs;
+       int v;
+
+       struct ini_data *ini = ini_load(_T("cputestgen.ini"), false);
+       if (!ini) {
+               wprintf(_T("Couldn't open cputestgen.ini"));
+               return 0;
+       }
+
+       TCHAR *sptr = sections;
+       _tcscpy(sections, INISECTION);
+       sptr += _tcslen(sptr) + 1;
+
+       int idx = 0;
+       for (;;) {
+               TCHAR *section = NULL;
+               if (!ini_getsection(ini, idx, &section))
+                       break;
+               if (!_tcsnicmp(section, _T("test="), 5)) {
+                       _tcscpy(sptr, section);
+                       if (!test(ini, sections, section + 5))
+                               break;
+               }
+               idx++;
+       }
+
+}
+
index a088abd1db7f73113012d0b3c339b73d902ac514..b86985090f43ff8a5033b5d3a4dd4f83702615bd 100644 (file)
@@ -2,6 +2,7 @@
        .text
 
        .equ ACTIVITYREG,0xdff180
+       .equ CYCLEREG,0xdff006
        
        .globl _allocate_absolute
        .globl _free_absolute
@@ -9,6 +10,19 @@
        .globl _tosuper
        .globl _testexit
        .globl _get_cpu_model
+       .globl sync
+
+sync:
+       move.b 0xdff006,d0
+       beq.s sync
+       cmp.b #0xff,d0
+       beq.s sync
+       cmp.b #0x38,d0
+       beq.s sync
+       | above prevent wraparound between
+       | dff004.w and dff006.w reads
+       move.l 0xdff004,d0
+       rts
 
        | check left mouse button/joystick fire
 _testexit:
@@ -26,6 +40,7 @@ _tosuper:
        jsr -0x78(a6) | Disable
        jsr -0x96(a6) | SuperState
        move.w #0x0200,0xdff096
+       move.w #0x2700,sr
        move.l (sp)+,a6
        rts
        
index a00440b252b330a4b5a69241837707a6c1e31ef4..3e5bab700ad593cb390457bf34a7914b1716baa7 100644 (file)
@@ -36,14 +36,16 @@ S_FPCR = S_FPIAR+4
 S_FPSR = S_FPCR+4
 S_TRACECNT = S_FPSR+4
 S_TRACESTACK = S_TRACECNT+4
-S_NEXT = S_TRACESTACK+12
+S_CYCLES = S_TRACESTACK+12
+S_CYCLES2 = S_CYCLES+4
+S_CYCLEST = S_CYCLES2+4
+S_NEXT = S_CYCLEST+4
 
 _callinflate:
-       movem.l a4-a5,-(sp)
-       move.l 4+2*4(sp),a4
-       move.l 8+2*4(sp),a5
+       movem.l a4-a6,-(sp)
+       movem.l 4+3*4(sp),a4-a6
        bsr _inflate
-       movem.l (sp)+,a4-a5
+       movem.l (sp)+,a4-a6
        rts
 
        | set CPU special registers
@@ -135,7 +137,10 @@ _execute_test000:
        move.w S_SR+2(a0),-(sp)
        move.l S_AREG+7*4(a0),a1
        move.l a1,USP
+       bsr sync
+       move.l d0,S_CYCLES2(a0)
        movem.l (a0),d0-d7/a0-a6
+       move.w CYCLEREG,cycles
        rte
 
        | 68010+ test entrypoint
@@ -154,7 +159,10 @@ _execute_test010:
        move.w S_SR+2(a0),-(sp)
        move.l S_AREG+7*4(a0),a1
        move.l a1,USP
+       bsr sync
+       move.l d0,S_CYCLES2(a0)
        movem.l (a0),d0-d7/a0-a6
+       move.w CYCLEREG,cycles
        | clear data output buffer.
        | we don't want random DOB contents in bus/address error frame
        move.w #0xf00d,dummy
@@ -214,12 +222,16 @@ _msp_address2:
        rte
 
 exception_trace000:
+       move.w sr,-(sp)
+       move.w CYCLEREG,cycles+4
+       addq.l #2+4,sp
        move.l a0,-(sp)
        move.l datapointer(pc),a0
        tst.l S_TRACECNT(a0)
        bne.s .nexttrace000
        move.l 4(sp),S_TRACESTACK(a0)
        move.l 8(sp),S_TRACESTACK+4(a0)
+       move.w cycles+4(pc),S_CYCLEST+2(a0)
 .nexttrace000:
        addq.l #1,S_TRACECNT(a0)
        move.l (sp)+,a0
@@ -233,7 +245,7 @@ _exceptiontable000:
        bsr.s exception | 6
        bsr.s exception | 7
        bsr.s exception | 8
-       bra.s exception_trace000 | 9
+       bsr.s exception_trace000 | 9
        bsr.s exception | 10
        bsr.s exception | 11
        bsr.s exception | 12
@@ -275,6 +287,7 @@ _exceptiontable000:
        nop
 exception:
        move.w sr,-(sp)
+       move.w CYCLEREG,cycles+2
        move.w #0,ACTIVITYREG
        move.l a0,-(sp)
        move.l datapointer(pc),a0
@@ -302,6 +315,7 @@ exception:
 
        move.l USP,a1
        move.l a1,S_AREG+7*4(a0)
+       move.l cycles(pc),S_CYCLES(a0)
 
        move.w #0x222,ACTIVITYREG
        move.l superstack(pc),sp
@@ -310,6 +324,9 @@ exception:
        rts
 
 exception_trace010:
+       move.w sr,-(sp)
+       move.w CYCLEREG,cycles+4
+       addq.l #2+4,sp
        move.l a0,-(sp)
        move.l datapointer(pc),a0
        tst.l S_TRACECNT(a0)
@@ -317,20 +334,21 @@ exception_trace010:
        move.l 4(sp),S_TRACESTACK(a0)
        move.l 8(sp),S_TRACESTACK+4(a0)
        move.l 12(sp),S_TRACESTACK+8(a0)
+       move.w cycles+4(pc),S_CYCLEST+2(a0)
 .nexttrace010:
        addq.l #1,S_TRACECNT(a0)
        move.l (sp)+,a0
        rte
 
 _exceptiontable010:
-       bsr.s exception010      | 2
-       bsr.s exception010      | 3
+       bsr.s exception010 | 2
+       bsr.s exception010 | 3
        bsr.s exception010 | 4
        bsr.s exception010 | 5
        bsr.s exception010 | 6
        bsr.s exception010 | 7
        bsr.s exception010 | 8
-       bra.s exception_trace010 | 9
+       bsr.s exception_trace010 | 9
        bsr.s exception010 | 10
        bsr.s exception010 | 11
        bsr.s exception010 | 12
@@ -372,6 +390,7 @@ _exceptiontable010:
        nop
 exception010:
        move.w sr,-(sp)
+       move.w CYCLEREG,cycles+2
        move.w #0,ACTIVITYREG
        move.l a0,-(sp)
        move.l datapointer(pc),a0
@@ -396,7 +415,8 @@ exception010:
 
        move.l USP,a1
        move.l a1,S_AREG+7*4(a0)
-               
+       move.l cycles(pc),S_CYCLES(a0)
+
        move.w #0x222,ACTIVITYREG
        move.l superstack(pc),sp
        move.w (sp)+,sr
@@ -600,5 +620,7 @@ datapointer:
        dc.l 0
 superstack:
        dc.l 0
+cycles:
+       dc.l 0,0
 dummy:
        dc.l 0
index 9677bb27c71eef172170d01afe70775af5b14667..19ef70812b70ba26d640018026c86e95143a3652 100644 (file)
@@ -1,5 +1,5 @@
 
-#define DATA_VERSION 14
+#define DATA_VERSION 15
 
 #define CT_FPREG 0
 #define CT_DREG 0
@@ -11,6 +11,7 @@
 #define CT_FPIAR 20
 #define CT_FPSR 21
 #define CT_FPCR 22
+#define CT_CYCLES 25
 #define CT_ENDPC 26
 #define CT_BRANCHTARGET 27
 #define CT_SRCADDR 28
index d60e03dab5435854b59596ee4c2971d1917ad4d4..24007c9b6e0866fbbf8726186d805258866af12e 100644 (file)
@@ -1,4 +1,3 @@
-
 [cputest]
 
 ; CPU model (68000, 68020, 68030, 68040 or 68060).
@@ -27,6 +26,7 @@ feature_gzip=0
 
 ; Low address space limits. Real hardware must have RAM in this space. Comment out to disable.
 ; Start should be zero if Amiga, set to 0x0800 if Atari ST.
+; Must be disabled if cycle counting, cycle count tests must only access real Fast RAM.
 test_low_memory_start=0x0000
 test_low_memory_end=0x8000
 
@@ -39,12 +39,11 @@ test_high_memory_end=0x01000000
 high_rom=D:\amiga\roms\Kickstart v3.1 rev 40.63 (1993)(Commodore)(A500-A600-A2000)[!].rom
 
 ; main test memory start and size (real hardware must have RAM in this address space)
-test_memory_start=0x800000
+test_memory_start=0x860000
 ;test_memory_start=0x68800000
 ;test_memory_start=0x07800000
-;test_memory_start=0x00800000
 ;test_memory_start=0x340000
-test_memory_size=0x1c0000
+test_memory_size=0xa0000
 
 ; address where test instructions are located
 ; if not defined: mid point of test memory
@@ -72,19 +71,23 @@ feature_exception3_instruction=0
 ; Supports 68000 addressing modes only.
 ; If instruction only has destination EA, source Areg, Dreg or immediate is generated.
 feature_target_src_ea=
-;feature_target_dst_ea=0x87fffa,0x87fffb,0x87fffc,0x87fffd,0x87fffe,0x87ffff,0x880000,0x880001,0x880002,0x880003,0x880004
+feature_target_dst_ea=
+
+; addresses where test instruction is located, use for bus error prefetch testing
+; automatically enables RP bus error mode, data read bus errors are skipped.
+;feature_target_opcode_offset=90,92,94,96,98,100,102,104
 
 ; Memory region that generates bus error (both read and write).
 ; Must be inside any test memory region.
 ; Can be used to verify bus errors if ea above is inside this memory region.
-feature_safe_memory_start=0x880000
-feature_safe_memory_size=0x80000
+feature_safe_memory_start=
+feature_safe_memory_size=
 ; R = data read only bus error
 ; W = data write only bus error
 ; P = prefetch bus error
 ; empty or RWP = both.
 ; if enabled, all tests that don't generate matching bus error are skipped.
-feature_safe_memory_mode=R
+feature_safe_memory_mode=
 
 ; user stack modes
 ; 0 = normal even stack
@@ -110,6 +113,12 @@ feature_flags_mode=1
 ; Skips all tests that would set lower interrupt mask.
 feature_min_interrupt_mask=0
 
+; Interrupt test
+; If enabled, interrupt request is set before test.
+; Tests all INTREQ bits one by one. Compatible with cycle count mode.
+; Amiga only
+feature_interrupts=0
+
 ; SR extra mask.
 ; 0x8000 = T1
 ; 0x4000 = T0 (68020-68040)
@@ -117,8 +126,9 @@ feature_min_interrupt_mask=0
 ; 0x1000 = M (68020-68060)
 ; Other bits are ignored.
 ; For example 0xa000 adds 3 extra test rounds: S=1/T1=0, S=0/T1=1 and S=1/T1=1
+; For example 0x8000 adds 1 extra test round: T1=1
 ; Note: instructions that generate privilege violation exception will automatically add extra S=1 round.
-feature_sr_mask=0xa000
+feature_sr_mask=0x0000
 
 ; generate loop test: label: <test instruction> dbf dn,label
 ; value: 0 = disabled, >0 = number of loops
@@ -144,4 +154,46 @@ feature_instruction_size=
 ; all = generate all CPU tests. tst = generate tst.b, tst.w and tst.l. tst.l = generate only tst.l
 ; fall = generate all FPU tests.
 ; branch = all branch instructions (branchj = non-stack only, branchs = stack using)
+mode=
+
+; test groups
+; use key=* to restore default value
+
+[test=Default]
+enabled=1
+mode=all
+
+[test=IRQ]
+enabled=0
+mode=nop,ext,swap
+feature_interrupts=1
+
+[test=AE_SRC]
+enabled=0
+feature_target_src_ea=0x87fff1,0x7111
+feature_target_dst_ea=
+mode=all
+
+[test=AE_DST]
+enabled=0
+feature_target_src_ea=
+feature_target_dst_ea=0x87fff1,0x7111
+mode=all
+
+[test=BERR_SRC]
+enabled=0
+feature_safe_memory_start=0x880000
+feature_safe_memory_size=0x80000
+feature_safe_memory_mode=R
+feature_target_src_ea=0x87fffc,0x87fffd,0x87fffe,0x87ffff,0x880000,0x880001,0x880002,0x880003,0x880004
+feature_target_dst_ea=
+mode=all
+
+[test=BERR_DST]
+enabled=0
+feature_safe_memory_start=0x880000
+feature_safe_memory_size=0x80000
+feature_safe_memory_mode=R
+feature_target_src_ea=
+feature_target_dst_ea=0x87fffc,0x87fffd,0x87fffe,0x87ffff,0x880000,0x880001,0x880002,0x880003,0x880004
 mode=all
index bdd5a099dbdcc4e45accaaed67bbe0c3a8a79783..c2f7eafdcb7f83d6222133abfaea7fabac8b26a6 100644 (file)
@@ -66,7 +66,7 @@
  * on whether OPT_TABLE_LOOKUP is enabled).
  * SPEEDUP: none; COST: -2 bytes code (makes code slightly smaller) */
 #ifndef OPT_STORAGE_OFFSTACK
-#define OPT_STORAGE_OFFSTACK 0
+#define OPT_STORAGE_OFFSTACK 1
 #endif
 
 /* By default all lookup/conversion tables are generated on-the-fly on every
index 6e85a55dc25bd132a9d803a1d79c006c84880a30..6b0aabaa1e1aa3a0d9dc8b3503046d24c48309db 100644 (file)
@@ -27,7 +27,7 @@ typedef signed char uae_s8;
 
 #include "cputest_defines.h"
 
-extern void callinflate(uae_u8*, uae_u8*);
+extern void callinflate(uae_u8*, uae_u8*,uae_u8*);
 
 struct fpureg
 {
@@ -51,6 +51,7 @@ struct registers
        uae_u32 fpiar, fpcr, fpsr;
        uae_u32 tracecnt;
        uae_u16 tracedata[6];
+       uae_u32 cycles, cycles2, cyclest;
        uae_u32 srcaddr, dstaddr, branchtarget;
        uae_u8 branchtarget_mode;
        uae_u32 endpc;
@@ -72,7 +73,7 @@ static uae_u32 test_memory_addr, test_memory_end;
 static uae_u32 test_memory_size;
 static uae_u8 *test_data;
 static uae_u8 *safe_memory_start, *safe_memory_end;
-static int safe_memory_mode;
+static short safe_memory_mode;
 static uae_u32 user_stack_memory, super_stack_memory;
 static uae_u32 exception_vectors;
 static int test_data_size;
@@ -114,18 +115,26 @@ static char tmpbuffer[1024];
 static char path[256];
 
 static char *outbp;
-static int infoadded;
+static short infoadded;
 static int errors;
 static int testcnt;
-static int dooutput = 1;
-static int quit;
+static short dooutput = 1;
+static short quit;
 static uae_u8 ccr_mask;
 static uae_u32 addressing_mask = 0x00ffffff;
 static uae_u32 interrupt_mask;
-static int disasm;
-static int basicexcept;
-static int askifmissing;
-static int nextall;
+static short disasm;
+static short basicexcept;
+static short askifmissing;
+static short nextall;
+static int exitcnt;
+static short cycles, cycles_range, cycles_adjust;
+static short gotcycles;
+static short interrupttest;
+#ifdef AMIGA
+static short interrupt_count;
+static uae_u16 main_intena;
+#endif
 
 #define SIZE_STORED_ADDRESS_OFFSET 8
 #define SIZE_STORED_ADDRESS 16
@@ -135,6 +144,8 @@ static uae_u8 branchtarget[SIZE_STORED_ADDRESS];
 static uae_u8 stackaddr[SIZE_STORED_ADDRESS];
 static uae_u32 stackaddr_ptr;
 
+static char opcode[32], group[32], cpustr[10];
+
 #ifndef M68K
 
 #define xmemcpy memcpy
@@ -349,19 +360,27 @@ static void start_test(void)
 
        enable_data = tosuper(0);
 
-       safe_memcpy(low_memory_back + low_memory_offset, low_memory + low_memory_offset, low_memory_size - low_memory_offset);
+#ifdef AMIGA
+       main_intena = *((volatile uae_u16*)0xdff01c);
+#endif
+
+       if (test_low_memory_start != 0xffffffff)
+               safe_memcpy(low_memory_back + low_memory_offset, low_memory + low_memory_offset, low_memory_size - low_memory_offset);
+
        // always copy exception vectors if 68000
        if (cpu_lvl == 0 && low_memory_offset > 0x08)
                safe_memcpy(low_memory_back + 8, low_memory + 8, (192 - 2) * 4);
 
-       if (!hmem_rom)
+       if (!hmem_rom && test_high_memory_start != 0xffffffff)
                safe_memcpy(high_memory_back, high_memory + high_memory_offset, high_memory_size - high_memory_offset);
 
-       safe_memcpy(low_memory + low_memory_offset, low_memory_temp + low_memory_offset, low_memory_size - low_memory_offset);
+       if (test_low_memory_start != 0xffffffff)
+               safe_memcpy(low_memory + low_memory_offset, low_memory_temp + low_memory_offset, low_memory_size - low_memory_offset);
+
        if (cpu_lvl == 0 && low_memory_offset > 0x08)
                safe_memcpy(low_memory + 8, low_memory_temp + 8, (192 - 2) * 4);
 
-       if (!hmem_rom)
+       if (!hmem_rom && test_high_memory_start != 0xffffffff)
                safe_memcpy(high_memory + high_memory_offset, high_memory_temp, high_memory_size - high_memory_offset);
 
        if (cpu_lvl == 0) {
@@ -375,6 +394,12 @@ static void start_test(void)
                                error_vectors[i - 2] = p[i];
                        }
                }
+               for (int i = 24; i < 24 + 8; i++) {
+                       p[i] = (uae_u32)(((uae_u32)&exceptiontable000) + (i - 2) * 2);
+                       if (exception_vectors) {
+                               p[i] = exception_vectors;
+                       }
+               }
                for (int i = 32; i < 48; i++) {
                        p[i] = (uae_u32)(((uae_u32)&exceptiontable000) + (i - 2) * 2);
                        if (exception_vectors) {
@@ -412,11 +437,13 @@ static void end_test(void)
                return;
        test_active = 0;
 
-       safe_memcpy(low_memory + low_memory_offset, low_memory_back + low_memory_offset, low_memory_size - low_memory_offset);
+       if (test_low_memory_start != 0xffffffff)
+               safe_memcpy(low_memory + low_memory_offset, low_memory_back + low_memory_offset, low_memory_size - low_memory_offset);
+
        if (cpu_lvl == 0 && low_memory_offset > 0x08)
                safe_memcpy(low_memory + 8, low_memory_back + 8, (192 - 2) * 4);
 
-       if (!hmem_rom)
+       if (!hmem_rom && test_high_memory_start != 0xffffffff)
                safe_memcpy(high_memory + high_memory_offset, high_memory_back, high_memory_size - high_memory_offset);
 
        if (cpu_lvl > 0) {
@@ -424,6 +451,12 @@ static void end_test(void)
        }
        setcpu(cpu_lvl, cpustatearraystore, NULL);
 
+#ifdef AMIGA
+       *((volatile uae_u16*)0xdff09a) = 0x7fff;
+       *((volatile uae_u16*)0xdff09c) = 0x7fff;
+       *((volatile uae_u16*)0xdff09a) = main_intena | 0x8000;
+#endif
+
        touser(enable_data);
 }
 
@@ -473,6 +506,9 @@ static uae_u8 *parse_gzip(uae_u8 *gzbuf, int *sizep)
        return gzbuf;
 }
 
+#define INFLATE_STACK_SIZE 3000
+static uae_u8 *inflatestack;
+
 static uae_u8 *load_file(const char *path, const char *file, uae_u8 *p, int *sizep, int exiterror, int candirect)
 {
        char fname[256];
@@ -503,6 +539,14 @@ static uae_u8 *load_file(const char *path, const char *file, uae_u8 *p, int *siz
                        exit(0);
                }
                f = NULL;
+               if (!inflatestack) {
+                       inflatestack = malloc(INFLATE_STACK_SIZE);
+                       if (!inflatestack) {
+                               printf("Couldn't allocate %ld bytes (inflate stack)\n", INFLATE_STACK_SIZE);
+                               exit(0);
+                       }
+                       inflatestack += INFLATE_STACK_SIZE;
+               }
                if (!p) {
                        p = calloc(1, size);
                        if (!p) {
@@ -510,12 +554,12 @@ static uae_u8 *load_file(const char *path, const char *file, uae_u8 *p, int *siz
                                exit(0);
                        }
                        printf("Decompressing '%s' (%ld -> %ld)\n", fname, gsize, size);
-                       callinflate(p, gzdata);
+                       callinflate(p, gzdata, inflatestack);
                        *sizep = size;
                        return p;
                } else if (candirect) {
                        printf("Decompressing '%s' (%ld -> %ld)\n", fname, gsize, size);
-                       callinflate(p, gzdata);
+                       callinflate(p, gzdata, inflatestack);
                        *sizep = size;
                        return p;
                } else {
@@ -525,7 +569,7 @@ static uae_u8 *load_file(const char *path, const char *file, uae_u8 *p, int *siz
                                exit(0);
                        }
                        printf("Decompressing '%s' (%ld -> %ld)\n", fname, gsize, size);
-                       callinflate(unpack, gzdata);
+                       callinflate(unpack, gzdata, inflatestack);
                        *sizep = size;
                }
        }
@@ -747,9 +791,9 @@ static uae_u8 *restore_rel(uae_u8 *p, uae_u32 *vp, int nocheck)
                        val |= *p++;
                        v = val;
                        if (!nocheck) {
-                               if ((val & addressing_mask) < low_memory_size) {
+                               if (test_low_memory_start != 0xffffffff && (val & addressing_mask) < low_memory_size) {
                                        ; // low memory
-                               } else if ((val & ~addressing_mask) == ~addressing_mask && val >= 0xfff80000) {
+                               } else if (test_high_memory_start != 0xffffffff && (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();
@@ -1023,6 +1067,10 @@ static uae_u8 *restore_data(uae_u8 *p)
        } else if (mode == CT_SR) {
                int size;
                p = restore_value(p, &regs.sr, &size);
+       } else if (mode == CT_CYCLES) {
+               int size;
+               p = restore_value(p, &regs.cycles, &size);
+               gotcycles = 1;
        } else if (mode == CT_FPIAR) {
                int size;
                p = restore_value(p, &regs.fpiar, &size);
@@ -1616,6 +1664,156 @@ static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, int excnum,
        return p;
 }
 
+static int getexceptioncycles(int exc)
+{
+       if (cpu_lvl == 0) {
+               switch (exc)
+               {
+               case 2:
+               case 3:
+                       return 58;
+               case 4:
+               case 5:
+               case 6:
+               case 8:
+               case 9:
+               case 10:
+               case 11:
+                       return 34;
+               case 7:
+                       return 30;
+               case 24:
+               case 25:
+               case 26:
+               case 27:
+               case 28:
+               case 29:
+               case 30:
+               case 31:
+                       return 44;
+               default:
+                       return 34;
+               }
+       } else {
+               switch (exc)
+               {
+               case 2:
+               case 3:
+                       return 126;
+               case 4:
+               case 10:
+               case 11:
+                       return 38;
+               case 5:
+                       return 42;
+               case 6:
+                       return 44;
+               case 7:
+                       return 40;
+               case 8:
+                       return 38;
+               case 9:
+                       return 38;
+               case 24:
+               case 25:
+               case 26:
+               case 27:
+               case 28:
+               case 29:
+               case 30:
+               case 31:
+                       return 48;
+               default:
+                       return 38;
+               }
+       }
+}
+
+static int check_cycles(int exc)
+{
+       // 7MHz 68000 PAL A500 only!
+       uae_u16 vstart = (test_regs.cycles >> 24) & 0xff;
+       uae_u16 vend = (test_regs.cycles >> 8) & 0xff;
+       uae_u16 hstart = (test_regs.cycles >> 16) & 0xff;
+       uae_u16 hend = (test_regs.cycles >> 0) & 0xff;
+
+       // trace exception?
+       if (test_regs.cyclest != 0xffffffff) {
+               vend = (test_regs.cyclest >> 8) & 0xff;
+               hend = (test_regs.cyclest >> 0) & 0xff;
+       }
+
+       if (test_regs.cycles2 & 0x00010000) {
+               if (vstart > vend) {
+                       vstart += 0x100;
+                       vend += 0x138 + 1;
+               } else {
+                       vstart += 0x100;
+                       vend += 0x100;
+               }
+       } else {
+               if (vstart > vend) {
+                       vend += 0x100;
+               }
+       }
+
+       // hpos 0-1: vertical count hasn't been increased yet
+       if (hstart <= 1) {
+               vstart++;
+       }
+       if (hend <= 1) {
+               vend++;
+       }
+
+       if (hstart >= hend) {
+               hend += 227;
+               vend--;
+       }
+       int startcycle = vstart * 227 + hstart;
+       int endcycle = vend * 227 + hend;
+       int gotcycles = (endcycle - startcycle) * 2;
+       int expectedcycles = last_registers.cycles;
+       if (cpu_lvl == 0) {
+               // move.w CYCLEREG,cycles
+               gotcycles -= 20;
+               // RTE
+               gotcycles -= 20;
+               // <test instruction>
+               // EXCEPTION
+               expectedcycles += getexceptioncycles(exc);
+               // bsr.b
+               gotcycles -= 18;
+               // move.w sr,-(sp)
+               gotcycles -= 14;
+               // move.w CYCLEREG,cycles
+               gotcycles -= 8;
+       } else {
+               // move.w CYCLEREG,cycles
+               gotcycles -= 20;
+               // move.w #x,dummy
+               gotcycles -= 20;
+               // RTE
+               gotcycles -= 24;
+               // <test instruction>
+               // ILLEGAL
+               expectedcycles += getexceptioncycles(exc);
+               // bsr.b
+               gotcycles -= 18;
+               // move.w sr,-(sp)
+               gotcycles -= 12;
+               // move.w CYCLEREG,cycles
+               gotcycles -= 8;
+       }
+       gotcycles += cycles_adjust;
+
+       if (0 || abs(gotcycles - expectedcycles) > cycles_range) {
+               addinfo();
+               sprintf(outbp, "Got %ld cycles but expected %ld cycles (%08x %08x)\n", gotcycles, expectedcycles, test_regs.cycles, test_regs.cycles2);
+               outbp += strlen(outbp);
+               return 0;
+       }
+       return 1;
+}
 
 // regs: registers before execution of test code
 // test_reg: registers used during execution of test code, also modified by test code.
@@ -1811,6 +2009,12 @@ static uae_u8 *validate_test(uae_u8 *p, int ignore_errors, int ignore_sr)
                        p = restore_rel(p, &val, 0);
                        pc_changed = 0;
                        last_registers.pc = val;
+               } else if (mode == CT_CYCLES) {
+                       uae_u32 val = last_registers.cycles;
+                       int size;
+                       p = restore_value(p, &val, &size);
+                       last_registers.cycles = val;
+                       gotcycles = 1;
                } else if (mode == CT_FPCR) {
                        uae_u32 val = last_registers.fpcr;
                        int size;
@@ -1965,6 +2169,18 @@ static uae_u8 *validate_test(uae_u8 *p, int ignore_errors, int ignore_sr)
                        }
                        errflag |= 1 << 5;
                }
+               if (cycles && cpu_lvl <= 1) {
+                       if (!gotcycles && errflag) {
+                               if (dooutput) {
+                                       sprintf(outbp, "No Cycle count data available.\n");
+                                       outbp += strlen(outbp);
+                               }
+                       } else {
+                               if (!check_cycles(exc)) {
+                                       errflag |= 1 << 8;
+                               }
+                       }
+               }
        }
        if (errflag && dooutput) {
                addinfo();
@@ -1984,6 +2200,8 @@ static uae_u8 *validate_test(uae_u8 *p, int ignore_errors, int ignore_sr)
                                outbp += strlen(outbp);
                                if (exception_stored) {
                                        hexdump(last_exception, exception_stored);
+                               } else {
+                                       *outbp++ = '\n';
                                }
                        }
                        if ((exc == 3 || exc == 2) && cpu_lvl == 0) {
@@ -2021,6 +2239,34 @@ static void store_addr(uae_u32 s, uae_u8 *d)
        }
 }
 
+#ifdef AMIGA
+static const int interrupt_levels[] =
+{
+       0, 1, 1, 1, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, -1
+};
+
+static void set_interrupt(void)
+{
+       if (interrupt_count < 15) {
+               volatile uae_u16 *intena = (uae_u16*)0xdff09a;
+               volatile uae_u16 *intreq = (uae_u16*)0xdff09c;
+               uae_u16 mask = 1 << interrupt_count;
+               *intena = mask | 0x8000 | 0x4000;
+               *intreq = mask | 0x8000;
+       }
+       interrupt_count++;
+       interrupt_count &= 15;
+}
+
+static void clear_interrupt(void)
+{
+       volatile uae_u16 *intena = (uae_u16*)0xdff09a;
+       volatile uae_u16 *intreq = (uae_u16*)0xdff09c;
+       *intena = 0x7fff;
+       *intreq = 0x7fff;
+}
+#endif
+
 static void process_test(uae_u8 *p)
 {
        outbp = outbuffer;
@@ -2036,10 +2282,14 @@ static void process_test(uae_u8 *p)
 
        endpc = opcode_memory_addr;
        startpc = opcode_memory_addr;
-
        start_test();
 
        test_ccrignoremask = 0xffff;
+
+#ifdef AMIGA
+       interrupt_count = 0;
+       clear_interrupt();
+#endif
        ahcnt = 0;
 
        for (;;) {
@@ -2134,6 +2384,7 @@ static void process_test(uae_u8 *p)
                                regs.msp = super_stack_memory;
                                regs.pc = startpc;
                                regs.fpiar = startpc;
+                               regs.cyclest = 0xffffffff;
 
 #ifdef M68K
                                if (stackcopysize > 0)
@@ -2168,6 +2419,20 @@ static void process_test(uae_u8 *p)
                                        old_super = super;
                                }
 
+                               if (exitcnt >= 0) {
+                                       exitcnt--;
+                                       if (exitcnt < 0) {
+                                               addinfo();
+                                               strcat(outbp, "Registers before:\n");
+                                               outbp += strlen(outbp);
+                                               out_regs(&regs, 1);
+                                               end_test();
+                                               printf(outbuffer);
+                                               printf("\nExit count expired\n");
+                                               exit(0);
+                                       }
+                               }
+
                                if ((*p) == CT_END_SKIP) {
 
                                        p++;
@@ -2180,10 +2445,18 @@ static void process_test(uae_u8 *p)
                                        if ((ccr_mask & ccr) || (ccr == 0)) {
 
                                                reset_error_vectors();
+
 #if 0
                                                volatile int *tn = (volatile int*)0x100;
                                                *tn = testcnt;
 #endif
+
+#ifdef AMIGA
+                                               if (interrupttest) {
+                                                       set_interrupt();
+                                               }
+#endif
+
                                                if (cpu_lvl == 1) {
                                                        execute_test010(&test_regs);
                                                } else if (cpu_lvl >= 2) {
@@ -2196,6 +2469,12 @@ static void process_test(uae_u8 *p)
                                                        execute_test000(&test_regs);
                                                }
 
+#ifdef AMIGA
+                                               if (interrupttest) {
+                                                       clear_interrupt();
+                                               }
+#endif
+
                                                if (ccr_mask == 0 && ccr == 0)
                                                        ignore_sr = 1;
 
@@ -2326,6 +2605,7 @@ static int test_mnemo(const char *opcode)
        lvl = (lvl_mask >> 16) & 15;
        interrupt_mask = (lvl_mask >> 20) & 7;
        addressing_mask = (lvl_mask & 0x80000000) ? 0xffffffff : 0x00ffffff;
+       interrupttest = (lvl_mask >> 26) & 1;
        sr_undefined_mask = lvl_mask & 0xffff;
        safe_memory_mode = (lvl_mask >> 23) & 3;
        fpu_model = read_u32(headerfile, &headoffset);
@@ -2372,11 +2652,19 @@ static int test_mnemo(const char *opcode)
        }
 
        low_memory_offset = 0;
-       high_memory_offset = 0;
-       if (test_low_memory_start != 0xffffffff)
+       if (test_low_memory_start != 0xffffffff) {
                low_memory_offset = test_low_memory_start;
-       if (test_high_memory_start != 0xffffffff)
+       } else {
+               low_memory_offset = 0x100;
+               test_low_memory_end = 0xffffffff;
+       }
+
+       high_memory_offset = 0;
+       if (test_high_memory_start != 0xffffffff) {
                high_memory_offset = test_high_memory_start & 0x7fff;
+       } else {
+               test_high_memory_end = 0xffffffff;
+       }
 
        if (!absallocated) {
                test_memory = allocate_absolute(test_memory_addr, test_memory_size);
@@ -2407,14 +2695,14 @@ static int test_mnemo(const char *opcode)
        printf("Test: %08lx-%08lx Safe: %08lx-%08lx\n",
                test_memory_addr, test_memory_end,
                safe_memory_start, safe_memory_end);
-       printf("%s:\n", inst_name);
+       printf("%s (%s):\n", inst_name, group);
 
        testcnt = 0;
        memset(exceptioncount, 0, sizeof(exceptioncount));
        supercnt = 0;
 
        for (;;) {
-               printf("%s. %lu...\n", tfname, testcnt);
+               printf("%s (%s). %lu...\n", tfname, group, testcnt);
 
                sprintf(tfname, "%s/%04ld.dat", opcode, filecnt);
 
@@ -2502,15 +2790,13 @@ static int getparamval(const char *p)
 static int isdir(const char *dirpath, const char *name)
 {
        struct stat buf;
-       char path[FILENAME_MAX];
 
-       snprintf(path, sizeof(path), "%s%s", dirpath, name);
-       return stat(path, &buf) == 0 && S_ISDIR(buf.st_mode);
+       snprintf(tmpbuffer, sizeof(tmpbuffer), "%s%s", dirpath, name);
+       return stat(tmpbuffer, &buf) == 0 && S_ISDIR(buf.st_mode);
 }
 
 int main(int argc, char *argv[])
 {
-       char opcode[16];
        int stop_on_error = 1;
 
        atexit(freestuff);
@@ -2554,153 +2840,233 @@ int main(int argc, char *argv[])
 #endif
 
        if (argc < 2) {
-               printf("cputest <all/mnemonic> (<start mnemonic>) (continue)\n");
+               printf("cputest (<group>)/<all/mnemonic> (<start mnemonic>) (other params)\n");
                printf("mnemonic = test single mnemonic\n");
                printf("all = test all\n");
                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 (all mode only)\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");
-               printf("askifmissing = ask for new path if dat file is missing.\n");
+               printf("all <mnemonic> -next = test all, starting after <mnemonic>\n");
+               printf("-continue = don't stop on error (all mode only)\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");
+               printf("-askifmissing = ask for new path if dat file is missing.\n");
+               printf("-exit n = exit after n tests.\n");
+               printf("-cycles [range adjust] = check cycle counts.\n");
                return 0;
        }
 
-       if (strlen(argv[1]) >= sizeof(opcode) - 1)
-               return 0;
-
-       strcpy(opcode, argv[1]);
+       opcode[0] = 0;
+       strcpy(group, "default");
 
        check_undefined_sr = 1;
        ccr_mask = 0xff;
        disasm = 1;
+       exitcnt = -1;
+
        for (int i = 1; i < argc; i++) {
                char *s = argv[i];
                char *next = i + 1 < argc ? argv[i + 1] : NULL;
-               if (!_stricmp(s, "continue")) {
+               if (s[0] != '-' && opcode[0] == 0 && strlen(s) < sizeof(opcode) - 1) {
+                       strcpy(opcode, s);
+                       continue;
+               }
+               if (!_stricmp(s, "-continue")) {
                        stop_on_error = 0;
-               } else if (!_stricmp(s, "noundefined")) {
+               } else if (!_stricmp(s, "-noundefined")) {
                        check_undefined_sr = 0;
-               } else if (!_stricmp(s, "ccrmask")) {
+               } else if (!_stricmp(s, "-ccrmask")) {
                        ccr_mask = 0;
                        if (next) {
                                ccr_mask = ~getparamval(next);
                                i++;
                        }
-               } else if (!_stricmp(s, "silent")) {
+               } else if (!_stricmp(s, "-silent")) {
                        dooutput = 0;
-               } else if (!_stricmp(s, "68000")) {
+               } else if (!_stricmp(s, "-68000")) {
                        cpu_lvl = 0;
-               } else if (!_stricmp(s, "68010")) {
+               } else if (!_stricmp(s, "-68010")) {
                        cpu_lvl = 1;
-               } else if (!_stricmp(s, "68020")) {
+               } else if (!_stricmp(s, "-68020")) {
                        cpu_lvl = 2;
-               } else if (!_stricmp(s, "68030")) {
+               } else if (!_stricmp(s, "-68030")) {
                        cpu_lvl = 3;
-               } else if (!_stricmp(s, "68040")) {
+               } else if (!_stricmp(s, "-68040")) {
                        cpu_lvl = 4;
-               } else if (!_stricmp(s, "68060")) {
+               } else if (!_stricmp(s, "-68060")) {
                        cpu_lvl = 5;
-               } else if (!_stricmp(s, "nodisasm")) {
+               } else if (!_stricmp(s, "-nodisasm")) {
                        disasm = 0;
-               } else if (!_stricmp(s, "basicexc")) {
+               } else if (!_stricmp(s, "-basicexc")) {
                        basicexcept = 1;
-               } else if (!_stricmp(s, "askifmissing")) {
+               } else if (!_stricmp(s, "-askifmissing")) {
                        askifmissing = 1;
-               } else if (!_stricmp(s, "next")) {
+               } else if (!_stricmp(s, "-next")) {
                        nextall = 1;
+               } else if (!_stricmp(s, "-exit")) {
+                       if (next) {
+                               exitcnt = atoi(next);
+                               i++;
+                       }
+               } else if (!_stricmp(s, "-cycles")) {
+                       cycles = 1;
+                       cycles_range = 2;
+                       if (i + 1 < argc) {
+                               i++;
+                               cycles_range = atoi(argv[i]);
+                               if (i + 1 < argc) {
+                                       i++;
+                                       cycles_adjust = atoi(argv[i]);
+                               }
+                       }
                }
        }
 
-       sprintf(path + strlen(path), "%lu/", 68000 + (cpu_lvl == 5 ? 6 : cpu_lvl) * 10);
+       DIR *groupd = NULL;
+       
+       char *p = strchr(opcode, '/');
+       if (p) {
+               strcpy(tmpbuffer, opcode);
+               strcpy(group, opcode);
+               group[p - opcode] = 0;
+               strcpy(opcode, tmpbuffer + (p - opcode) + 1);
+       }
+       
+       if (!strcmp(group, "all")) {
+               groupd = opendir(path);
+       }
+
+       int cpumodel = 68000 + (cpu_lvl == 5 ? 6 : cpu_lvl) * 10;
+       sprintf(cpustr, "%lu_", cpumodel);
+       char *pathptr = path + strlen(path);
+
+       for (;;) {
+
+               if (groupd) {
+                       pathptr[0] = 0;
+                       struct dirent *groupdr = readdir(groupd);
+                       if (!groupdr)
+                               break;
+                       if (!isdir(path, groupdr->d_name))
+                               continue;
+                       if (groupdr->d_name[0] == '.')
+                               continue;
+                       if (strnicmp(cpustr, groupdr->d_name, strlen(cpustr)))
+                               continue;
+                       sprintf(pathptr, "%s/", groupdr->d_name);               
+                       strcpy(group, groupdr->d_name + strlen(cpustr));
+               } else {
+                       sprintf(pathptr, "%lu_%s/",cpumodel, group);
+               }
 
-       low_memory_size = -1;
-       low_memory_temp = load_file(path, "lmem.dat", NULL, &low_memory_size, 0, 1);
-       high_memory_size = -1;
-       high_memory_temp = load_file(path, "hmem.dat", NULL, &high_memory_size, 0, 1);
+               low_memory_size = -1;
+               low_memory_temp = load_file(path, "lmem.dat", NULL, &low_memory_size, 0, 1);
+               high_memory_size = -1;
+               high_memory_temp = load_file(path, "hmem.dat", NULL, &high_memory_size, 0, 1);
 
 #ifndef M68K
-       if (low_memory_size > 0)
-               low_memory = calloc(1, low_memory_size);
-       if (high_memory_size > 0)
-               high_memory = calloc(1, high_memory_size);
+               low_memory = calloc(1, 32768);
+               if (high_memory_size > 0)
+                       high_memory = calloc(1, high_memory_size);
 #endif
 
-       if (low_memory_size > 0)
-               low_memory_back = calloc(1, low_memory_size);
-       if (high_memory_size > 0)
-               high_memory_back = calloc(1, high_memory_size);
+               low_memory_back = calloc(1, 32768);
+               if (!low_memory_temp) {
+                       low_memory_temp = calloc(1, 32768);
+               }
 
-       if (!_stricmp(opcode, "all")) {
-               DIR *d = opendir(path);
-               if (!d) {
-                       printf("Couldn't list directory '%s'\n", path);
-                       return 0;
+               if (high_memory_size > 0) {
+                       high_memory_back = calloc(1, high_memory_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;
+                       char *dirs = calloc(MAX_MNEMOS, MAX_FILE_LEN);
+                       int diroff = 0;
+                       if (!dirs)
+                               return 0;
 
-               for (;;) {
-                       struct dirent *dr = readdir(d);
-                       if (!dr)
-                               break;
-                       int d = isdir(path, dr->d_name);
-                       if (d && 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;
+                       for (;;) {
+                               struct dirent *dr = readdir(d);
+                               if (!dr)
+                                       break;
+                               int d = isdir(path, dr->d_name);
+                               if (d && 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);
+                       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);
+                       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) {
-                       first = -1;
-                       for (int i = 0; i < diroff; i += MAX_FILE_LEN) {
-                               if (!_stricmp(dirs + i, argv[2])) {
-                                       first = i;
-                                       break;
+                       int first = 0;
+                       if (argc >= 3 && argv[2][0] != '-') {
+                               first = -1;
+                               for (int i = 0; i < diroff; i += MAX_FILE_LEN) {
+                                       if (!_stricmp(dirs + i, argv[2])) {
+                                               first = i;
+                                               break;
+                                       }
+                               }
+                               if (first < 0) {
+                                       printf("Couldn't find '%s'\n", argv[2]);
+                                       return 0;
                                }
                        }
-                       if (first < 0) {
-                               printf("Couldn't find '%s'\n", argv[2]);
-                               return 0;
+                       if (nextall) {
+                               first += MAX_FILE_LEN;
                        }
-               }
-               if (nextall) {
-                       first += MAX_FILE_LEN;
-               }
-               for (int i = first; i < diroff; i += MAX_FILE_LEN) {
-                       if (test_mnemo(dirs + i)) {
+                       int err = 0;
+                       for (int i = first; i < diroff; i += MAX_FILE_LEN) {
+                               if (test_mnemo(dirs + i)) {
+                                       err = 1;
+                                       if (stop_on_error)
+                                               break;
+                               }
+                       }
+
+                       free(dirs);
+
+                       if (err && stop_on_error)
+                               break;
+
+               } else {
+                       if (test_mnemo(opcode)) {
                                if (stop_on_error)
                                        break;
                        }
                }
 
-               free(dirs);
+               free(low_memory_temp);
+               free(high_memory_temp);
+               free(low_memory_back);
+               free(high_memory_back);
 
-       } else {
-               test_mnemo(opcode);
+               if (!groupd)
+                       break;
        }
 
+       if (groupd)
+               closedir(groupd);
+
        return 0;
 }
index 9baedfa03a46992538dfefbfc93768d97361cda6..1c553904480ad33ef63ab88bf81f1dfa4ec295f1 100644 (file)
@@ -1,5 +1,5 @@
 
-UAE CPU Tester
+UAE 680x0 CPU Tester
 
 I finally wrote utility (This was my "Summer 2019" project) that can be used to verify operation of for example software emulated or FPGA 680x0 CPUs.
 It is based on UAE CPU core (gencpu generated special test core). All the CPU logic comes from UAE CPU core.
@@ -12,6 +12,7 @@ Verifies:
 - Memory writes, including stack modifications (if any)
 - Loop mode for JIT testing. (generates <test instruction>, dbf dn,loop)
 - Supports 68000, 68010, 68020, 68030 (only difference between 020 and 030 seems to be data cache and MMU), 68040 and 68060.
+- Cycle counts (68000 Amiga only)
 
 Tests executed for each tested instruction:
 
@@ -24,9 +25,11 @@ Tests executed for each tested instruction:
 
 Test generation details:
 
-Instruction's effective address is randomized. It is accepted if it points to any of 3 test memory regions. If it points outside of test memory, it will be re-randomized few times. Test will be skipped if current EA makes it impossible to point to any of 3 test regions.
+If normal mode: Instruction's effective address is randomized. It is accepted if it points to any of 3 test memory regions. If it points outside of test memory, it will be re-randomized few times. Test will be skipped if current EA makes it impossible to point to any of 3 test regions.
 If 68000/68010 and address error testing is enabled: 2 extra test rounds are generated, one with even and another with odd EAs to test and verify address errors.
 
+If target EA mode: instruction's effective address always points to configured target address(es). Very useful when testing address or bus errors.
+
 Notes and limitations:
 
 - Test generator is very brute force based, it should be more intelligent.. Now has optional target src/dst/opcode modes for better bus/address error testing.
@@ -35,20 +38,34 @@ Notes and limitations:
 - All tests that would halt or reset the CPU are skipped (RESET in supervisor mode, STOP parameter that would stop the CPU etc)
 - Single instruction test set will take long time to run on real 68000. Few minutes to much longer...
 - Undefined flags (for example DIV and CHK or 68000/010 bus address error) are also verified. It probably would be good idea to optionally filter them out.
-- Instruction cycle order or timing is ignored. It is not possible without extra hardware.
 - FPU testing is not yet fully implemented.
-- Sometimes reported old and new condition code state does not match error report..
 
 Tester compatibility (integer instructions only):
 
-68000: Complete. Including bus and address error stack frame/register/CCR modification undocumented behavior.
-68010: Partially supported.
+68000: Complete. Including bus and address error stack frame/register/CCR modification undocumented behavior. Cycle count support.
+68010: Almost complete. Bus errors are only partially supported. DIVS undefined condition codes are not yet supported.
 68020: Almost complete (DIV undocumented behavior is not yet known)
 68030: Same as 68020.
 68040: Almost complete (Weird unaligned MOVE16 behavior which may be board specific).
 68060: Same as 68040.
 
-More CPU details in WinUAE changelog.
+68000 cycle count testing:
+
+Cycle counting requires 100% accurate timing also for following instructions:
+- BSR.B
+- NOP
+- MOVE.W ABS.L,ABS.L
+- MOVE SR,-(SP)
+- RTE
+- Illegal instruction exception
+- If instruction internally generates exception, internal exception also needs to be cycle-accurate.
+
+0xDFF006 is used for cycle counting = accuracy will be +-2 CPU cycles. 0xDFF006 behavior must be accurate.
+Currently only supported hardware for cycle counting is 7MHz 68000 PAL Amiga with real Fast RAM.
+
+Bus error cycle counting is not yet supported.
+
+--
 
 Not implemented or only partially implemented:
 
@@ -60,7 +77,7 @@ Not implemented or only partially implemented:
 
 All models:
 
-- Interrupts (stack frames and STOP)
+- STOP test only checks immediate values that do not stop the CPU.
 - MMU instructions (Not going to happen)
 - 68020+ cache related instructions.
 - FPU FSAVE/FRESTORE, FPU support also isn't fully implemented yet.
@@ -72,6 +89,9 @@ Build instructions:
 - build cputestgen project.
 - build native Amiga project (cputest directory). Assembly files probably only compiles with Bebbo's GCC.
 
+More CPU details in WinUAE changelog.
+
+--
 
 Test generator quick instructions:
 
@@ -99,3 +119,12 @@ cputest tst.b = run tst.b tests only
 cputest all tst.b = run tst.b, then tst.w and so on in alphabetical order until end or mismatch is detected.
 
 If mismatch is detected, opcode word(s), instruction disassembly, registers before and after and reason message is shown on screen. If difference is in exception stack frame, both expected and returned stack frame is shown in hexadecimal.
+
+--
+
+Change log:
+
+- Cycle count validation (Amiga, 68000 only), including exceptions (except bus errors).
+- Interrupt testing (Amiga only, INTREQ bits set one by one, validate correct exception).
+- Multiple test sets can be generated and tested in single step.
+- Stack usage reduced, gzip decompression works with default 4096 byte stack.
index acfe3100b1e2989b49b4aa641731cc313d6b7f15..e24a7544362d0000a83a7ea7c616fbd20ac5a63e 100644 (file)
@@ -6255,6 +6255,10 @@ static void gen_opcode (unsigned int opcode)
                                if (curi->smode >= Ad16 && cpu_level == 1 && using_prefetch) {
                                        dummy_prefetch("srca", NULL);
                                }
+                               if (curi->smode == Ad16 || curi->smode == absw || curi->smode == PC16)
+                                       addcycles000(2);
+                               if (curi->smode == Ad8r || curi->smode == PC8r)
+                                       addcycles000(6);
                                printf("\t\texception3i(opcode, srca);\n");
                                write_return_cycles("\t\t", 0);
                                printf("\t}\n");
@@ -6339,6 +6343,10 @@ static void gen_opcode (unsigned int opcode)
                        if (curi->smode >= Ad16 && cpu_level == 1 && using_prefetch) {
                                dummy_prefetch("srca", NULL);
                        }
+                       if (curi->smode == Ad16 || curi->smode == absw || curi->smode == PC16)
+                               addcycles000(2);
+                       if (curi->smode == Ad8r || curi->smode == PC8r)
+                               addcycles000(6);
                        printf("\t\texception3i(opcode, srca);\n");
                        write_return_cycles("\t\t", 0);
                        printf("\t}\n");
@@ -8288,7 +8296,12 @@ static void generate_cpu_test(int mode)
        using_exception_3 = 1;
        using_simple_cycles = 1;
 
-       if (mode == 1) {
+       if (mode == 0) {
+               using_simple_cycles = 0;
+               using_ce = 1;
+       } else if (mode == 1) {
+               using_simple_cycles = 0;
+               using_ce = 1;
                cpu_level = 1;
        } else if (mode == 2) {
                cpu_level = 2;
index 550065f073677ad8fd5dc3761524e0d4aeacdfbf..bbfd0e31c501d6fd7eb69c85a41fc6d58f1309be 100644 (file)
@@ -38,6 +38,10 @@ extern int movem_index1[256];
 extern int movem_index2[256];
 extern int movem_next[256];
 
+void ipl_fetch(void);
+void do_cycles_test(int);
+int intlev(void);
+
 uae_u16 get_word_test_prefetch(int);
 uae_u16 get_wordi_test(int);
 
@@ -55,6 +59,9 @@ uaecptr m68k_getpci(void);
 void m68k_setpci_j(uaecptr);
 void m68k_do_rtsi(void);
 void m68k_do_bsri(uaecptr, uae_s32);
+void m68k_do_bsr_ce(uaecptr, uae_s32);
+void m68k_do_bsr_ce(uaecptr oldpc, uae_s32 offset);
+void m68k_do_jsr_ce(uaecptr oldpc, uaecptr dest);
 
 void m68k_setstopped(void);
 void check_t0_trace(void);
diff --git a/ini.cpp b/ini.cpp
index 4e555ff04aa682566e682c256cff1414352b3e29..af3c45d6d52c68fe34357982ab3e0ffb80f348a9 100644 (file)
--- a/ini.cpp
+++ b/ini.cpp
@@ -446,6 +446,30 @@ bool ini_getdata(struct ini_data *ini, const TCHAR *section, const TCHAR *key, u
        return ini_getdata_multi(ini, section, key, out, size, NULL);
 }
 
+bool ini_getsection(struct ini_data *ini, int idx, TCHAR **section)
+{
+       const TCHAR *sptr = NULL;
+       for (int c = 0; c < ini->inilines; c++) {
+               struct ini_line *il = ini->inidata[c];
+               if (il) {
+                       if (!sptr) {
+                               sptr = il->section;
+                       }
+                       if (!sptr)
+                               continue;
+                       if (_tcsicmp(sptr, il->section)) {
+                               idx--;
+                               if (idx < 0) {
+                                       *section = my_strdup(il->section);
+                                       return true;
+                               }
+                               sptr = il->section;
+                       }
+               }
+       }
+       return false;
+}
+
 bool ini_getsectionstring(struct ini_data *ini, const TCHAR *section, int idx, TCHAR **keyout, TCHAR **valout)
 {
        for (int c = 0; c < ini->inilines; c++) {