From 531dccb42604c87737a69f4b1af3c1298065eacd Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Sat, 11 Apr 2020 10:30:47 +0300 Subject: [PATCH] CPU tester FPU support. --- cputest.cpp | 721 ++++++++++++++++++++++++++++++++--------- cputest/asm.S | 70 +++- cputest/asm060.S | 13 + cputest/cputestgen.ini | 49 ++- cputest/main.c | 90 +++-- cputest/makefile | 5 +- cputest/makefile.st | 5 +- cputest/readme.txt | 22 +- debugmem.cpp | 14 +- include/newcpu.h | 1 + 10 files changed, 782 insertions(+), 208 deletions(-) create mode 100644 cputest/asm060.S diff --git a/cputest.cpp b/cputest.cpp index 4e480dec..09452ebf 100644 --- a/cputest.cpp +++ b/cputest.cpp @@ -5,6 +5,7 @@ #include "disasm.h" #include "ini.h" #include "fpp.h" +#include "softfloat/softfloat-specialize.h" #include "zlib.h" @@ -13,6 +14,7 @@ #define MAX_REGISTERS 16 +#define FPUOPP_ILLEGAL 0x80 static floatx80 fpuregisters[8]; static uae_u32 fpu_fpiar, fpu_fpcr, fpu_fpsr; @@ -54,7 +56,8 @@ static int feature_usp = 0; static int feature_exception_vectors = 0; static int feature_interrupts = 0; static int feature_randomize = 0; -static TCHAR *feature_instruction_size = NULL; +static int feature_instruction_size = 0; +static TCHAR *feature_instruction_size_text = NULL; static uae_u32 feature_addressing_modes[2]; static int feature_gzip = 0; static int ad8r[2], pc8r[2]; @@ -65,6 +68,7 @@ static int target_ea_src_cnt, target_ea_dst_cnt, target_ea_opcode_cnt; static int target_ea_src_max, target_ea_dst_max, target_ea_opcode_max; static uae_u32 target_ea[3]; static int maincpu[6]; +static uae_u8 exceptionenabletable[256]; #define HIGH_MEMORY_START (addressing_mask == 0xffffffff ? 0xffff8000 : 0x00ff8000) @@ -118,10 +122,12 @@ static int test_exception_opcode; static uae_u32 trace_store_pc; static uae_u16 trace_store_sr; static int generate_address_mode; +static int test_memory_access_mask; static uae_u8 imm8_cnt; static uae_u16 imm16_cnt; static uae_u32 imm32_cnt; +static uae_u32 immabsw_cnt; static uae_u32 immabsl_cnt; static uae_u32 specials_cnt; static uae_u32 addressing_mask; @@ -187,7 +193,9 @@ static bool valid_address(uaecptr addr, int size, int rwp) goto oob; if (w && lmem_rom) goto oob; - low_memory_accessed = w ? -1 : 1; + if (testing_active) { + low_memory_accessed = w ? -1 : 1; + } return 1; } if (high_memory_size != 0xffffffff && addr >= HIGH_MEMORY_START && addr <= HIGH_MEMORY_START + 0x7fff) { @@ -197,7 +205,9 @@ static bool valid_address(uaecptr addr, int size, int rwp) goto oob; if (w && hmem_rom) goto oob; - high_memory_accessed = w ? -1 : 1; + if (testing_active) { + high_memory_accessed = w ? -1 : 1; + } return 1; } if (addr >= super_stack_memory - RESERVED_SUPERSTACK && addr + size < super_stack_memory) { @@ -229,13 +239,24 @@ static bool valid_address(uaecptr addr, int size, int rwp) if (addr >= opcode_memory_start && addr + size < opcode_memory_start + OPCODE_AREA) goto oob; } - test_memory_accessed = w ? -1 : 1; + if (testing_active) { + test_memory_accessed = w ? -1 : 1; + } return 1; } oob: return 0; } +static bool check_valid_addr(uaecptr addr, int size, int rwp) +{ + if (!valid_address(addr, 1, rwp)) + return false; + if (!valid_address(addr + size - 1, 1, rwp)) + return false; + return true; +} + static bool is_nowrite_address(uaecptr addr, int size) { return addr + size > safe_memory_start && addr < safe_memory_end; @@ -304,6 +325,13 @@ static void check_bus_error(uaecptr addr, int write, int fc) { if (!testing_active) return; + if (!write && (fc & 2)) { + test_memory_access_mask |= 4; + } else if (!write && !(fc & 2)) { + test_memory_access_mask |= 1; + } else if (write) { + test_memory_access_mask |= 2; + } if (safe_memory_start == 0xffffffff && safe_memory_end == 0xffffffff) return; if (addr >= safe_memory_start && addr < safe_memory_end) { @@ -1448,6 +1476,74 @@ static uae_u32 registers[] = 0x00000000 // 15 replaced with stack }; static int regcnts[16]; +static int fpuregcnts[8]; +static float_status fpustatus; + +static bool fpuregchange(int reg, floatx80 *regs) +{ + int regcnt = fpuregcnts[reg]; + floatx80 v = regs[reg]; + floatx80 add; + + switch(reg) + { + case 0: // positive + add = floatx80_div(int32_to_floatx80(1), int32_to_floatx80(10), &fpustatus); + v = floatx80_add(v, add, &fpustatus); + break; + case 1: // negative + add = floatx80_div(int32_to_floatx80(1), int32_to_floatx80(10), &fpustatus); + v = floatx80_sub(v, add, &fpustatus); + break; + case 2: // positive/negative zero + v.high ^= 0x8000; + break; + case 3: + // very large value, larger than fits in double + v = packFloatx80(1, 0x7000 + (rand16() & 0xfff), 0x8000000000000000 | (((uae_u64)rand32()) << 32)); + if (regcnt & 1) { + v.high ^= 0x8000; + } + break; + case 4: + // value that fits in double but does not fit in single + v = packFloatx80(1, 0x700 + rand8(), 0x8000000000000000 | (((uae_u64)rand32()) << 32)); + if (regcnt & 1) { + v.high ^= 0x8000; + } + break; + case 5: + case 6: + // random + v = int32_to_floatx80(rand32()); + for (int i = 0; i < 10; i++) { + uae_u64 n = rand32() | (((uae_u64)rand16()) << 32); + // don't create denormals yet + if (!((v.low + n) & 0x8000000000000000)) { + v.low |= 0x8000000000000000; + continue; + } + v.low += n; + break; + } + break; + case 7: // +NaN, -Nan, +Inf, -Inf + if ((regcnt & 3) == 0) { + v = floatx80_default_nan(NULL); + } else if ((regcnt & 3) == 1) { + v = floatx80_default_nan(NULL); + v.high ^= 0x8000; + } else if ((regcnt & 3) == 2) { + v = packFloatx80(0, 0x7FFF, floatx80_default_infinity_low); + } else if ((regcnt & 3) == 3) { + v = packFloatx80(1, 0x7FFF, floatx80_default_infinity_low); + } + break; + } + fpuregcnts[reg]++; + regs[reg] = v; + return true; +} static bool regchange(int reg, uae_u32 *regs) { @@ -1923,47 +2019,96 @@ static void save_data(uae_u8 *dst, const TCHAR *dir) } static int full_format_cnt; +static int fpu_imm_cnt; + +static const int bytesizes[] = { 4, 4, 12, 12, 2, 8, 1, 12 }; +static int fpuopsize; -static uaecptr putfpuimm(uaecptr pc, int opcodesize, int *isconstant) +static int putfpuimm(uaecptr addr, int opcodesize, int *isconstant) { - // TODO: generate sane FPU immediates + uaecptr start = addr; + switch (opcodesize) { case 0: // L - put_long_test(pc, rand32()); - pc += 4; + put_long_test(addr, rand32()); + addr += 4; break; case 4: // W - put_word_test(pc, rand16()); - pc += 2; + put_word_test(addr, rand16()); + addr += 2; break; case 6: // B - put_word_test(pc, rand16()); - pc += 2; + put_byte_test(addr, rand8()); + addr += 1; break; case 1: // S - put_long(pc, rand32()); - pc += 4; + { + floatx80 v; + if (fpu_imm_cnt & 1) { + v = int32_to_floatx80(rand32()); + } else { + v = fpuregisters[(fpu_imm_cnt >> 1) & 7]; + } + fpu_imm_cnt++; + float32 v2 = floatx80_to_float32(v, &fpustatus); + put_long_test(addr, v2); + addr += 4; break; + } case 2: // X - put_long(pc, rand32()); - put_long(pc + 4, rand32()); - put_long(pc + 8, rand32()); - pc += 12; + { + floatx80 v; + if (fpu_imm_cnt & 1) { + v = int32_to_floatx80(rand32()); + } else { + v = fpuregisters[(fpu_imm_cnt >> 1) & 7]; + } + fpu_imm_cnt++; + put_long_test(addr + 0, v.high); + put_long_test(addr + 4, v.low >> 32); + put_long_test(addr + 8, v.low); + addr += 12; break; + } case 3: // P - put_long(pc, rand32()); - put_long(pc + 4, rand32()); - put_long(pc + 8, rand32()); - pc += 12; + { + fpdata fpd = { 0 }; + if (fpu_imm_cnt & 1) { + fpd.fpx = int32_to_floatx80(rand32()); + } else { + fpd.fpx = fpuregisters[(fpu_imm_cnt >> 1) & 7]; + } + fpu_imm_cnt++; + uae_u32 out[3]; + fpp_from_pack(&fpd, out, (rand8() & 63) - 31); + put_long_test(addr + 0, out[0]); + put_long_test(addr + 4, out[1]); + put_long_test(addr + 8, out[2]); + addr += 12; break; + } case 5: // D - put_long(pc, rand32()); - put_long(pc + 4, rand32()); - pc += 8; + { + floatx80 v; + if (fpu_imm_cnt & 1) { + v = int32_to_floatx80(rand32()); + } else { + v = fpuregisters[(fpu_imm_cnt >> 1) & 7]; + } + fpu_imm_cnt++; + float64 v2 = floatx80_to_float64(v, &fpustatus); + put_long_test(addr + 0, v2 >> 32); + put_long_test(addr + 4, v2); + addr += 8; break; } - return pc; + } + if (out_of_test_space) { + wprintf(_T(" putfpuimm out of bounds access!?")); + abort(); + } + return addr - start; } static int ea_state_found[3]; @@ -2034,8 +2179,10 @@ static int analyze_address(struct instr *dp, int srcdst, uae_u32 addr) return 1; } +static int generate_fpu_memory_read(uae_u16 opcode, uaecptr pc, struct instr *dp, int *isconstant, uae_u32 *eap, int *regused); + // generate mostly random EA. -static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, struct instr *dp, int *isconstant, int srcdst, int fpuopcode, int opcodesize, uae_u32 *eap, int *regused) +static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, struct instr *dp, int *isconstant, int srcdst, int fpuopcode, int opcodesize, uae_u32 *eap, int *regused, int *fpuregused) { uaecptr old_pc = pc; uae_u16 opcode = *opcodep; @@ -2059,6 +2206,8 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str } break; case Areg: + *regused = reg + 8; + break; case Aind: case Aipi: *regused = reg + 8; @@ -2066,7 +2215,11 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str break; case Apdi: *regused = reg + 8; - *eap = cur_registers[reg + 8] - (1 << dp->size); + if (fpuopsize < 0) { + *eap = cur_registers[reg + 8] - (1 << dp->size); + } else { + *eap = cur_registers[reg + 8] - bytesizes[fpuopsize]; + } break; case Ad16: { @@ -2077,8 +2230,13 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str v = rand16(); addr = cur_registers[reg + 8] + (uae_s16)v; *regused = reg + 8; - if (analyze_address(dp, srcdst, addr)) - break; + if (fpuopsize >= 0) { + if (check_valid_addr(addr, bytesizes[fpuopsize], 2)) + break; + } else { + if (analyze_address(dp, srcdst, addr)) + break; + } maxcnt--; if (maxcnt < 0) break; @@ -2098,8 +2256,13 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str for (;;) { v = rand16(); addr = pct + (uae_s16)v; - if (analyze_address(dp, srcdst, addr)) - break; + if (fpuopsize >= 0) { + if (check_valid_addr(addr, bytesizes[fpuopsize], 2)) + break; + } else { + if (analyze_address(dp, srcdst, addr)) + break; + } maxcnt--; if (maxcnt < 0) break; @@ -2139,6 +2302,9 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str addr = mode == PC8r ? pc + 2 - 2 : cur_registers[reg + 8]; *regused = v >> 12; add = cur_registers[v >> 12]; + if (currprefs.cpu_model >= 68020) { + add <<= (v >> 9) & 3; // SCALE + } if (v & 0x0800) { // L addr += add; @@ -2146,14 +2312,16 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str // W addr += (uae_s16)add; } - if (currprefs.cpu_model >= 68020) { - add <<= (v >> 9) & 3; // SCALE - } addr += (uae_s8)(v & 0xff); // DISPLACEMENT - if (other_targetea_same(srcdst, addr)) - continue; - if (analyze_address(dp, srcdst, addr)) - break; + if (fpuopsize >= 0) { + if (check_valid_addr(addr, bytesizes[fpuopsize], 2)) + break; + } else { + if (other_targetea_same(srcdst, addr)) + continue; + if (analyze_address(dp, srcdst, addr)) + break; + } maxcnt--; if (maxcnt < 0) break; @@ -2186,14 +2354,13 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str uaecptr pce = pc; pc += 2; // calculate lenght of extension - ShowEA_disp(&pce, mode == Ad8r ? regs.regs[reg + 8] : pce, NULL, NULL); + *eap = ShowEA_disp(&pce, mode == Ad8r ? regs.regs[reg + 8] : pce, NULL, NULL); while (pc < pce) { v = rand16(); put_word_test(pc, v); pc += 2; } *isconstant = 128; - *eap = 1; } break; } @@ -2204,12 +2371,22 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str return -1; for (;;) { v = rand16(); + if (immabsw_cnt & 1) + v |= 0x8000; + else + v &= ~0x8000; + immabsw_cnt++; if (v >= 0x8000) v |= 0xffff0000; - if (other_targetea_same(srcdst, (uae_s32)(uae_s16)v)) - continue; - if (analyze_address(dp, srcdst, v)) - break; + if (fpuopsize >= 0) { + if (check_valid_addr((uae_s32)(uae_s16)v, bytesizes[fpuopsize], 2)) + break; + } else { + if (other_targetea_same(srcdst, (uae_s32)(uae_s16)v)) + continue; + if (analyze_address(dp, srcdst, v)) + break; + } } put_word_test(pc, v); *isconstant = 16; @@ -2237,10 +2414,15 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str v = opcode_memory_start + offset; } immabsl_cnt++; - if (other_targetea_same(srcdst, v)) - continue; - if (analyze_address(dp, srcdst, v)) - break; + if (fpuopsize >= 0) { + if (check_valid_addr(v, bytesizes[fpuopsize], 2)) + break; + } else { + if (other_targetea_same(srcdst, v)) + continue; + if (analyze_address(dp, srcdst, v)) + break; + } } put_long_test(pc, v); *isconstant = 32; @@ -2249,15 +2431,14 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str break; } case imm: - if (fpuopcode >= 0 && opcodesize < 8) { - pc = putfpuimm(pc, opcodesize, isconstant); + if (fpuopsize >= 0) { + pc += putfpuimm(pc, fpuopsize, isconstant); } else { if (dp->size == sz_long) { put_long_test(pc, rand32()); *isconstant = 32; pc += 4; - } - else { + } else { put_word_test(pc, rand16()); *isconstant = 16; pc += 2; @@ -2283,9 +2464,11 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str { // word immediate if (fpuopcode >= 0) { + int extra = 0; uae_u16 v = 0; - if (opcodesize == 7) { - // FMOVECR + if (opcodesize == 7 && fpuopcode == 0) { + // FMOVECR (which is technically non-existing FMOVE.P + // with Packed-Decimal Real with Dynamic k-Factor. v = 0x4000; v |= opcodesize << 10; v |= imm16_cnt & 0x3ff; @@ -2307,26 +2490,50 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str *isconstant = -1; } else { v |= fpuopcode; - if (imm16_cnt & 1) { - // EA to FP reg + imm16_cnt++; + if ((imm16_cnt & 3) == 0) { + // FPUOP EA,FPx v |= 0x4000; v |= opcodesize << 10; - imm16_cnt++; - } else { - // FP reg to FP reg - v |= ((imm16_cnt >> 1) & 7) << 10; - // clear mode/reg field - opcode &= ~0x3f; - imm16_cnt++; + fpuopsize = (v >> 10) & 7; + // generate source addressing mode + extra = generate_fpu_memory_read(opcode, pc + 2, dp, isconstant, eap, regused); + if (extra < 0) + return -2; + v |= ((imm16_cnt >> 2) & 7) << 7; + *fpuregused = (v >> 7) & 7; + *isconstant = 8 * 2; + } else if ((imm16_cnt & 3) == 1) { + // FPUOP FPx,FPx + v |= ((imm16_cnt >> 2) & 7) << 10; + v |= ((imm16_cnt >> 5) & 7) << 7; + if (opcode & 0x3f) { + // mode/reg field non-zero: we already processed same FPU instruction + return -2; + } if (opcodesize != 2) { // not X: skip return -2; } + *fpuregused = (v >> 10) & 7; + *isconstant = 8 * 8 * 2; + } else if ((imm16_cnt & 3) == 2) { + if (fpuopcode != 0) + return -2; + // FMOVE FPx,EA + v |= 0x2000 | 0x4000; + v |= opcodesize << 10; + int srcspec = (v >> 10) & 7; + v |= ((imm16_cnt >> 2) & 7) << 7; + *fpuregused = (v >> 7) & 7; + *isconstant = 8 * 2; + } else { + return -2; } - *isconstant = 16; } put_word_test(pc, v); pc += 2; + pc += extra; } else { if (opcodecnt == 1) { // STOP #xxxx: test all combinations @@ -2443,7 +2650,7 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str static int ea_exact_cnt; // generate exact EA (for bus error test) -static int create_ea_exact(uae_u16 *opcodep, uaecptr pc, int mode, int reg, struct instr *dp, int *isconstant, int srcdst, int fpuopcode, int opcodesize, uae_u32 *eap, int *regused) +static int create_ea_exact(uae_u16 *opcodep, uaecptr pc, int mode, int reg, struct instr *dp, int *isconstant, int srcdst, int fpuopcode, int opcodesize, uae_u32 *eap, int *regused, int *fpuregused) { uae_u32 target = target_ea[srcdst]; ea_exact_cnt++; @@ -2675,7 +2882,7 @@ static int create_ea_exact(uae_u16 *opcodep, uaecptr pc, int mode, int reg, stru return -2; } -static int create_ea(uae_u16 *opcodep, uaecptr pc, int mode, int reg, struct instr *dp, int *isconstant, int srcdst, int fpuopcode, int opcodesize, uae_u32 *ea, int *regused) +static int create_ea(uae_u16 *opcodep, uaecptr pc, int mode, int reg, struct instr *dp, int *isconstant, int srcdst, int fpuopcode, int opcodesize, uae_u32 *ea, int *regused, int *fpuregused) { int am = mode >= imm ? imm : mode; @@ -2683,12 +2890,39 @@ static int create_ea(uae_u16 *opcodep, uaecptr pc, int mode, int reg, struct ins return -1; if (target_ea[srcdst] == 0xffffffff) { - return create_ea_random(opcodep, pc, mode, reg, dp, isconstant, srcdst, fpuopcode, opcodesize, ea, regused); + return create_ea_random(opcodep, pc, mode, reg, dp, isconstant, srcdst, fpuopcode, opcodesize, ea, regused, fpuregused); } else { - return create_ea_exact(opcodep, pc, mode, reg, dp, isconstant, srcdst, fpuopcode, opcodesize, ea, regused); + return create_ea_exact(opcodep, pc, mode, reg, dp, isconstant, srcdst, fpuopcode, opcodesize, ea, regused, fpuregused); } } +// generate valid FPU memory access that returns valid FPU data. +static int generate_fpu_memory_read(uae_u16 opcode, uaecptr pc, struct instr *dp, int *isconstant, uae_u32 *eap, int *regused) +{ + int fpuopsize_t = fpuopsize; + int reg = opcode & 7; + int mode = (opcode >> 3) & 7; + if (mode == 7) { + mode = absw + reg; + reg = 0; + if (mode == imm && fpuopsize == 6) { + fpuopsize = 4; + } + } + uaecptr addr = 0xff0000ff; // FIXME: use separate flag + int o = create_ea_random(&opcode, pc, mode, reg, dp, isconstant, 0, -1, 8, &addr, regused, NULL); + fpuopsize = fpuopsize_t; + if (o < 0) + return o; + if (addr != 0xff0000ff) { + if (!check_valid_addr(addr, bytesizes[fpuopsize], 2)) + return -2; + putfpuimm(addr, fpuopsize, NULL); + *eap = addr; + } + return o; +} + static int imm_special; static int handle_specials_preea(uae_u16 opcode, uaecptr pc, struct instr *dp) @@ -3049,8 +3283,8 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp) uae_u16 opc = regs.ir; uae_u16 opw1 = (opcode_memory[2] << 8) | (opcode_memory[3] << 0); uae_u16 opw2 = (opcode_memory[4] << 8) | (opcode_memory[5] << 0); - if (opc == 0x199c - && opw1 == 0x2808 + if (opc == 0xf200 + && opw1 == 0x0019 //&& opw2 == 0x4afc ) printf(""); @@ -3073,6 +3307,7 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp) low_memory_accessed = 0; high_memory_accessed = 0; test_memory_accessed = 0; + test_memory_access_mask = 0; testing_active = 1; testing_active_opcode = opc; hardware_bus_error = 0; @@ -3118,6 +3353,7 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp) } regs.instruction_pc = regs.pc; + regs.fp_ea_set = false; uaecptr a7 = regs.regs[15]; int s = regs.s; @@ -3186,13 +3422,13 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp) } // STOP can only end with exception, fake prefetch here. if (dp->mnemo == i_STOP) { - regs.ir = get_word_test(regs.pc + 0); - regs.irc = get_word_test(regs.pc + 2); + regs.ir = get_iword_test(regs.pc + 0); + regs.irc = get_iword_test(regs.pc + 2); } } if (currprefs.cpu_model >= 68020) { - regs.ir = get_word_test(regs.pc + 0); - regs.irc = get_word_test(regs.pc + 2); + regs.ir = get_iword_test(regs.pc + 0); + regs.irc = get_iword_test(regs.pc + 2); } opc = regs.ir; continue; @@ -3209,8 +3445,8 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp) regs.ird = opc; if (currprefs.cpu_model >= 68020) { - regs.ir = get_word_test(regs.pc + 0); - regs.irc = get_word_test(regs.pc + 2); + regs.ir = get_iword_test(regs.pc + 0); + regs.irc = get_iword_test(regs.pc + 2); } opc = regs.ir; } @@ -3354,18 +3590,23 @@ static uae_u8 *save_exception(uae_u8 *p, struct instr *dp) case 0: break; case 2: - // instruction address + // instruction address or effective address p = store_rel(p, 0, opcode_memory_start, gl(sf + 8), 1); + if (test_exception == 11 || test_exception == 55) { // FPU unimplemented? + *p++ = regs.fp_ea_set ? 0x01 : 0x00; + } break; case 3: // effective address p = store_rel(p, 0, opcode_memory_start, gl(sf + 8), 1); + *p++ = regs.fp_ea_set ? 0x01 : 0x00; break; case 4: // floating point unimplemented (68040/060) // fault/effective address p = store_rel(p, 0, opcode_memory_start, gl(sf + 8), 1); // FSLW or PC of faulted instruction p = store_rel(p, 0, opcode_memory_start, gl(sf + 12), 1); + *p++ = regs.fp_ea_set ? 0x01 : 0x00; break; case 8: // 68010 address/bus error // SSW @@ -3480,6 +3721,12 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi size = 1; else if (opcodesize == 6) size = 0; + if (opcodesize == -1) + opcodesize = 8; + } + + if (feature_instruction_size && !(feature_instruction_size & (1 << opcodesize))) { + return; } filecount = 0; @@ -3497,21 +3744,26 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi mn = lookup->mnemo; xorshiftstate = lookup - lookuptab; - const TCHAR *mns = lookup->name; + TCHAR mns[200]; + _tcscpy(mns, lookup->name); if (fpuopcode >= 0) { xorshiftstate = 128 + fpuopcode; - mns = fpuopcodes[fpuopcode]; + if (fpuopcodes[fpuopcode] == NULL) { + _stprintf(mns, _T("FPP%02X"), fpuopcode); + } else { + _tcscpy(mns, fpuopcodes[fpuopcode]); + } if (opcodesize == 7) { - mns = _T("FMOVECR"); + _tcscpy(mns, _T("FMOVECR")); xorshiftstate = 128 + 64; } else if (opcodesize == 8) { - mns = _T("FMOVEM"); + _tcscpy(mns, _T("FMOVEM")); xorshiftstate = 128 + 64 + 1; } } xorshiftstate += 256 * opcodesize; if (ovrfilename) { - mns = ovrfilename; + _tcscpy(mns, ovrfilename); for (int i = 0; i < _tcslen(ovrfilename); i++) { xorshiftstate <<= 1; xorshiftstate ^= ovrfilename[i]; @@ -3525,7 +3777,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi _tcscat(dir, _T(".")); _tcscat(dir, sizes[size]); } - } else { + } else if (fpuopcode != FPUOPP_ILLEGAL) { _tcscat(dir, _T(".")); _tcscat(dir, fpsizes[opcodesize < 7 ? opcodesize : 2]); } @@ -3535,6 +3787,9 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi opcodecnt = 0; for (int opcode = 0; opcode < 65536; opcode++) { struct instr *dp = table68k + opcode; + // if FPU mode: skip everything else than FPU instructions + if (currprefs.fpu_model && (opcode & 0xf000) != 0xf000) + continue; // match requested mnemonic if (dp->mnemo != lookup->mnemo) continue; @@ -3544,7 +3799,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi if (size == 3 && !dp->unsized) continue; // skip all unsupported instructions if not specifically testing i_ILLG - if (lookup->mnemo != i_ILLG) { + if (lookup->mnemo != i_ILLG && fpuopcode != FPUOPP_ILLEGAL) { if (dp->clev > cpu_lvl) continue; if (isunsupported(dp)) @@ -3600,28 +3855,23 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi target_ea_opcode_cnt = 0; generate_address_mode = 0; + fpustatus.floatx80_rounding_precision = 80; + fpustatus.float_rounding_mode = float_round_nearest_even; + // 1.0 - fpuregisters[0].high = 0x3fff; - fpuregisters[0].low = 0x8000000000000000; + fpuregisters[0] = int32_to_floatx80(1); // -1.0 - fpuregisters[1].high = 0xbfff; - fpuregisters[1].low = 0x8000000000000000; + fpuregisters[1] = int32_to_floatx80(-1); // 0.0 - fpuregisters[2].high = 0x0000; - fpuregisters[2].low = 0x0000000000000000; + fpuregisters[2] = int32_to_floatx80(0); // NaN - fpuregisters[3].high = 0x7fff; - fpuregisters[3].low = 0xffffffffffffffff; - // inf+ - fpuregisters[4].high = 0x7fff; - fpuregisters[4].low = 0x0000000000000000; - // inf- - fpuregisters[5].high = 0xffff; - fpuregisters[5].low = 0x0000000000000000; + fpuregisters[7] = floatx80_default_nan(NULL); - for (int i = 6; i < 8; i++) { - fpuregisters[i].high = rand16(); - fpuregisters[i].low = (((uae_u64)rand32()) << 32) | (rand32()); + for (int i = 3; i < 7; i++) { + uae_u32 v = rand32(); + if (v < 10 || v > -10) + continue; + fpuregisters[i] = int32_to_floatx80(v); } for (int i = 0; i < MAX_REGISTERS; i++) { @@ -3719,7 +3969,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi if (dp->mnemo != lookup->mnemo) continue; - if (lookup->mnemo != i_ILLG) { + if (lookup->mnemo != i_ILLG && fpuopcode != FPUOPP_ILLEGAL) { // match requested size if ((size >= 0 && size <= 2) && (size != dp->size || dp->unsized)) continue; @@ -3768,6 +4018,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi imm16_cnt = 0; imm32_cnt = 0; immabsl_cnt = 0; + immabsw_cnt = 0; imm_special = 0; target_ea[0] = target_ea_bak[0]; @@ -3781,9 +4032,13 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi int oob_retries = 10; // if instruction has immediate(s), repeat instruction test multiple times // each round generates new random immediate(s) - int constant_loops = 32; - if (dp->mnemo == i_ILLG) { - constant_loops = 1; + int constant_loops = 256; + if (dp->mnemo == i_ILLG || fpuopcode == FPUOPP_ILLEGAL) { + if (fpumode) { + constant_loops = 65536; + } else { + constant_loops = 1; + } } while (constant_loops-- > 0) { @@ -3807,6 +4062,8 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi int srcregused = -1; int dstregused = -1; + int srcfpuregused = -1; + int dstfpuregused = -1; out_of_test_space = 0; noaccesshistory = 0; @@ -3815,6 +4072,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi ahcnt_current = 0; ahcnt_written = 0; multi_mode = 0; + fpuopsize = -1; target_ea[0] = target_ea_bak[0]; target_ea[1] = target_ea_bak[1]; @@ -3830,7 +4088,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi regs.usp = regs.regs[15]; regs.isp = super_stack_memory - 0x80; - if (opc == 0x0e51) + if (opc == 0xf228) printf(""); if (subtest_count >= 700) printf(""); @@ -3860,7 +4118,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi goto nextopcode; } - if (dp->mnemo != i_ILLG) { + if (dp->mnemo != i_ILLG && fpuopcode != FPUOPP_ILLEGAL) { pc += handle_specials_preea(opc, pc, dp); @@ -3869,7 +4127,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi // create source addressing mode if (dp->suse) { - int o = create_ea(&opc, pc, dp->smode, dp->sreg, dp, &isconstant_src, 0, fpuopcode, opcodesize, &srcea, &srcregused); + int o = create_ea(&opc, pc, dp->smode, dp->sreg, dp, &isconstant_src, 0, fpuopcode, opcodesize, &srcea, &srcregused, &srcfpuregused); if (o < 0) { memcpy(opcode_memory, oldcodebytes, sizeof(oldcodebytes)); if (o == -1) @@ -3915,8 +4173,8 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi dp = table68k + opc; // create destination addressing mode - if (dp->duse) { - int o = create_ea(&opc, pc, dp->dmode, dp->dreg, dp, &isconstant_dst, 1, fpuopcode, opcodesize, &dstea, &dstregused); + if (dp->duse && fpuopsize < 0) { + int o = create_ea(&opc, pc, dp->dmode, dp->dreg, dp, &isconstant_dst, 1, fpuopcode, opcodesize, &dstea, &dstregused, &dstfpuregused); if (o < 0) { memcpy(opcode_memory, oldcodebytes, sizeof(oldcodebytes)); if (o == -1) @@ -3963,6 +4221,19 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi // misc pc += handle_specials_misc(opc, pc, dp, &isconstant_src); + if (fpumode) { + // append fnop so that we detect pending FPU exceptions immediately + put_long_test(pc, 0xf2800000); + pc += 4; + } + + } else { + + if (fpumode) { + put_word_test(pc, 65535 - constant_loops); + pc += 2; + } + } // if bus error stack checking and RTE: copy USP to ISP before RTE @@ -4004,17 +4275,19 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi uae_u32 instructionendpc = pc; - if (isconstant_src < 0 || isconstant_dst < 0) { - constant_loops++; - quick = 1; - } else { - // the smaller the immediate, the less test loops - if (constant_loops > isconstant_src && constant_loops > isconstant_dst) - constant_loops = isconstant_dst > isconstant_src ? isconstant_dst : isconstant_src; + if (fpuopcode != FPUOPP_ILLEGAL) { + if (isconstant_src < 0 || isconstant_dst < 0) { + constant_loops++; + quick = 1; + } else { + // the smaller the immediate, the less test loops + if (constant_loops > isconstant_src && constant_loops > isconstant_dst) + constant_loops = isconstant_dst > isconstant_src ? isconstant_dst : isconstant_src; - // don't do extra tests if no immediates - if (!isconstant_dst && !isconstant_src) - extra_loops = 0; + // don't do extra tests if no immediates + if (!isconstant_dst && !isconstant_src) + extra_loops = 0; + } } if (out_of_test_space) { @@ -4238,7 +4511,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi int maxflag = fpumode ? 256 : 32; // if cc-instruction: always do full test - if (feature_flag_mode == 1 && (dp->mnemo == i_ILLG || !dp->ccuse)) { + if (feature_flag_mode > 1 || (feature_flag_mode == 1 && (dp->mnemo == i_ILLG || fpuopcode == FPUOPP_ILLEGAL || (!dp->ccuse && !fpumode)))) { maxflag = fpumode ? 256 / 8 : 2; } @@ -4332,7 +4605,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } regs.fpiar = regs.pc; // condition codes - if (maxflag >= 32) { + if (maxflag > 32) { fpp_set_fpsr((ccr & 15) << 24); // precision and rounding fpp_set_fpcr((ccr >> 4) << 4); @@ -4388,6 +4661,18 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi // examine results + if (fpumode) { + // if FPU illegal test: skip unless PC equals start of instruction + if (fpuopcode == FPUOPP_ILLEGAL && (test_exception != 11 && test_exception != 4 && test_exception != 8)) { + skipped = 1; + } + } + + // exception check disabled + if (!exceptionenabletable[test_exception]) { + skipped = 1; + } + // if only testing read bus errors, skip tests that generated only writes and vice-versa // skip also all tests don't generate any bus errors if ((hardware_bus_error == 0 && safe_memory_mode) || @@ -4632,7 +4917,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } else { full_format_cnt++; data_saved = 1; - // if test used data register as a source: modify it + // if test used data or fpu register as a source or destination: modify it if (srcregused >= 0) { uae_u32 prev = cur_registers[srcregused]; if (regchange(srcregused, cur_registers)) { @@ -4645,6 +4930,16 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi dst = store_reg(dst, CT_DREG + dstregused, prev, cur_registers[dstregused], -1); } } + if (srcfpuregused >= 0) { + if (fpuregchange(srcfpuregused, cur_fpuregisters)) { + dst = store_fpureg(dst, CT_FPREG + srcfpuregused, cur_fpuregisters[srcfpuregused]); + } + } + if (dstfpuregused >= 0 && srcfpuregused != dstfpuregused) { + if (fpuregchange(dstfpuregused, cur_fpuregisters)) { + dst = store_fpureg(dst, CT_FPREG + dstfpuregused, cur_fpuregisters[dstfpuregused]); + } + } } if (verbose) { wprintf(_T(" OK=%d OB=%d S=%d/%d T=%d STP=%d"), ok, exception_array[0], prev_s_cnt, s_cnt, t_cnt, cnt_stopped); @@ -4693,6 +4988,9 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } } nextopcode:; + if (fpuopcode == FPUOPP_ILLEGAL) { + break; + } } if (data_saved) { @@ -4703,7 +5001,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi if (opcodecnt == 1 && target_address == 0xffffffff && target_opcode_address == 0xffffffff && target_usp_address == 0xffffffff && subtest_count >= feature_test_rounds_opcode) break; - if (lookup->mnemo == i_ILLG) + if (lookup->mnemo == i_ILLG || fpuopcode == FPUOPP_ILLEGAL) break; bool nextround = false; @@ -4770,11 +5068,8 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi if (fpumode) { for (int i = 0; i < 8; i++) { - cur_fpuregisters[i].high = rand16(); - cur_fpuregisters[i].low = (((uae_u64)rand32()) << 32) | (rand32()); - if (rand16() & 1) { - cur_fpuregisters[i].low |= 0x8000000000000000; - } + uae_u32 v = rand32(); + cur_fpuregisters[i] = int32_to_floatx80(v); } } } @@ -4799,30 +5094,27 @@ static void test_mnemo_text(const TCHAR *path, const TCHAR *mode) _tcscpy(modetxt, mode); my_trim(modetxt); TCHAR *s = _tcschr(modetxt, '.'); - if (s || feature_instruction_size != NULL) { + if (s || feature_instruction_size) { TCHAR c = 0; if (s) { *s = 0; c = _totlower(s[1]); } - if (!c && feature_instruction_size) { - c = feature_instruction_size[0]; - } - if (c == 'b' || c == 'B') + if (c == 'B') sizes = 6; - if (c == 'w' || c == 'W') + if (c == 'W') sizes = 4; - if (c == 'l' || c == 'L') + if (c == 'L') sizes = 0; - if (c == 'u' || c == 'U') + if (c == 'U') sizes = 8; - if (c == 's' || c == 'S') + if (c == 'S') sizes = 1; - if (c == 'x' || c == 'X') + if (c == 'X') sizes = 2; - if (c == 'p' || c == 'P') + if (c == 'P') sizes = 3; - if (c == 'd' || c == 'D') + if (c == 'D') sizes = 5; } @@ -4884,9 +5176,18 @@ static void test_mnemo_text(const TCHAR *path, const TCHAR *mode) mnemo = i_FPP; sizes = 8; fpuopcode = 0; + } else if (!_tcsicmp(modetxt, _T("fillegal"))) { + mnemo = i_FPP; + fpuopcode = FPUOPP_ILLEGAL; } else { - for (int i = 0; i < 64; i++) { - if (fpuopcodes[i] && !_tcsicmp(modetxt, fpuopcodes[i])) { + for (int i = 0; i < 128; i++) { + TCHAR name[100]; + if (fpuopcodes[i]) { + _tcscpy(name, fpuopcodes[i]); + } else { + _stprintf(name, _T("FPP%02X"), i); + } + if (!_tcsicmp(modetxt, name)) { mnemo = i_FPP; fpuopcode = i; break; @@ -4905,6 +5206,8 @@ static void test_mnemo_text(const TCHAR *path, const TCHAR *mode) if (fpuopcode >= 0) { for (int i = 0; i < 7; i++) { test_mnemo(path, lookuptab[mnemo].name, ovrname, i, fpuopcode); + if (fpuopcode == FPUOPP_ILLEGAL) + break; } } else { if (lookuptab[mnemo].mnemo == i_ILLG) { @@ -4918,6 +5221,10 @@ static void test_mnemo_text(const TCHAR *path, const TCHAR *mode) } } else { test_mnemo(path, lookuptab[mnemo].name, ovrname, sizes, fpuopcode); + if (fpuopcode > 0 && sizes == 3) { + // Dynamic k-Factor packed (0 = FMOVE = FMOVECR) + test_mnemo(path, lookuptab[mnemo].name, ovrname, 7, fpuopcode); + } } } @@ -4975,11 +5282,13 @@ static bool ini_getvalx(struct ini_data *ini, const TCHAR *sections, const TCHAR } static bool ini_getstringx(struct ini_data *ini, const TCHAR *sections, const TCHAR *key, TCHAR **out) { + struct ini_context ictx; + ini_initcontext(ini, &ictx); bool ret = false; *out = NULL; while (*sections) { TCHAR *tout = NULL; - if (ini_getstring(ini, sections, key, &tout)) { + if (ini_getstring_multi(ini, sections, key, &tout, &ictx)) { if (!_tcsicmp(tout, _T("*"))) { xfree(tout); if (!ini_getstring(ini, INISECTION, key, &tout)) { @@ -4991,6 +5300,17 @@ static bool ini_getstringx(struct ini_data *ini, const TCHAR *sections, const TC free(*out); } *out = tout; + TCHAR *tout2 = NULL; + ini_setnextasstart(ini, &ictx); + while (ini_getstring_multi(ini, sections, key, &tout2, &ictx)) { + TCHAR *out2 = xcalloc(TCHAR, _tcslen(*out) + _tcslen(tout2) + 1 + 1); + _tcscpy(out2, *out); + _tcscat(out2, _T(",")); + _tcscat(out2, tout2); + xfree(*out); + *out = out2; + ini_setnextasstart(ini, &ictx); + } } sections += _tcslen(sections) + 1; } @@ -5025,6 +5345,8 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna wprintf(_T("Generating test '%s'\n"), testname); + memset(exceptionenabletable, 1, sizeof(exceptionenabletable)); + v = 0; ini_getvalx(ini, sections, _T("enabled"), &v); if (!v) { @@ -5105,13 +5427,25 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna currprefs.fpu_model = 0; currprefs.fpu_mode = 1; ini_getvalx(ini, sections, _T("fpu"), &currprefs.fpu_model); - if (currprefs.fpu_model && currprefs.cpu_model < 68020) { - wprintf(_T("FPU requires 68020+ CPU.\n")); - return 0; - } - if (currprefs.fpu_model != 0 && currprefs.fpu_model != 68881 && currprefs.fpu_model != 68882 && currprefs.fpu_model != 68040 && currprefs.fpu_model != 68060) { - wprintf(_T("Unsupported FPU model.\n")); - return 0; + if (currprefs.fpu_model) { + if (currprefs.fpu_model < 0) { + currprefs.fpu_model = currprefs.cpu_model; + if (currprefs.fpu_model == 68020 || currprefs.fpu_model == 68030) { + currprefs.fpu_model == 68882; + } + } else if (currprefs.cpu_model >= 68040) { + currprefs.fpu_model = currprefs.cpu_model; + } else if (currprefs.cpu_model >= 68020 && currprefs.cpu_model <= 68030 && currprefs.fpu_model < 68881) { + currprefs.fpu_model = 68882; + } + if (currprefs.fpu_model && currprefs.cpu_model < 68020) { + wprintf(_T("FPU requires 68020+ CPU.\n")); + return 0; + } + if (currprefs.fpu_model != 68881 && currprefs.fpu_model != 68882 && currprefs.fpu_model != 68040 && currprefs.fpu_model != 68060) { + wprintf(_T("Unsupported FPU model.\n")); + return 0; + } } verbose = 1; @@ -5153,6 +5487,33 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna } + if (ini_getstringx(ini, sections, _T("exceptions"), &vs)) { + bool first = true; + TCHAR *p = vs; + while (p && *p) { + TCHAR *pp = _tcschr(p, ','); + if (pp) { + *pp++ = 0; + } + int exc = _tstol(p); + bool neg = exc < 0; + if (exc < 0) { + exc = -exc; + } + if (exc <= 2 || exc >= 256) { + wprintf(_T("Invalid exception number %d.\n"), exc); + return 0; + } + if (first) { + memset(exceptionenabletable, neg ? 1 : 0, sizeof(exceptionenabletable)); + first = false; + } + exceptionenabletable[exc] = neg ? 0 : 1; + p = pp; + } + xfree(vs); + } + for (int i = 0; i < MAX_TARGET_EA; i++) { feature_target_ea[i][0] = 0xffffffff; feature_target_ea[i][1] = 0xffffffff; @@ -5308,10 +5669,33 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna feature_test_rounds_opcode = 0; ini_getvalx(ini, sections, _T("min_opcode_test_rounds"), &feature_test_rounds_opcode); - feature_instruction_size = NULL; - ini_getstringx(ini, sections, _T("feature_instruction_size"), &feature_instruction_size); + ini_getstringx(ini, sections, _T("feature_instruction_size"), &feature_instruction_size_text); + for (int i = 0; i < _tcslen(feature_instruction_size_text); i++) { + TCHAR c = _totupper(feature_instruction_size_text[i]); + int sizes = -1; + if (c == 'B') + sizes = 6; + else if (c == 'W') + sizes = 4; + else if (c == 'L') + sizes = 0; + else if (c == 'U') + sizes = 8; + else if (c == 'S') + sizes = 1; + else if (c == 'X') + sizes = 2; + else if (c == 'P') + sizes = 3; + else if (c == 'D') + sizes = 5; + if (sizes >= 0) { + feature_instruction_size |= 1 << sizes; + } + } + xfree(feature_instruction_size_text); - ini_getvalx(ini, sections, _T("feature_instruction_size"), &feature_test_rounds); + ini_getvalx(ini, sections, _T("test_rounds"), &feature_test_rounds); v = 0; ini_getvalx(ini, sections, _T("test_memory_start"), &v); @@ -5375,6 +5759,11 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna if (ini_getvalx(ini, sections, _T("opcode_memory_start"), &v)) { opcode_memory_start = v; opcode_memory = test_memory + (opcode_memory_start - test_memory_start); + if (opcode_memory_start < test_memory_start || opcode_memory_start + OPCODE_AREA >= test_memory_end) { + wprintf(_T("Opcode memory out of bounds, using default location.\n")); + opcode_memory = test_memory + test_memory_size / 2; + opcode_memory_start = test_memory_start + test_memory_size / 2; + } } else { opcode_memory = test_memory + test_memory_size / 2; opcode_memory_start = test_memory_start + test_memory_size / 2; @@ -5630,11 +6019,21 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna if (verbose == 1) verbose = 0; test_mnemo_text(path, _T("FMOVECR")); - const TCHAR *prev = _T(""); - for (int j = 0; j < 64; j++) { - if (fpuopcodes[j] && _tcscmp(prev, fpuopcodes[j])) { - test_mnemo_text(path, fpuopcodes[j]); - prev = fpuopcodes[j]; + TCHAR prev[100]; + prev[0] = 0; + TCHAR namebuf[100]; + for (int j = 0; j < 128; j++) { + const TCHAR *name = fpuopcodes[j]; + if (name == NULL) { + // test also one unsupported opcode + if (j == 0x3f) { + _stprintf(namebuf, _T("FPP%02X"), j); + name = namebuf; + } + } + if (name && _tcscmp(prev, name)) { + test_mnemo_text(path, name); + _tcscpy(prev, name); } } for (int j = 1; lookuptab[j].name; j++) { @@ -5691,7 +6090,7 @@ int __cdecl main(int argc, char *argv[]) int cpuidx = cputoindex(cpu); if (cpuidx < 0) { - wprintf(_T("Unsupport CPU model\n")); + wprintf(_T("Unsupported CPU model\n")); return 0; } maincpu[cpuidx] = 1; diff --git a/cputest/asm.S b/cputest/asm.S index 08ce21be..a2b8775c 100644 --- a/cputest/asm.S +++ b/cputest/asm.S @@ -40,7 +40,8 @@ S_FPU = S_EXCFRAME+4 S_FPIAR = S_FPU+8*12 S_FPCR = S_FPIAR+4 S_FPSR = S_FPCR+4 -S_TRACECNT = S_FPSR+4 +S_FSAVE = S_FPSR+4 +S_TRACECNT = S_FSAVE+216 S_TRACESTACK = S_TRACECNT+4 S_CYCLES = S_TRACESTACK+12 S_CYCLES2 = S_CYCLES+4 @@ -59,6 +60,10 @@ _setcpu: move.l 4(sp),d1 | cpu_lvl move.l 8(sp),a1 | new move.l 12(sp),a0 | store + cmp.w #5,d1 + bcs.s .scend1d + bsr.w enable060fpu +.scend1d: cmp.w #1,d1 bcs.s .scend1 move.l a0,d0 @@ -398,6 +403,22 @@ _exceptiontable010: bsr.s exception010 | 45 bsr.s exception010 | 46 bsr.s exception010 | 47 + bsr.s exception010 | 48 + bsr.s exception010 | 49 + bsr.s exception010 | 50 + bsr.s exception010 | 51 + bsr.s exception010 | 52 + bsr.s exception010 | 53 + bsr.s exception010 | 54 + bsr.s exception010 | 55 + bsr.s exception010 | 56 + bsr.s exception010 | 57 + bsr.s exception010 | 58 + bsr.s exception010 | 59 + bsr.s exception010 | 60 + bsr.s exception010 | 61 + bsr.s exception010 | 62 + bsr.s exception010 | 63 nop exception010: move.w sr,-(sp) @@ -485,6 +506,22 @@ _exceptiontable020: bsr.s exception020 | 45 bsr.s exception020 | 46 bsr.s exception020 | 47 + bsr.s exception020 | 48 + bsr.s exception020 | 49 + bsr.s exception020 | 50 + bsr.s exception020 | 51 + bsr.s exception020 | 52 + bsr.s exception020 | 53 + bsr.s exception020 | 54 + bsr.s exception020 | 55 + bsr.s exception020 | 56 + bsr.s exception020 | 57 + bsr.s exception020 | 58 + bsr.s exception020 | 59 + bsr.s exception020 | 60 + bsr.s exception020 | 61 + bsr.s exception020 | 62 + bsr.s exception020 | 63 nop exception020: move.w sr,-(sp) @@ -530,8 +567,8 @@ exception_trace010t2: bra exception_trace010 _exceptiontablefpu: - bsr.s exceptionfpu | 2 - bsr.s exceptionfpu | 3 + bsr.s exceptionfpu | 2 + bsr.s exceptionfpu | 3 bsr.s exceptionfpu | 4 bsr.s exceptionfpu | 5 bsr.s exceptionfpu | 6 @@ -576,9 +613,26 @@ _exceptiontablefpu: bsr.s exceptionfpu | 45 bsr.s exceptionfpu | 46 bsr.s exceptionfpu | 47 + bsr.s exceptionfpu | 48 + bsr.s exceptionfpu | 49 + bsr.s exceptionfpu | 50 + bsr.s exceptionfpu | 51 + bsr.s exceptionfpu | 52 + bsr.s exceptionfpu | 53 + bsr.s exceptionfpu | 54 + bsr.s exceptionfpu | 55 + bsr.s exceptionfpu | 56 + bsr.s exceptionfpu | 57 + bsr.s exceptionfpu | 58 + bsr.s exceptionfpu | 59 + bsr.s exceptionfpu | 60 + bsr.s exceptionfpu | 61 + bsr.s exceptionfpu | 62 + bsr.s exceptionfpu | 63 nop exceptionfpu: move.w sr,-(sp) +exceptionfpucontinue: move.w #0,ACTIVITYREG move.l a0,-(sp) move.l datapointer(pc),a0 @@ -587,7 +641,7 @@ exceptionfpu: move.w (sp)+,S_EXPSR+2(a0) move.l (sp)+,d0 - lea _exceptiontable020(pc),a1 + lea _exceptiontablefpu(pc),a1 sub.l a1,d0 lsr.w #1,d0 addq.w #1,d0 @@ -608,11 +662,15 @@ _msp_address4: move.l USP,a1 move.l a1,S_AREG+7*4(a0) + fsave S_FSAVE(a0) fmovem.x fp0-fp7,S_FPU(a0) lea S_FPIAR(a0),a1 fmove.l fpiar,(a1)+ fmove.l fpcr,(a1)+ fmove.l fpsr,(a1)+ + + lea nullframe(pc),a0 + frestore (a0) move.w #0x222,ACTIVITYREG move.l superstack(pc),a0 @@ -636,3 +694,7 @@ cycles: dc.l 0,0 dummy: dc.l 0 +temp: + dc.l 0 +nullframe: + dc.l 0,0,0 diff --git a/cputest/asm060.S b/cputest/asm060.S new file mode 100644 index 00000000..a06aabcf --- /dev/null +++ b/cputest/asm060.S @@ -0,0 +1,13 @@ + + .text + + .globl enable060fpu + + .arch 68060 + +enable060fpu: + | enable 68060 FPU + movec pcr,d0 + bclr #1,d0 + movec d0,pcr + rts diff --git a/cputest/cputestgen.ini b/cputest/cputestgen.ini index 485a9666..bc80d780 100644 --- a/cputest/cputestgen.ini +++ b/cputest/cputestgen.ini @@ -1,7 +1,6 @@ [cputest] ; CPU model (68000, 68020, 68030, 68040 or 68060). -; Always select 68020 when testing FPU instructions, even if test hardware CPU is 68040 or 68060. cpu=68000 ; CPU address space. @@ -10,7 +9,8 @@ cpu=68000 cpu_address_space=68030 ; FPU model (empty string or 0, 68881, 68882, 68040, 68060) -; Enable only when testing FPU. Enabled FPU mode will slow down native test execution even when not testing FPU instructions. +; Enable only when testing FPU. Only FPU instruction tests are allowed if FPU is enabled. +; if CPU is 68040/060 and FPU is 68881/68882, FPU type will be automatically corrected. fpu= ; Write generated instructions to standard output. Always disabled in "all" mode. @@ -107,10 +107,16 @@ feature_usp=0 ; skips all tests that didn't generate address error feature_exception_vectors= +; global exception disable/enable +; - = disable all except listed. = enable only listed +; default: all enabled +exceptions= + ; CCR/FPU status flags mode ; 0 = all combinations (32 CCR loops, 256 FPU loops) ; 1 = all zeros and all ones only (2 CCR loops, 32 FPU loops) ; Xcc type instruction (Bcc, DBcc etc) always forces all combinations mode +; 2 = always all zeros and all ones only feature_flags_mode=1 ; SR min interrupt mask @@ -159,6 +165,7 @@ feature_addressing_modes_dst= ; Limit test instruction size ; B = byte, W = word, L = long, empty = no size limit +; FPU only: S = single, D = double, X = extended, P = packed feature_instruction_size= ; mnemonics separated by comma or all/fall. @@ -361,3 +368,41 @@ cpu=68020-68060 mode=nop,ext,swap feature_interrupts=1 feature_exception_vectors=0x000123 + +; *********** +; FPU presets +; *********** + +; basic test +; no arithmetic exceptions, F-line, unsupported instructions or datatypes, denormals or unnormals. +[test=BasicFPU] +enabled=1 +verbose=1 +cpu=68020-68060 +fpu=68882 +feature_flags_mode=2 +exceptions=-48,-49,-50,-51,-52,-53,-54,-11 +mode=fneg.b +mode=fbcc,ftrapcc,fscc,fdbcc +mode=fmove,fsmove,fdmove,fint,fintrz,fneg,fsneg,fdneg,fabs,fsabs,fdabs,fdiv,fsdiv,fddiv,fadd,fsadd,fdadd,fmul,fsmul,fdmul,fsgldiv,fsglmul,fsub,fssub,fdsub,fcmp,ftst + +; packed datatype +; no exceptions +[test=PackedFPU] +enabled=0 +cpu=68020-68060 +fpu=68882 +exceptions=-48,-49,-50,-51,-52,-53,-54 +feature_flags_mode=2 +feature_instruction_size=P +mode=fall + +; FPU illegal or unimplemented instructions +[test=IllgFPU] +enabled=0 +verbose=1 +cpu=68020-68060 +fpu=68882 +exceptions=11,55,60,61 +feature_flags_mode=2 +mode=fillegal diff --git a/cputest/main.c b/cputest/main.c index 269666b3..34308bce 100644 --- a/cputest/main.c +++ b/cputest/main.c @@ -49,12 +49,15 @@ struct registers uae_u32 excframe; struct fpureg fpuregs[8]; uae_u32 fpiar, fpcr, fpsr; + uae_u32 fsave[216/4]; uae_u32 tracecnt; uae_u16 tracedata[6]; uae_u32 cycles, cycles2, cyclest; + uae_u32 srcaddr, dstaddr, branchtarget; uae_u8 branchtarget_mode; uae_u32 endpc; + uae_u16 fpeaset; }; static struct registers test_regs; @@ -420,7 +423,7 @@ static void start_test(void) exceptiontableinuse = (uae_u32)&exceptiontable000; } else { oldvbr = setvbr((uae_u32)vbr); - for (int i = 2; i < 48; i++) { + for (int i = 2; i < 64; i++) { if (fpu_model) { vbr[i] = (uae_u32)(((uae_u32)&exceptiontablefpu) + (i - 2) * 2); exceptiontableinuse = (uae_u32)&exceptiontablefpu; @@ -1358,7 +1361,7 @@ static void out_regs(struct registers *r, int before) return; for (int i = 0; i < 8; i++) { - if ((i % 2) == 0) { + if (i > 0 && (i % 2) == 0) { strcat(outbp, "\n"); } else if ((i % 4) != 0) { @@ -1376,9 +1379,9 @@ static void out_regs(struct registers *r, int before) outbp += strlen(outbp); } sprintf(outbp, "\nFPSR:%c%08x FPCR:%c%08x FPIAR:%c%08x\n", - test_fpsr != test_regs.fpsr ? '*' : ' ', before ? test_fpsr : r->fpsr, - test_fpcr != test_regs.fpcr ? '*' : ' ', before ? test_fpcr : r->fpcr, - regs.fpiar != test_regs.fpiar ? '*' : ' ', r->fpiar); + test_fpsr != last_registers.fpsr ? '*' : ' ', before ? test_fpsr : test_regs.fpsr, + test_fpcr != last_registers.fpcr ? '*' : ' ', before ? test_fpcr : test_regs.fpcr, + regs.fpiar != last_registers.fpiar ? '*' : ' ', r->fpiar); outbp += strlen(outbp); @@ -1586,12 +1589,26 @@ static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, short excnu p = restore_rel_ordered(p, &v); pl(exc + 8, v); exclen = 12; + if (excnum == 11 || excnum == 55) { + regs->fpeaset = (*p++) & 1; + if (!regs->fpeaset) { + mask_exception = 1; + memset(masked_exception, 0xff, exclen); + memset(masked_exception + 8, 0, 4); + } + } break; case 3: v = opcode_memory_addr; p = restore_rel_ordered(p, &v); pl(exc + 8, v); exclen = 12; + regs->fpeaset = (*p++) & 1; + if (!regs->fpeaset) { + mask_exception = 1; + memset(masked_exception, 0xff, exclen); + memset(masked_exception + 8, 0, 4); + } break; case 4: v = opcode_memory_addr; @@ -1601,6 +1618,12 @@ static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, short excnu p = restore_rel_ordered(p, &v); pl(exc + 12, v); exclen = 16; + regs->fpeaset = (*p++) & 1; + if (!regs->fpeaset) { + mask_exception = 1; + memset(masked_exception, 0xff, exclen); + memset(masked_exception + 8, 0, 4); + } break; case 8: // 68010 bus/address error { @@ -1994,7 +2017,7 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr) } if (cpu_lvl > 0 && exc >= 2 && cpuexc010 != cpuexc) { if (dooutput) { - sprintf(outbp, "Exception: vector number does not match vector offset! (%d <> %d)\n", exc, cpuexc010); + sprintf(outbp, "Exception: vector number does not match vector offset! (%d <> %d) %d\n", exc, cpuexc010, cpuexc); experr = 1; outbp += strlen(outbp); errflag |= 1 << 16; @@ -2253,23 +2276,27 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr) errflag |= 1 << 2; } } - for (int i = 0; i < 8; i++) { - if (regs_fpuchanged[i]) { - if (dooutput) { - sprintf(outbp, "FP%d: modified %04x-%08x%08x -> %04x-%08x%08x but expected no modifications\n", i, - last_registers.fpuregs[i].exp, last_registers.fpuregs[i].m[0], last_registers.fpuregs[i].m[1], - test_regs.fpuregs[i].exp, test_regs.fpuregs[i].m[0], test_regs.fpuregs[i].m[1]); - outbp += strlen(outbp); + if (!skipregchange) { + for (int i = 0; i < 8; i++) { + if (regs_fpuchanged[i]) { + if (dooutput) { + sprintf(outbp, "FP%d: modified %04x-%08x%08x -> %04x-%08x%08x but expected no modifications\n", i, + last_registers.fpuregs[i].exp, last_registers.fpuregs[i].m[0], last_registers.fpuregs[i].m[1], + test_regs.fpuregs[i].exp, test_regs.fpuregs[i].m[0], test_regs.fpuregs[i].m[1]); + outbp += strlen(outbp); + } + errflag |= 1 << 1; } - errflag |= 1 << 1; } } - if (fpsr_changed) { - if (dooutput) { - sprintf(outbp, "FPSR: modified %08x -> %08x but expected no modifications\n", last_registers.fpsr, test_regs.fpsr); - outbp += strlen(outbp); + if (!ignore_sr) { + if (fpsr_changed) { + if (dooutput) { + sprintf(outbp, "FPSR: modified %08x -> %08x but expected no modifications\n", last_registers.fpsr, test_regs.fpsr); + outbp += strlen(outbp); + } + errflag |= 1 << 3; } - errflag |= 1 << 3; } if (fpcr_changed) { if (dooutput) { @@ -2309,15 +2336,11 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr) outbp = outbuffer; addinfo(); strcpy(outbp, outbuffer2); - if (!fpu_model) { - strcat(outbp, "Registers before:\n"); - outbp += strlen(outbp); - } + strcat(outbp, "Registers before:\n"); + outbp += strlen(outbp); out_regs(®s, 1); - if (!fpu_model) { - strcat(outbp, "Registers after:\n"); - outbp += strlen(outbp); - } + strcat(outbp, "Registers after:\n"); + outbp += strlen(outbp); out_regs(&test_regs, 0); if (exc > 1) { if (!experr) { @@ -2499,6 +2522,8 @@ static void process_test(uae_u8 *p) sr_mask |= 0x1000; // M int maxccr = *p++; + if (!maxccr) + maxccr = 256; for (int ccr = 0; ccr < maxccr; ccr++) { opcodeend = (opcodeend >> 16) | (opcodeend << 16); @@ -2528,6 +2553,7 @@ static void process_test(uae_u8 *p) regs.pc = startpc; regs.fpiar = startpc; regs.cyclest = 0xffffffff; + regs.fpeaset = 0; #ifdef M68K if (stackcopysize > 0) @@ -2544,11 +2570,11 @@ static void process_test(uae_u8 *p) test_regs.expsr = test_regs.sr | 0x2000; test_sr = test_regs.sr; if (fpumode) { - if (maxccr >= 32) { + if (maxccr > 32) { test_regs.fpsr = (ccr & 15) << 24; test_regs.fpcr = (ccr >> 4) << 4; } else { - test_regs.fpsr = (ccr ? 15 : 0) << 24; + test_regs.fpsr = ((ccr & 1) ? 15 : 0) << 24; test_regs.fpcr = (ccr >> 1) << 4; } test_fpsr = test_regs.fpsr; @@ -2626,6 +2652,7 @@ static void process_test(uae_u8 *p) } else { test_regs.sr = test_sr; + test_regs.fpsr = test_fpsr; ignore_errors = 1; ignore_sr = 1; @@ -2639,6 +2666,11 @@ static void process_test(uae_u8 *p) for (int i = 0; i < 16; i++) { test_regs.regs[i] = regs.regs[i]; } + if (fpu_model) { + for (int i = 0; i < 8; i++) { + test_regs.fpuregs[i] = regs.fpuregs[i]; + } + } } p = validate_test(p, ignore_errors, ignore_sr); diff --git a/cputest/makefile b/cputest/makefile index 67b586ad..db65f34a 100644 --- a/cputest/makefile +++ b/cputest/makefile @@ -8,7 +8,7 @@ AS=/opt/amiga/bin/m68k-amigaos-as CFLAGS = -mcrt=nix13 -O2 -m68000 -fomit-frame-pointer -msmall-code -msoft-float -DREVDATE=$(NOWDATE) -DREVTIME=$(NOWTIME) -DAMIGA -DM68K LINK_CFLAGS = -mcrt=nix13 -lm -s -OBJS = main.o asm040.o amiga.o \ +OBJS = main.o asm040.o asm060.o amiga.o \ decode_ea.o globals.o opcode_handler_cpu.o opcode_handler_fpu.o \ opcode_handler_mmu.o opcodes_cpu.o opcodes_fpu.o opcodes_mmu.o util.o \ inflate.o @@ -52,5 +52,8 @@ inflate.o: inflate.S asm040.o: asm040.S $(AS) -m68020 -o $@ asm040.S +asm060.o: asm060.S + $(AS) -m68020 -o $@ asm060.S + amiga.o: amiga.S asm.S $(AS) -m68020 -o $@ amiga.S diff --git a/cputest/makefile.st b/cputest/makefile.st index 377f220b..badf5ab8 100644 --- a/cputest/makefile.st +++ b/cputest/makefile.st @@ -8,7 +8,7 @@ AS=/opt/m68k-atari/bin/m68k-atari-mint-as CFLAGS = -O2 -m68000 -fomit-frame-pointer -msoft-float -DREVDATE=$(NOWDATE) -DREVTIME=$(NOWTIME) -DM68K -DWAITEXIT LINK_CFLAGS = -lm -s -OBJS = main.o asm040.o atari.o \ +OBJS = main.o asm040.o asm060.o atari.o \ decode_ea.o globals.o opcode_handler_cpu.o opcode_handler_fpu.o \ opcode_handler_mmu.o opcodes_cpu.o opcodes_fpu.o opcodes_mmu.o util.o \ inflate.o @@ -52,5 +52,8 @@ inflate.o: inflate.S asm040.o: asm040.S $(AS) -m68020 -o $@ asm040.S +asm060.o: asm060.S + $(AS) -m68020 -o $@ asm060.S + atari.o: atari.S asm.S $(AS) -m68020 -o $@ atari.S diff --git a/cputest/readme.txt b/cputest/readme.txt index d8c96d5b..18a4c394 100644 --- a/cputest/readme.txt +++ b/cputest/readme.txt @@ -67,6 +67,11 @@ Cycle counting requires 100% accurate timing also for following instructions: 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/68010 PAL Amiga with real Fast RAM. +FPU testing: (Work in progress) + +68040/060 FPU test hardware must not have any 68040/060 or MMU support libraries loaded. + + -- Not implemented or only partially implemented: @@ -126,6 +131,11 @@ If mismatch is detected, opcode word(s), instruction disassembly, registers befo Change log: +11.04.2020 + +- Working FPU support. Not all tests work correctly yet. +- Added FPU test presets. + 15.03.2020 - Test coverage improved: If test uses data or address register as a source or destination, register gets modified after each test. Each register has different modification logic. (Some simply toggle few bits, some shift data etc..). Previously registers were static during single test round and start of each new round randomized register contents. @@ -133,6 +143,12 @@ Change log: Only test generator was updated. Data structures or m68k tester has not been changed. +01.03.2020 + +- Added 68020+ test presets. +- CPU selection changed. CPU=680x0 line at the top of ini is now the main CPU selection field. Test is generated if CPU model matches preset's CPU and preset is active. This update allows use of same preset for multiple CPU models. +- cpu_address_space can be also used to select which CPU model is first 32-bit addressing capable model (normally 68020 or 68030). + 16.02.2020 - 68000 prefetch bus error BTST Dn,#x, NBCD.B and LSLW fix. All prefetch bus error tests verified. @@ -163,9 +179,3 @@ Only test generator was updated. Data structures or m68k tester has not been cha - 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. - -01.03.2020 - -- Added 68020+ test presets. -- CPU selection changed. CPU=680x0 line at the top of ini is now the main CPU selection field. Test is generated if CPU model matches preset's CPU and preset is active. This update allows use of same preset for multiple CPU models. -- cpu_address_space can be also used to select which CPU model is first 32-bit addressing capable model (normally 68020 or 68030). diff --git a/debugmem.cpp b/debugmem.cpp index c7fbbe07..87cec2af 100644 --- a/debugmem.cpp +++ b/debugmem.cpp @@ -23,6 +23,8 @@ #define ELFMODE_ROM 1 #define ELFMODE_DEBUGMEM 2 +#define ELF_ALIGN_MASK 7 + #define N_GSYM 0x20 #define N_FUN 0x24 #define N_STSYM 0x26 @@ -2421,12 +2423,13 @@ static void swap_rel(struct rel *d, struct rel *s) static int loadelf(uae_u8 *file, int filelen, uae_u8 **outp, int outsize, struct sheader *sh) { int size = sh->size; + int asize = (size + ELF_ALIGN_MASK) & ~ELF_ALIGN_MASK; uae_u8 *out = *outp; if (outsize >= 0) { if (!out) - out = xcalloc(uae_u8, outsize + size); + out = xcalloc(uae_u8, outsize + asize); else - out = xrealloc(uae_u8, out, outsize + size); + out = xrealloc(uae_u8, out, outsize + asize); } else { outsize = 0; } @@ -2562,6 +2565,7 @@ static uae_u8 *loadelffile(uae_u8 *file, int filelen, uae_u8 *dbgfile, int debug struct loadelfsection *lelfs = xcalloc(struct loadelfsection, shnum); outsize = 0; + int aoutsize = 0; for (int i = 0; i < shnum; i++) { struct sheader *shp = (struct sheader*)&shp_first[i]; struct sheader sh; @@ -2583,9 +2587,10 @@ static uae_u8 *loadelffile(uae_u8 *file, int filelen, uae_u8 *dbgfile, int debug } else { lelfs[i].offsets = outsize; if (relocate) - lelfs[i].bases = outsize; + lelfs[i].bases = aoutsize; } outsize += sh.size; + aoutsize += (sh.size + ELF_ALIGN_MASK) & ~ELF_ALIGN_MASK; } } else if (sh.type == SHT_NOBITS) { if (sh.size) { @@ -2613,7 +2618,7 @@ static uae_u8 *loadelffile(uae_u8 *file, int filelen, uae_u8 *dbgfile, int debug } if (mode == ELFMODE_ROM) { - relocate_base = getrombase(outsize); + relocate_base = getrombase(aoutsize); if (!relocate_base) goto end; for (int i = 0; i < shnum; i++) { @@ -2696,6 +2701,7 @@ static uae_u8 *loadelffile(uae_u8 *file, int filelen, uae_u8 *dbgfile, int debug loadelf(file, filelen, &outp, -1, &sh); } else { int newoutsize = loadelf(file, filelen, &outp, outsize, &sh); + newoutsize = (newoutsize + ELF_ALIGN_MASK) & ~ELF_ALIGN_MASK; outptr = outp + outsize; outsize = newoutsize; *outsizep = outsize; diff --git a/include/newcpu.h b/include/newcpu.h index 8781966d..f4a186e7 100644 --- a/include/newcpu.h +++ b/include/newcpu.h @@ -212,6 +212,7 @@ struct regstruct uae_u32 fpu_exp_state; uae_u16 fp_opword; uaecptr fp_ea; + bool fp_ea_set; uae_u32 fp_exp_pend, fp_unimp_pend; bool fpu_exp_pre; bool fp_unimp_ins; -- 2.47.3