From 16c23db543f0986eefc5a21af9c9d844c06d05aa Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Thu, 8 Aug 2019 19:29:06 +0300 Subject: [PATCH] 24/32-bit addressing support. Loop mode testing (JIT testing), enable/disable option for low/high memory. --- cputest.cpp | 161 +++++++++++++++++++++++++++++--------- cputest/asm.S | 9 ++- cputest/cputest_defines.h | 1 + cputest/cputestgen.ini | 17 +++- cputest/main.c | 99 +++++++++++++++++++---- 5 files changed, 229 insertions(+), 58 deletions(-) diff --git a/cputest.cpp b/cputest.cpp index 1f5149f5..d5fc3a2d 100644 --- a/cputest.cpp +++ b/cputest.cpp @@ -56,6 +56,8 @@ static int verbose = 1; static int feature_exception3_data = 0; static int feature_exception3_instruction = 0; static int feature_sr_mask = 0; +static int feature_loop_mode = 0; +static int feature_loop_mode_register = -1; static int feature_full_extension_format = 0; static uae_u32 feature_addressing_modes[2]; static int ad8r[2], pc8r[2]; @@ -126,7 +128,7 @@ static bool valid_address(uaecptr addr, int size, int w) addr &= addressing_mask; size--; if (addr + size < LOW_MEMORY_END) { - if (addr < test_low_memory_start) + if (addr < test_low_memory_start || test_low_memory_start == 0xffffffff) goto oob; // exception vectors needed during tests if ((addr + size >= 0x0c && addr < 0x30 || (addr + size >= 0x80 && addr < 0xc0)) && regs.vbr == 0) @@ -138,7 +140,7 @@ static bool valid_address(uaecptr addr, int size, int w) return 1; } if (addr >= HIGH_MEMORY_START && addr < HIGH_MEMORY_START + 0x8000) { - if (addr < test_high_memory_start) + if (addr < test_high_memory_start || test_high_memory_start == 0xffffffff) goto oob; if (addr + size >= test_high_memory_end) goto oob; @@ -842,11 +844,15 @@ static void save_memory(const TCHAR *path, const TCHAR *name, uae_u8 *p, int siz -static uae_u8 *store_rel(uae_u8 *dst, uae_u8 mode, uae_u32 s, uae_u32 d) +static uae_u8 *store_rel(uae_u8 *dst, uae_u8 mode, uae_u32 s, uae_u32 d, int ordered) { int diff = (uae_s32)d - (uae_s32)s; - if (diff == 0) + if (diff == 0) { + if (!ordered) + return dst; + *dst++ = CT_EMPTY; return dst; + } if (diff >= -128 && diff < 128) { *dst++ = mode | CT_RELATIVE_START_BYTE; *dst++ = diff & 0xff; @@ -1051,7 +1057,7 @@ 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 << 16) | lmem_rom); + 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); @@ -1140,6 +1146,14 @@ static int create_ea(uae_u16 *opcodep, uaecptr pc, int mode, int reg, struct ins switch (mode) { case Dreg: + if (reg == feature_loop_mode_register) { + if (((dp->sduse & 0x20) && !srcdst) || ((dp->sduse & 0x02) && srcdst)) { + int pos = srcdst ? dp->dpos : dp->spos; + opcode &= ~(7 << pos); + opcode |= ((reg + 1) & 7) << pos; + } + } + break; case Areg: case Aind: case Aipi: @@ -1364,7 +1378,7 @@ static int handle_specials_stack(uae_u16 opcode, uaecptr pc, struct instr *dp, i addr += 2; offset += 2; *isconstant = imm_special >= (1 << (0 + 5)) * 4 ? 0 : -1; - } else if (opcode == 0x4e77) { + } else if (opcode == 0x4e74) { // RTD v = imm_special >> 2; uae_u16 sr = v & 31; @@ -1413,7 +1427,7 @@ static int handle_specials_stack(uae_u16 opcode, uaecptr pc, struct instr *dp, i return offset; } -static void execute_ins(uae_u16 opc) +static void execute_ins(uae_u16 opc, uaecptr endpc, uaecptr targetpc) { uae_u16 opw1 = (opcode_memory[2] << 8) | (opcode_memory[3] << 0); uae_u16 opw2 = (opcode_memory[4] << 8) | (opcode_memory[5] << 0); @@ -1431,22 +1445,55 @@ static void execute_ins(uae_u16 opc) testing_active = 1; - if (SPCFLAG_TRACE) - do_trace(); + int cnt = feature_loop_mode * 2; + + for (;;) { + + if (SPCFLAG_TRACE) + do_trace(); + + (*cpufunctbl[opc])(opc); + + if (!test_exception) { + if (SPCFLAG_DOTRACE) + Exception(9); + + if (cpu_stopped && regs.s == 0 && currprefs.cpu_model <= 68010) { + // 68000/68010 undocumented special case: + // if STOP clears S-bit and T was not set: + // cause privilege violation exception, PC pointing to following instruction. + // If T was set before STOP: STOP works as documented. + cpu_stopped = 0; + Exception(8); + } + } + + if (regs.pc == endpc || regs.pc == targetpc) + break; + + if (test_exception) + break; + + if (!valid_address(regs.pc, 2, 0)) + break; - (*cpufunctbl[opc])(opc); + if (!feature_loop_mode) { + wprintf(_T("Test instruction didn't finish in single step in non-loop mode!?\n")); + abort(); + } - if (!test_exception) { - if (SPCFLAG_DOTRACE) - Exception(9); + if (cpu_lvl < 2) { + opc = get_word_test_prefetch(2); + m68k_incpc(2); + } else { + opc = get_word_test_prefetch(0); + m68k_incpc(2); + } - if (cpu_stopped && regs.s == 0 && currprefs.cpu_model <= 68010) { - // 68000/68010 undocumented special case: - // if STOP clears S-bit and T was not set: - // cause privilege violation exception, PC pointing to following instruction. - // If T was set before STOP: STOP works as documented. - cpu_stopped = 0; - Exception(8); + cnt--; + if (cnt <= 0) { + wprintf(_T("Loop mode didn't end!?\n")); + abort(); } } @@ -1513,6 +1560,13 @@ static int isunsupported(struct instr *dp) } +static uae_u8 *save_exception(uae_u8 *p) +{ + uae_u8 size = 0; + *p++ = size; + return p; +} + static const TCHAR *sizes[] = { _T("B"), _T("W"), _T("L") }; static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, int opcodesize, int fpuopcode) @@ -1633,6 +1687,12 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, int opcodesize, in if (quick) break; + if (feature_loop_mode) { + regs.regs[feature_loop_mode_register] &= 0xffff0000; + regs.regs[feature_loop_mode_register] |= feature_loop_mode - 1; + cur_registers[feature_loop_mode_register] = regs.regs[feature_loop_mode_register]; + } + for (int i = 0; i < MAX_REGISTERS; i++) { dst = store_reg(dst, CT_DREG + i, 0, cur_registers[i], -1); regs.regs[i] = cur_registers[i]; @@ -1731,10 +1791,8 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, int opcodesize, in ) printf(""); - if (opc != opcode) { - // source EA modified opcode - dp = table68k + opc; - } + // if source EA modified opcode + dp = table68k + opc; // create destination addressing mode if (dp->duse) { @@ -1749,6 +1807,9 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, int opcodesize, in pc += o; } + // if destination EA modified opcode + dp = table68k + opc; + uae_u8 *bo = opcode_memory + 2; uae_u16 bopw1 = (bo[0] << 8) | (bo[1] << 0); uae_u16 bopw2 = (bo[2] << 8) | (bo[3] << 0); @@ -1762,6 +1823,14 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, int opcodesize, in pc += handle_specials_branch(opc, pc, dp, &isconstant_src); put_word_test(opcode_memory_start, opc); + + // loop mode + if (feature_loop_mode) { + // dbf dn, opcode_memory_start + put_long_test(pc, ((0x51c8 | feature_loop_mode_register) << 16) | ((opcode_memory_start - pc - 2) & 0xffff)); + pc += 4; + } + // end word, needed to detect if instruction finished normally when // running on real hardware. put_word_test(pc, 0x4afc); // illegal instruction @@ -1812,6 +1881,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, int opcodesize, in abort(); } #endif + uaecptr branch_target = 0xffffffff; int bc = isbranchinst(dp); if (bc) { if (bc < 0) { @@ -1849,6 +1919,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, int opcodesize, in } else { // branch target = generate exception put_word_test(srcaddr, 0x4afc); + branch_target = srcaddr; dst = store_mem(dst, 1); memcpy(&ahist2, &ahist, sizeof(struct accesshistory) *MAX_ACCESSHIST); ahcnt2 = ahcnt; @@ -1956,7 +2027,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, int opcodesize, in if (regs.sr & 0x2000) prev_s_cnt++; - execute_ins(opc); + execute_ins(opc, pc - 2, branch_target); if (regs.s) s_cnt++; @@ -2030,7 +2101,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, int opcodesize, in last_sr = regs.sr; } if (regs.pc != last_pc) { - dst = store_rel(dst, CT_PC, last_pc, regs.pc); + dst = store_rel(dst, CT_PC, last_pc, regs.pc, 0); last_pc = regs.pc; } if (currprefs.fpu_model) { @@ -2043,7 +2114,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, int opcodesize, in } } if (regs.fpiar != last_fpiar) { - dst = store_rel(dst, CT_FPIAR, last_fpiar, regs.fpiar); + dst = store_rel(dst, CT_FPIAR, last_fpiar, regs.fpiar, 0); last_fpiar = regs.fpiar; } if (regs.fpsr != last_fpsr) { @@ -2058,6 +2129,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, int opcodesize, in dst = store_mem(dst, 0); if (test_exception) { *dst++ = CT_END | test_exception; + dst = save_exception(dst); } else { *dst++ = CT_END; } @@ -2172,6 +2244,7 @@ int __cdecl main(int argc, char *argv[]) { const struct cputbl *tbl = NULL; TCHAR path[1000]; + int v; struct ini_data *ini = ini_load(_T("cputestgen.ini"), false); if (!ini) { @@ -2185,6 +2258,16 @@ int __cdecl main(int argc, char *argv[]) wprintf(_T("Unsupported CPU model.\n")); return 0; } + + currprefs.address_space_24 = 1; + addressing_mask = 0x00ffffff; + v = 24; + ini_getval(ini, INISECTION, _T("cpu_address_space"), &v); + if (v == 32) { + currprefs.address_space_24 = 0; + addressing_mask = 0xffffffff; + } + currprefs.fpu_model = 0; currprefs.fpu_mode = 1; ini_getval(ini, INISECTION, _T("fpu"), &currprefs.fpu_model); @@ -2211,6 +2294,12 @@ int __cdecl main(int argc, char *argv[]) ini_getval(ini, INISECTION, _T("feature_exception3_instruction"), &feature_exception3_instruction); feature_sr_mask = 0; ini_getval(ini, INISECTION, _T("feature_sr_mask"), &feature_sr_mask); + feature_loop_mode = 0; + ini_getval(ini, INISECTION, _T("feature_loop_mode"), &feature_loop_mode); + if (feature_loop_mode) { + feature_loop_mode_register = 7; + } + feature_full_extension_format = 0; if (currprefs.cpu_model > 68000) { ini_getval(ini, INISECTION, _T("feature_full_extension_format"), &feature_full_extension_format); @@ -2221,6 +2310,7 @@ int __cdecl main(int argc, char *argv[]) pc8r[1] |= 2; } } + 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)) { @@ -2280,7 +2370,7 @@ int __cdecl main(int argc, char *argv[]) xorshiftstate = 1; - int v = 0; + v = 0; ini_getval(ini, INISECTION, _T("test_memory_start"), &v); if (!v) { wprintf(_T("test_memory_start is required\n")); @@ -2297,8 +2387,8 @@ int __cdecl main(int argc, char *argv[]) test_memory_size = v; test_memory_end = test_memory_start + test_memory_size; - test_low_memory_start = 0x0000; - test_low_memory_end = 0x8000; + test_low_memory_start = 0xffffffff; + test_low_memory_end = 0xffffffff; v = 0; if (ini_getval(ini, INISECTION, _T("test_low_memory_start"), &v)) test_low_memory_start = v; @@ -2306,8 +2396,8 @@ int __cdecl main(int argc, char *argv[]) if (ini_getval(ini, INISECTION, _T("test_low_memory_end"), &v)) test_low_memory_end = v; - test_high_memory_start = 0x00ff8000; - test_high_memory_end = 0x01000000; + test_high_memory_start = 0xffffffff; + test_high_memory_end = 0xffffffff; v = 0; if (ini_getval(ini, INISECTION, _T("test_high_memory_start"), &v)) test_high_memory_start = v; @@ -2329,7 +2419,7 @@ int __cdecl main(int argc, char *argv[]) TCHAR *lmem_rom_name = NULL; ini_getstring(ini, INISECTION, _T("low_rom"), &lmem_rom_name); - if (lmem_rom_name) { + if (lmem_rom_name && test_low_memory_start != 0xffffffff) { if (load_file(NULL, lmem_rom_name, low_memory_temp, 32768, 0)) { wprintf(_T("Low test memory ROM loaded\n")); lmem_rom = 1; @@ -2339,7 +2429,7 @@ int __cdecl main(int argc, char *argv[]) TCHAR *hmem_rom_name = NULL; ini_getstring(ini, INISECTION, _T("high_rom"), &hmem_rom_name); - if (hmem_rom_name) { + if (hmem_rom_name && test_high_memory_start != 0xffffffff) { if (load_file(NULL, hmem_rom_name, high_memory_temp, 32768, -1)) { wprintf(_T("High test memory ROM loaded\n")); hmem_rom = 1; @@ -2371,15 +2461,12 @@ int __cdecl main(int argc, char *argv[]) if (currprefs.cpu_model == 68000) { tbl = op_smalltbl_90_test_ff; cpu_lvl = 0; - addressing_mask = 0x00ffffff; } else if (currprefs.cpu_model == 68010) { tbl = op_smalltbl_91_test_ff; cpu_lvl = 1; - addressing_mask = 0x00ffffff; } else if (currprefs.cpu_model == 68020) { tbl = op_smalltbl_92_test_ff; cpu_lvl = 2; - addressing_mask = 0x00ffffff; } else { wprintf(_T("Unsupported CPU model.\n")); abort(); diff --git a/cputest/asm.S b/cputest/asm.S index 01a3c5e4..fbe8bf15 100644 --- a/cputest/asm.S +++ b/cputest/asm.S @@ -13,6 +13,7 @@ .globl _setcpu .globl _flushcache +| must match main.c S_DREG = 0 S_AREG = S_DREG+8*4 S_SSP = S_AREG+8*4 @@ -20,7 +21,8 @@ S_MSP = S_SSP+4 S_PC = S_MSP+4 S_SR = S_PC+4 S_EXC = S_SR+4 -S_FPU = S_EXC+4 +S_EXCFRAME = S_EXC+4 +S_FPU = S_EXCFRAME+4 S_FPIAR = S_FPU+8*12 S_FPCR = S_FPIAR+4 S_FPSR = S_FPCR+4 @@ -241,6 +243,7 @@ exception: addq.w #2,d0 move.w d0,S_EXC+2(a0) + move.l sp,S_EXCFRAME(a0) cmp.w #3,d0 bne.s .noaddresserror move.w (sp),S_EXC+0(a0) @@ -263,13 +266,14 @@ _exception010: movem.l d0-d7/a0-a6,(a0) move.l (sp)+,8*4(a0) + move.l sp,S_EXCFRAME(a0) move.w (sp)+,S_SR+2(a0) move.l (sp)+,S_PC(a0) move.w (sp),d0 and.w #0xfff,d0 lsr.w #2,d0 move.w d0,S_EXC+2(a0) - + move.l USP,a1 move.l a1,S_AREG+7*4(a0) @@ -284,6 +288,7 @@ _exception020: movem.l d0-d7/a0-a6,(a0) move.l (sp)+,8*4(a0) + move.l sp,S_EXCFRAME(a0) move.w (sp)+,S_SR+2(a0) move.l (sp)+,S_PC(a0) move.w (sp),d0 diff --git a/cputest/cputest_defines.h b/cputest/cputest_defines.h index 35044293..169a496d 100644 --- a/cputest/cputest_defines.h +++ b/cputest/cputest_defines.h @@ -33,3 +33,4 @@ #define CT_END_FINISH 0xff #define CT_END_INIT (0x80 | 0x40) #define CT_END_SKIP (0x80 | 0x40 | 0x01) +#define CT_EMPTY CT_END_INIT diff --git a/cputest/cputestgen.ini b/cputest/cputestgen.ini index ca12bd0c..8274d408 100644 --- a/cputest/cputestgen.ini +++ b/cputest/cputestgen.ini @@ -3,7 +3,10 @@ ; CPU model (68000, 68020). ; Always select 68020 when testing FPU instructions, even if test hardware CPU is 68040 or 68060. -cpu=68000 +cpu=68020 + +; CPU address space. 24-bit or 32-bit. +cpu_address_space=32 ; FPU model (empty string or 0, 68881, 68882, 68040, 68060) ; Enable only when testing FPU. Enabled FPU mode will slow down execution. @@ -20,8 +23,8 @@ test_low_memory_start=0x0000 test_low_memory_end=0x8000 ; High address space limits (0x00ff8000 to 0x01000000 is complete space) -test_high_memory_start=0x00ff8000 -test_high_memory_end=0x01000000 +;test_high_memory_start=0x00ff8000 +;test_high_memory_end=0x01000000 ; ROM high address space high_rom=D:\amiga\roms\Kickstart v3.1 rev 40.63 (1993)(Commodore)(A500-A600-A2000)[!].rom @@ -50,6 +53,11 @@ feature_exception3_instruction=1 ; Note: instructions that generate privilege violation exception will automatically add extra S=1 round. feature_sr_mask=0x0000 +; generate loop test: label: dbf dn,label +; value: 0 = disabled, >0 = number of loops +feature_loop_mode=10 +feature_loop_mode_register=7 + ; 68020+ addressing modes (this makes test files much larger if other addressing modes are also enabled) ; currently does not generate any reserved mode bit combinations. feature_full_extension_format=0 @@ -63,4 +71,5 @@ feature_addressing_modes_dst= ; mnemonics separated by comma or all. ; all = generate all. tst = generate tst.b, tst.w and tst.l. tst.l = generate only tst.l -mode=abcd,mv2sr,mvsr2 +mode=not.b + diff --git a/cputest/main.c b/cputest/main.c index 0804ec62..81be8d0a 100644 --- a/cputest/main.c +++ b/cputest/main.c @@ -33,6 +33,7 @@ struct fpureg uae_u32 m[2]; }; +// must match asm.S struct registers { uae_u32 regs[16]; @@ -41,6 +42,7 @@ struct registers uae_u32 pc; uae_u32 sr; uae_u32 exc; + uae_u32 excframe; struct fpureg fpuregs[8]; uae_u32 fpiar, fpcr, fpsr; }; @@ -202,13 +204,13 @@ static void start_test(void) return; #ifndef _MSC_VER - if (lmem_rom) { + if (lmem_rom > 0) { if (memcmp(low_memory, low_memory_temp, 32768)) { printf("Low memory ROM mismatch!\n"); exit(0); } } - if (hmem_rom) { + if (hmem_rom > 0) { if (memcmp(high_memory, high_memory_temp, 32768)) { printf("High memory ROM mismatch!\n"); exit(0); @@ -740,6 +742,64 @@ static void out_regs(struct registers *r, int before) } +static void hexdump(uae_u8 *p, int len) +{ + for (int i = 0; i < len; i++) { + if (i > 0) + *outbp++ = '.'; + sprintf(outbp, "%02x", p[i]); + outbp += strlen(outbp); + } + *outbp++ = '\n'; +} + +static void validate_exception(struct registers *regs, uae_u8 *p) +{ + int exclen = 0; + uae_u8 excmatch[32]; + uae_u8 *sp = (uae_u8*)regs->excframe; + uae_u32 v; + uae_u8 excdatalen = *p++; + + if (!excdatalen) + return; + + if (cpu_lvl == 0) { + if (regs->exc == 3) { + // status (with undocumented opcode part) + excmatch[0] = opcode_memory[0]; + excmatch[1] = (opcode_memory[1] & 0xf0) | (*p++); + // access address + v = opcode_memory_addr; + p = restore_rel(p, &v); + pl(excmatch + 2, v); + p += 4; + // opcode + excmatch[6] = opcode_memory[0]; + excmatch[7] = opcode_memory[1]; + // sr + excmatch[8] = regs->sr >> 8; + excmatch[9] = regs->sr; + // pc + pl(excmatch + 10, regs->pc); + exclen = 14; + } + } else { + // sr + excmatch[0] = regs->sr >> 8; + excmatch[1] = regs->sr; + pl(excmatch + 2, regs->pc); + } + if (exclen == 0) + return; + if (memcmp(excmatch, sp, exclen)) { + strcpy(outbp, "Exception stack frame mismatch"); + outbp += strlen(outbp); + hexdump(sp, exclen); + hexdump(excmatch, exclen); + } +} + static uae_u8 *validate_test(uae_u8 *p, int ignore_errors, int ignore_sr) { uae_u8 regs_changed[16] = { 0 }; @@ -808,6 +868,13 @@ static uae_u8 *validate_test(uae_u8 *p, int ignore_errors, int ignore_sr) } break; } + if (exc) { + uae_u8 excdatalen = *p++; + if (exc == cpuexc && excdatalen) { + validate_exception(&test_regs, p); + } + p += excdatalen; + } if (exc != cpuexc) { addinfo(); if (dooutput) { @@ -954,24 +1021,26 @@ static uae_u8 *validate_test(uae_u8 *p, int ignore_errors, int ignore_sr) } } if (!ignore_errors) { - for (int i = 0; i < 16; i++) { - if (regs_changed[i]) { + if (!ignore_sr) { + 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, "%c%d: modified %08lx -> %08lx but expected no modifications\n", i < 8 ? 'D' : 'A', i & 7, last_registers.regs[i], test_regs.regs[i]); + sprintf(outbp, "SR: modified %04x -> %04x but expected no modifications\n", last_registers.sr, test_regs.sr); 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(); @@ -1228,8 +1297,8 @@ static int test_mnemo(const char *path, const char *opcode) fread(data, 1, 4, f); starttimeid = gl(data); fread(data, 1, 4, f); - hmem_rom = gl(data) >> 16; - lmem_rom = gl(data) & 65535; + hmem_rom = (uae_s16)(gl(data) >> 16); + lmem_rom = (uae_s16)(gl(data) & 65535); fread(data, 1, 4, f); test_memory_addr = gl(data); fread(data, 1, 4, f); -- 2.47.3